3
* $Id: irc.c,v 1.156 2005/04/21 06:58:50 nohar Exp $
5
* This file is part of the bip project
6
* Copyright (C) 2004 2005 Arnaud Cornet and Loïc Gomez
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
12
* See the file "COPYING" for the exact licensing terms.
23
#include "connection.h"
27
#define S_CONN_DELAY (10)
32
static int irc_join(struct link_server *server, struct line *line);
33
static int irc_part(struct link_server *server, struct line *line);
34
static int irc_mode(struct link_server *server, struct line *line);
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);
53
#define OIDENTD_FILENAME ".oidentd.conf"
54
void oidentd_dump(bip_t *bip);
57
void irc_client_free(struct link_client *cli);
58
extern int conf_log_sync_interval;
60
void write_user_list(connection_t *c, char *dest);
62
static void irc_copy_cli(struct link_client *src, struct link_client *dest,
64
static void irc_cli_make_join(struct link_client *ic);
65
static void server_setup_reconnect_timer(struct link *link);
66
int irc_cli_bip(bip_t *bip, struct link_client *ic, struct line *line);
68
#define LAGOUT_TIME 480
69
#define LAGCHECK_TIME (90)
70
#define RECONN_TIMER (120)
71
#define RECONN_TIMER_MAX (600)
72
#define LOGGING_TIMEOUT (360)
73
#define CONN_INTERVAL 60
74
#define CONNECT_TIMEOUT 60
76
struct channel *channel_new(const char *name)
79
chan = bip_calloc(sizeof(struct channel), 1);
80
chan->name = bip_strdup(name);
81
hash_init(&chan->ovmasks, HASH_NOCASE);
85
char *nick_from_ircmask(const char *mask)
87
const char *nick = mask;
93
while (*nick && *nick != '!')
96
return bip_strdup(mask);
98
ret = bip_malloc(len + 1);
99
memcpy(ret, mask, len);
106
list_t *channel_name_list(struct channel *c)
111
char *str = bip_malloc(NAMESIZE + 1);
113
ret = list_new(NULL);
115
for (hash_it_init(&c->ovmasks, &hi); hash_it_key(&hi);
117
const char *nick = hash_it_key(&hi);
118
long int ovmask = (long int)hash_it_item(&hi);
120
assert(strlen(nick) + 2 < NAMESIZE);
122
if (len + strlen(nick) + 2 + (ovmask ? 1 : 0) >= NAMESIZE) {
123
list_add_last(ret, str);
124
str = bip_malloc(NAMESIZE + 1);
134
else if (ovmask & NICKHALFOP)
136
else if (ovmask & NICKVOICED)
142
assert(len < NAMESIZE);
144
list_add_last(ret, str);
148
char *link_name(struct link_any *l)
151
return LINK(l)->name ? LINK(l)->name : "(null)";
152
return "*connecting*";
155
static int irc_001(struct link_server *server, struct line *line)
159
if (LINK(server)->s_state == IRCS_WAS_CONNECTED)
160
LINK(server)->s_state = IRCS_RECONNECTING;
162
LINK(server)->s_state = IRCS_CONNECTING;
164
/* change nick on client */
166
for (i = 0; i < LINK(server)->l_clientc; i++) {
167
struct link_client *c = LINK(server)->l_clientv[i];
168
WRITE_LINE1(CONN(c), LINK(server)->cli_nick, "NICK",
174
void irc_start_lagtest(struct link_server *l)
176
l->laginit_ts = time(NULL);
177
write_line_fast(CONN(l), "PING :" S_PING "\r\n");
181
* returns 0 if we ping timeout
183
void irc_compute_lag(struct link_server *is)
185
assert(is->laginit_ts != -1);
186
is->lag = time(NULL) - is->laginit_ts;
189
int irc_lags_out(struct link_server *is)
191
if (is->lag > LAGOUT_TIME) {
192
mylog(LOG_ERROR, "[%s] Lags out! closing", LINK(is)->name);
195
mylog(LOG_DEBUG, "[%s] lag : %d\n", LINK(is)->name, is->lag);
200
void irc_lag_init(struct link_server *is)
202
is->lagtest_timeout = LAGCHECK_TIME;
206
static void irc_server_join(struct link_server *s)
209
for (list_it_init(&LINK(s)->chan_infos_order, &it); list_it_item(&it);
211
struct chan_info *ci = list_it_item(&it);
213
WRITE_LINE1(CONN(s), NULL, "JOIN", ci->name);
215
WRITE_LINE2(CONN(s), NULL, "JOIN", ci->name, ci->key);
219
static void irc_server_connected(struct link_server *server)
223
LINK(server)->s_state = IRCS_CONNECTED;
224
LINK(server)->s_conn_attempt = 0;
226
mylog(LOG_INFO, "[%s] Connected for user %s",
227
LINK(server)->name, LINK(server)->user->name);
229
irc_server_join(server);
230
log_connected(LINK(server)->log);
232
if (LINK(server)->cli_nick) {
233
/* we change nick on client */
234
for (i = 0; i < LINK(server)->l_clientc; i++) {
235
struct link_client *ic = LINK(server)->l_clientv[i];
236
WRITE_LINE1(CONN(ic), LINK(server)->cli_nick, "NICK",
239
free(LINK(server)->cli_nick);
240
LINK(server)->cli_nick = NULL;
243
/* basic helper for nickserv and co */
244
list_iterator_t itocs;
245
for (list_it_init(&LINK(server)->on_connect_send, &itocs);
246
list_it_item(&itocs); list_it_next(&itocs)) {
247
ssize_t len = strlen(list_it_item(&itocs)) + 2;
248
char *str = bip_malloc(len + 1);
249
sprintf(str, "%s\r\n", (char *)list_it_item(&itocs));
250
write_line(CONN(server), str);
254
if (LINK(server)->l_clientc == 0) {
255
if (LINK(server)->away_nick)
256
WRITE_LINE1(CONN(server), NULL, "NICK",
257
LINK(server)->away_nick);
258
if (LINK(server)->no_client_away_msg)
259
WRITE_LINE1(CONN(server), NULL, "AWAY",
260
LINK(server)->no_client_away_msg);
265
* Given the way irc nets disrespect the rfc, we completely forget
266
* about this damn ircmask...
267
:irc.iiens.net 352 pwet * ~a je.suis.t1r.net irc.iiens.net pwet H :0 d
268
-> nohar!~nohar@haruka.t1r.net
270
static int irc_352(struct link_server *server, struct line *line)
273
if (!irc_line_includes(line, 6))
277
if (irc_line_elem_case_equals(line, 6, server->nick)) {
278
const char *nick = server->nick;
279
const char *iname = irc_line_elem(line, 3);
280
const char *ihost = irc_line_elem(line, 4);
281
char *ircmask = bip_malloc(strlen(nick) + strlen(iname) +
283
strcpy(ircmask, nick);
284
strcat(ircmask, "!");
285
strcat(ircmask, iname);
286
strcat(ircmask, "@");
287
strcat(ircmask, ihost);
289
free(server->ircmask);
290
server->ircmask = ircmask;
295
if (!origin_is_me(line, server)) {
296
struct channel *channel;
299
channel = hash_get(&server->channels, irc_line_elem(line, 2));
303
nick = hash_get(&channel->nicks, irc_line_elem(line, 6));
312
static int irc_315(struct link_server *server, struct line *l)
314
struct link *link = LINK(server);
315
if (link->who_client) {
316
if (link->who_client->who_count == 0) {
317
mylog(LOG_DEBUG, "Spurious irc_315");
320
link->who_client->whoc_tstamp = time(NULL);
321
if (link->who_client->who_count > 0) {
322
--link->who_client->who_count;
325
"Decrementing who count for %p: %d",
326
link->who_client, link->who_client->who_count);
329
l = NULL; /* keep gcc happy */
334
void rotate_who_client(struct link *link)
337
mylog(LOG_DEBUG, "rotate_who_client %p", link->who_client);
338
/* find a client with non-null who_count */
339
link->who_client = NULL;
340
for (i = 0; i < link->l_clientc; i++) {
341
struct link_client *ic = link->l_clientv[i];
342
if (!list_is_empty(&ic->who_queue)) {
344
while ((l = list_remove_first(&ic->who_queue))) {
345
write_line(CONN(link->l_server), l);
348
link->who_client = ic;
354
int irc_dispatch_server(bip_t *bip, struct link_server *server,
361
if (!irc_line_includes(line, 0))
364
if (irc_line_elem_equals(line, 0, "PING")) {
365
if (!irc_line_includes(line, 1))
367
struct line *resp = irc_line_new();
369
irc_line_append(resp, "PONG");
370
irc_line_append(resp, irc_line_elem(line, 1));
371
resp->colon = 1; /* it seems some ircds want it */
372
resps = irc_line_to_string(resp);
373
write_line_fast(CONN(server), resps);
377
} else if (irc_line_elem_equals(line, 0, "PONG")) {
378
/* not all server reply with PONG <servername> <our string>
379
* so we blindly assume the PONG is ours. */
380
if (irc_line_count(line) == 2 || irc_line_count(line) == 3) {
381
if (server->laginit_ts != -1) {
382
irc_compute_lag(server);
383
irc_lag_init(server);
387
} else if (irc_line_elem_equals(line, 0, "433")) {
388
if (LINK(server)->s_state != IRCS_CONNECTED) {
389
size_t nicklen = strlen(server->nick);
390
char *newnick = bip_malloc(nicklen + 2);
392
strcpy(newnick, server->nick);
393
if (strlen(server->nick) < 9) {
394
strcat(newnick, "`");
396
if (newnick[7] != '`') {
397
if (newnick[8] != '`') {
403
newnick[8] = rand() *
404
('z' - 'a') / RAND_MAX + 'a';
408
ls_set_nick(server, newnick);
410
WRITE_LINE1(CONN(server), NULL, "NICK", server->nick);
413
} else if (LINK(server)->s_state == IRCS_RECONNECTING) {
415
if (irc_line_elem_equals(line, 0, "376")) /* end of motd */
416
irc_server_connected(server);
417
else if (irc_line_elem_equals(line, 0, "422")) /* no motd */
418
irc_server_connected(server);
420
} else if (LINK(server)->s_state == IRCS_CONNECTING) {
422
if (LINK(server)->ignore_server_capab &&
423
irc_line_elem_equals(line, 0, "005")) {
425
for (i = 0; i < irc_line_count(line); i++)
426
if (irc_line_elem_equals(line, i, "CAPAB"))
427
irc_line_drop(line, i);
429
if (irc_line_elem_equals(line, 0, "NOTICE")) {
430
} else if (irc_line_elem_equals(line, 0, "376")) {
432
irc_server_connected(server);
433
list_add_last(&LINK(server)->init_strings,
435
} else if (irc_line_elem_equals(line, 0, "422")) { /* no motd */
436
irc_server_connected(server);
437
list_add_last(&LINK(server)->init_strings,
440
list_add_last(&LINK(server)->init_strings,
443
} else if (irc_line_elem_equals(line, 0, "001")) {
444
ret = irc_001(server, line);
445
if (LINK(server)->s_state == IRCS_CONNECTING) {
446
if (!list_is_empty(&LINK(server)->init_strings))
448
/* update the irc mask */
449
list_add_last(&LINK(server)->init_strings,
452
} else if (irc_line_elem_equals(line, 0, "JOIN")) {
453
ret = irc_join(server, line);
454
} else if (irc_line_elem_equals(line, 0, "332")) {
455
ret = irc_332(server, line);
456
} else if (irc_line_elem_equals(line, 0, "333")) {
457
ret = irc_333(server, line);
458
} else if (irc_line_elem_equals(line, 0, "352")) {
459
ret = irc_352(server, line);
460
} else if (irc_line_elem_equals(line, 0, "315")) {
461
ret = irc_315(server, line);
462
} else if (irc_line_elem_equals(line, 0, "353")) {
463
ret = irc_353(server, line);
464
} else if (irc_line_elem_equals(line, 0, "366")) {
465
ret = irc_366(server, line);
466
} else if (irc_line_elem_equals(line, 0, "367")) {
467
ret = irc_367(server, line);
468
} else if (irc_line_elem_equals(line, 0, "368")) {
469
ret = irc_368(server, line);
470
} else if (irc_line_elem_equals(line, 0, "PART")) {
471
ret = irc_part(server, line);
472
} else if (irc_line_elem_equals(line, 0, "MODE")) {
473
ret = irc_mode(server, line);
474
} else if (irc_line_elem_equals(line, 0, "TOPIC")) {
475
ret = irc_topic(server, line);
476
} else if (irc_line_elem_equals(line, 0, "KICK")) {
477
ret = irc_kick(server, line);
478
} else if (irc_line_elem_equals(line, 0, "PRIVMSG")) {
479
ret = irc_privmsg(server, line);
480
} else if (irc_line_elem_equals(line, 0, "NOTICE")) {
481
ret = irc_notice(server, line);
482
} else if (irc_line_elem_equals(line, 0, "QUIT")) {
483
ret = irc_quit(server, line);
484
} else if (irc_line_elem_equals(line, 0, "NICK")) {
485
ret = irc_nick(server, line);
488
if (ret == OK_COPY) {
490
for (i = 0; i < LINK(server)->l_clientc; i++) {
491
if (TYPE(LINK(server)->l_clientv[i]) ==
493
char *s = irc_line_to_string(line);
494
write_line(CONN(LINK(server)->l_clientv[i]), s);
499
if (ret == OK_COPY_WHO && LINK(server)->who_client) {
502
s = irc_line_to_string(line);
503
write_line(CONN(LINK(server)->who_client), s);
506
if (LINK(server)->who_client &&
507
LINK(server)->who_client->who_count == 0) {
508
mylog(LOG_DEBUG, "OK_COPY_WHO: who_count for %p is nul",
509
LINK(server)->who_client);
510
rotate_who_client(LINK(server));
515
/* send join and related stuff to client */
516
static void irc_send_join(struct link_client *ic, struct channel *chan)
521
user = LINK(ic)->user;
524
/* user ircmask here for rbot */
525
ircmask = bip_malloc(strlen(LINK(ic)->l_server->nick) +
526
strlen(BIP_FAKEMASK) + 1);
527
strcpy(ircmask, LINK(ic)->l_server->nick);
528
strcat(ircmask, BIP_FAKEMASK);
529
WRITE_LINE1(CONN(ic), ircmask, "JOIN", chan->name);
533
WRITE_LINE3(CONN(ic), P_SERV, "332", LINK(ic)->l_server->nick,
534
chan->name, chan->topic);
535
if (chan->creator && chan->create_ts)
536
WRITE_LINE4(CONN(ic), P_SERV, "333", LINK(ic)->l_server->nick,
537
chan->name, chan->creator, chan->create_ts);
539
list_t *name_list = channel_name_list(chan);
541
while ((s = list_remove_first(name_list))) {
543
tmptype[0] = chan->type;
545
WRITE_LINE4(CONN(ic), P_SERV, "353", LINK(ic)->l_server->nick,
546
tmptype, chan->name, s);
549
list_free(name_list);
551
WRITE_LINE3(CONN(ic), P_SERV, "366", LINK(ic)->l_server->nick,
552
chan->name, "End of /NAMES list.");
555
static void write_init_string(connection_t *c, struct line *line, char *nick)
559
l = irc_line_to_string_to(line, nick);
564
static void bind_to_link(struct link *l, struct link_client *ic)
566
int i = l->l_clientc;
570
l->l_clientv = bip_realloc(l->l_clientv, l->l_clientc *
571
sizeof(struct link_client *));
572
l->l_clientv[i] = ic;
575
void unbind_from_link(struct link_client *ic)
577
struct link *l = LINK(ic);
580
for (i = 0; i < l->l_clientc; i++)
581
if (l->l_clientv[i] == ic)
584
assert(i != l->l_clientc);
586
if (l->who_client == ic) {
587
mylog(LOG_DEBUG, "unbind_from_link: %p: %d", l->who_client,
589
l->who_client = NULL;
592
for (i = i + 1; i < l->l_clientc; i++)
593
l->l_clientv[i - 1] = l->l_clientv[i];
596
l->l_clientv = bip_realloc(l->l_clientv, l->l_clientc *
597
sizeof(struct link_client *));
598
if (l->l_clientc == 0) { /* bip_realloc was equiv to free() */
604
int irc_cli_bip(bip_t *bip, struct link_client *ic, struct line *line)
606
return adm_bip(bip, ic, line, 0);
611
static char *get_str_elem(char *str, int num)
618
while ((c = strchr(cur, PASS_SEP))) {
626
ret = bip_malloc(c - cur + 1);
627
strncpy(ret, cur, c - cur);
632
c = str + strlen(str);
635
ret = bip_malloc(c - cur + 1);
636
strncpy(ret, cur, c - cur);
643
static void irc_cli_make_join(struct link_client *ic)
645
if (LINK(ic)->l_server) {
646
/* join channels, step one, those in conf, in order */
648
for (list_it_init(&LINK(ic)->chan_infos_order, &li);
649
list_it_item(&li); list_it_next(&li)) {
650
struct chan_info *ci = (struct chan_info *)
652
struct channel *chan;
653
if ((chan = hash_get(&LINK(ic)->l_server->channels,
655
irc_send_join(ic, chan);
658
/* step two, those not in conf */
660
for (hash_it_init(&LINK(ic)->l_server->channels, &hi);
661
hash_it_item(&hi); hash_it_next(&hi)) {
662
struct channel *chan = (struct channel *)
664
if (!hash_get(&LINK(ic)->chan_infos, chan->name))
665
irc_send_join(ic, chan);
670
void irc_cli_backlog(struct link_client *ic, int hours)
674
user = LINK(ic)->user;
676
assert(LINK(ic)->l_server);
678
if (!user->backlog) {
679
mylog(LOG_DEBUG, "Backlog disabled for %s, not backlogging",
685
/* have some limit */
686
if (hours > 24 * 366)
694
backlogl = log_backlogs(LINK(ic)->log);
695
while ((bl = list_remove_first(backlogl))) {
696
bllines = backlog_lines(LINK(ic)->log, bl,
697
LINK(ic)->l_server->nick, hours);
699
if (!list_is_empty(bllines)) {
700
mylog(LOG_INFO, "[%s] backlogging: %s",
702
write_lines(CONN(ic), bllines);
711
static int irc_cli_startup(bip_t *bip, struct link_client *ic,
715
char *user, *pass, *connname;
718
assert(ic->init_pass);
720
user = get_str_elem(ic->init_pass, 0);
723
pass = get_str_elem(ic->init_pass, 1);
728
connname = get_str_elem(ic->init_pass, 2);
736
for (list_it_init(&bip->link_list, &it); list_it_item(&it);
738
struct link *l = list_it_item(&it);
739
if (strcmp(user, l->user->name) == 0 &&
740
strcmp(connname, l->name) == 0) {
741
if (chash_cmp(pass, l->user->password,
742
l->user->seed) == 0) {
750
mylog(LOG_ERROR, "[%s] Invalid credentials (user: %s)",
757
ic->init_pass = NULL;
758
init_nick = ic->init_nick;
759
ic->init_nick = NULL;
767
if (LINK(ic)->s_state != IRCS_CONNECTED) {
768
/* Check if we have an untrusted certificate from the server */
769
if (ssl_check_trust(ic)) {
770
TYPE(ic) = IRC_TYPE_TRUST_CLIENT;
778
if (LINK(ic)->s_state == IRCS_NONE) {
779
/* drop it if corresponding server hasn't connected at all. */
780
write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
781
":ERROR Proxy not yet connected, try again "
783
unbind_from_link(ic);
788
list_remove(&bip->connecting_client_list, ic);
789
TYPE(ic) = IRC_TYPE_CLIENT;
791
for (list_it_init(&LINK(ic)->init_strings, &it);
792
list_it_item(&it); list_it_next(&it))
793
write_init_string(CONN(ic), list_it_item(&it), init_nick);
795
/* we change nick on server */
796
if (LINK(ic)->l_server) {
797
struct link_server *server = LINK(ic)->l_server;
798
WRITE_LINE1(CONN(ic), init_nick, "NICK", server->nick);
800
if (!LINK(ic)->ignore_first_nick)
801
WRITE_LINE1(CONN(server), NULL, "NICK", init_nick);
802
else if (LINK(ic)->away_nick &&
803
strcmp(LINK(ic)->away_nick, server->nick) == 0)
804
WRITE_LINE1(CONN(server), NULL, "NICK",
805
LINK(server)->connect_nick);
807
/* change away status */
808
if (server && LINK(ic)->no_client_away_msg)
809
WRITE_LINE0(CONN(server), NULL, "AWAY");
812
if (!LINK(ic)->l_server) {
817
irc_cli_make_join(ic);
818
irc_cli_backlog(ic, 0);
820
log_client_connected(LINK(ic)->log);
826
static int irc_cli_nick(bip_t *bip, struct link_client *ic, struct line *line)
828
if (irc_line_count(line) != 2)
831
if ((ic->state & IRCC_READY) == IRCC_READY)
834
ic->state |= IRCC_NICK;
837
ic->init_nick = bip_strdup(irc_line_elem(line, 1));
839
if ((ic->state & IRCC_READY) == IRCC_READY)
840
return irc_cli_startup(bip, ic, line);
842
if ((ic->state & IRCC_PASS) != IRCC_PASS)
843
WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", ic->init_nick,
844
"You should type /QUOTE PASS your_username:"
845
"your_password:your_connection_name");
850
static int irc_cli_user(bip_t *bip, struct link_client *ic, struct line *line)
852
if (irc_line_count(line) != 5)
855
if ((ic->state & IRCC_READY) == IRCC_READY)
858
ic->state |= IRCC_USER;
859
if ((ic->state & IRCC_READY) == IRCC_READY)
860
return irc_cli_startup(bip, ic, line);
864
static int irc_cli_pass(bip_t *bip, struct link_client *ic, struct line *line)
866
if (irc_line_count(line) != 2)
869
if ((ic->state & IRCC_READY) == IRCC_READY)
872
ic->state |= IRCC_PASS;
875
ic->init_pass = bip_strdup(irc_line_elem(line, 1));
876
if ((ic->state & IRCC_READY) == IRCC_READY)
877
return irc_cli_startup(bip, ic, line);
881
static int irc_cli_quit(struct link_client *ic, struct line *line)
888
static int irc_cli_privmsg(bip_t *bip, struct link_client *ic,
891
if (!irc_line_includes(line, 2))
894
if (irc_line_elem_equals(line, 1, "-bip"))
895
return adm_bip(bip, ic, line, 1);
897
log_cli_privmsg(LINK(ic)->log, LINK(ic)->l_server->nick,
898
irc_line_elem(line, 1), irc_line_elem(line, 2));
900
if (LINK(ic)->user->blreset_on_talk) {
901
if (LINK(ic)->user->blreset_connection)
902
log_reset_all(LINK(ic)->log);
904
log_reset_store(LINK(ic)->log, irc_line_elem(line, 1));
909
static int irc_cli_notice(struct link_client *ic, struct line *line)
911
if (!irc_line_includes(line, 2))
913
log_cli_notice(LINK(ic)->log, LINK(ic)->l_server->nick,
914
irc_line_elem(line, 1), irc_line_elem(line, 2));
915
if (LINK(ic)->user->blreset_on_talk) {
916
if (LINK(ic)->user->blreset_connection)
917
log_reset_all(LINK(ic)->log);
919
log_reset_store(LINK(ic)->log, irc_line_elem(line, 1));
924
static int irc_cli_who(struct link_client *ic, struct line *line)
926
struct link *l = LINK(ic);
929
if (ic->who_count == 1)
930
ic->whoc_tstamp = time(NULL);
931
mylog(LOG_DEBUG, "cli_who: Incrementing who count for %p: %d",
934
if (l->who_client && l->who_client != ic) {
935
list_add_first(&ic->who_queue, irc_line_to_string(line));
945
static int irc_cli_mode(struct link_client *ic, struct line *line)
947
struct link *l = LINK(ic);
949
if (irc_line_count(line) != 3)
952
/* This is a wild guess and that sucks. */
953
if (!irc_line_elem_equals(line, 0, "MODE") ||
954
strchr(irc_line_elem(line, 2), 'b') == NULL)
958
if (ic->who_count == 1)
959
ic->whoc_tstamp = time(NULL);
960
mylog(LOG_DEBUG, "cli_mode: Incrementing who count for %p: %d",
961
l->who_client, ic->who_count);
963
if (l->who_client && l->who_client != ic) {
964
list_add_first(&ic->who_queue, irc_line_to_string(line));
975
static void irc_notify_disconnection(struct link_server *is)
978
LINK(is)->cli_nick = bip_strdup(is->nick);
980
for (i = 0; i < LINK(is)->l_clientc; i++) {
981
struct link_client *ic = LINK(is)->l_clientv[i];
983
for (hash_it_init(&is->channels, &hi); hash_it_item(&hi);
985
struct channel *c = (struct channel *)hash_it_item(&hi);
986
WRITE_LINE3(CONN(ic), P_IRCMASK, "KICK",
988
"Server disconnected, reconnecting");
990
bip_notify(ic, "Server disconnected, reconnecting");
994
void irc_add_channel_info(struct link_server *ircs, const char *chan,
997
struct chan_info *ci;
998
if (!ischannel(*chan))
1001
ci = hash_get(&LINK(ircs)->chan_infos, chan);
1003
struct chan_info *ci;
1004
ci = chan_info_new();
1005
ci->name = bip_strdup(chan);
1006
ci->key = key ? bip_strdup(key) : NULL;
1008
hash_insert(&LINK(ircs)->chan_infos, chan, ci);
1009
list_add_last(&LINK(ircs)->chan_infos_order, ci);
1015
ci->key = key ? bip_strdup(key) : NULL;
1019
static int irc_cli_join(struct link_client *irc, struct line *line)
1021
if (irc_line_count(line) != 2 && irc_line_count(line) != 3)
1022
return ERR_PROTOCOL;
1024
const char *s, *e, *ks, *ke = NULL;
1025
s = irc_line_elem(line, 1);
1026
if (irc_line_count(line) == 3)
1027
ks = irc_line_elem(line, 2);
1031
while ((e = strchr(s, ','))) {
1033
char *p = bip_malloc(len + 1);
1041
ke = strchr(ks, ',');
1043
ke = ks + strlen(ks);
1045
kp = bip_malloc(klen + 1);
1046
memcpy(kp, ks, klen);
1056
irc_add_channel_info(LINK(irc)->l_server, p, kp);
1066
irc_add_channel_info(LINK(irc)->l_server, s, ks);
1070
static int irc_cli_part(struct link_client *irc, struct line *line)
1072
struct chan_info *ci;
1075
if (irc_line_count(line) != 2 && irc_line_count(line) != 3)
1076
return ERR_PROTOCOL;
1078
cname = (char *)irc_line_elem(line, 1);
1080
if ((ci = hash_remove_if_exists(&LINK(irc)->chan_infos,
1082
list_remove(&LINK(irc)->chan_infos_order, ci);
1092
static int irc_dispatch_trust_client(struct link_client *ic, struct line *line)
1095
if (!irc_line_includes(line, 1))
1096
return ERR_PROTOCOL;
1098
if (strcasecmp(irc_line_elem(line, 0), "BIP") == 0 &&
1099
strcasecmp(irc_line_elem(line, 1), "TRUST") == 0)
1100
r = adm_trust(ic, line);
1106
static int irc_dispatch_client(bip_t *bip, struct link_client *ic,
1110
if (irc_line_count(line) == 0)
1111
return ERR_PROTOCOL;
1113
if (irc_line_elem_equals(line, 0, "PING")) {
1114
if (!irc_line_includes(line, 1))
1115
return ERR_PROTOCOL;
1116
WRITE_LINE1(CONN(ic), link_name((struct link_any *)ic), "PONG",
1117
irc_line_elem(line, 1));
1119
} else if (LINK(ic)->s_state != IRCS_CONNECTED) {
1120
write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
1121
":ERROR Proxy not connected, please wait "
1122
"before sending commands\r\n");
1124
} else if (strcasecmp(irc_line_elem(line, 0), "BIP") == 0) {
1125
r = irc_cli_bip(bip, ic, line);
1126
} else if (irc_line_elem_equals(line, 0, "JOIN")) {
1127
r = irc_cli_join(ic, line);
1128
} else if (irc_line_elem_equals(line, 0, "PART")) {
1129
r = irc_cli_part(ic, line);
1130
} else if (irc_line_elem_equals(line, 0, "NICK")) {
1131
r = irc_cli_nick(bip, ic, line);
1132
} else if (irc_line_elem_equals(line, 0, "QUIT")) {
1133
r = irc_cli_quit(ic, line);
1134
} else if (irc_line_elem_equals(line, 0, "PRIVMSG")) {
1135
r = irc_cli_privmsg(bip, ic, line);
1136
} else if (irc_line_elem_equals(line, 0, "NOTICE")) {
1137
r = irc_cli_notice(ic, line);
1138
} else if (irc_line_elem_equals(line, 0, "WHO")) {
1139
r = irc_cli_who(ic, line);
1140
} else if (irc_line_elem_equals(line, 0, "MODE")) {
1141
r = irc_cli_mode(ic, line);
1144
if (r == OK_COPY || r == OK_COPY_CLI) {
1145
char *str = irc_line_to_string(line);
1146
if (LINK(ic)->s_state == IRCS_CONNECTED &&
1147
LINK(ic)->l_server->nick)
1148
write_line(CONN(LINK(ic)->l_server), str);
1149
else if (LINK(ic)->l_server->nick)
1150
WRITE_LINE2(CONN(ic), P_IRCMASK,
1151
(LINK(ic)->user->bip_use_notice ?
1152
"NOTICE" : "PRIVMSG"),
1153
LINK(ic)->l_server->nick,
1154
":Not connected please try again "
1158
if (r == OK_COPY_CLI) {
1160
struct link_server *s = LINK(ic)->l_server;
1162
for (i = 0; i < LINK(s)->l_clientc; i++)
1163
irc_copy_cli(ic, LINK(s)->l_clientv[i], line);
1169
static void irc_copy_cli(struct link_client *src, struct link_client *dest,
1177
if (!irc_line_includes(line, 1) ||
1178
!irc_line_elem_equals(line, 0, "PRIVMSG")) {
1179
str = irc_line_to_string(line);
1180
write_line(CONN(dest), str);
1185
if (ischannel(*irc_line_elem(line, 1)) || LINK(src) != LINK(dest)) {
1186
assert(!line->origin);
1187
line->origin = LINK(src)->l_server->nick;
1188
str = irc_line_to_string(line);
1189
line->origin = NULL;
1190
write_line(CONN(dest), str);
1195
/* LINK(src) == LINK(dest) */
1196
size_t len = strlen(irc_line_elem(line, 2)) + 5;
1202
tmp = bip_malloc(len);
1204
snprintf(tmp, len, " -> %s", irc_line_elem(line, 2));
1207
struct line *retline = irc_line_new();
1209
retline->origin = bip_strdup(irc_line_elem(line, 1));
1210
irc_line_append(retline, irc_line_elem(line, 0));
1211
irc_line_append(retline, LINK(src)->l_server->nick);
1212
irc_line_append(retline, tmp);
1214
str = irc_line_to_string(retline);
1215
irc_line_free(retline);
1218
irc_line_elem(line, 1) = LINK(src)->l_server->nick;
1220
oldelem = irc_line_elem(line, 2);
1221
irc_line_elem(line, 2) = tmp;
1222
str = irc_line_to_string(line);
1224
irc_line_elem(line, 1) = line->origin;
1225
irc_line_elem(line, 2) = oldelem;
1226
line->origin = NULL;
1228
write_line(CONN(dest), str);
1233
static int irc_dispatch_loging_client(bip_t *bip, struct link_client *ic,
1236
if (irc_line_count(line) == 0)
1237
return ERR_PROTOCOL;
1239
if (irc_line_elem_equals(line, 0, "NICK")) {
1240
return irc_cli_nick(bip, ic, line);
1241
} else if (irc_line_elem_equals(line, 0, "USER")) {
1242
return irc_cli_user(bip, ic, line);
1243
} else if (irc_line_elem_equals(line, 0, "PASS")) {
1244
return irc_cli_pass(bip, ic, line);
1249
int irc_dispatch(bip_t *bip, struct link_any *l, struct line *line)
1252
case IRC_TYPE_SERVER:
1253
return irc_dispatch_server(bip, (struct link_server*)l, line);
1255
case IRC_TYPE_CLIENT:
1256
return irc_dispatch_client(bip, (struct link_client*)l, line);
1258
case IRC_TYPE_LOGING_CLIENT:
1259
return irc_dispatch_loging_client(bip, (struct link_client*)l,
1263
case IRC_TYPE_TRUST_CLIENT:
1264
return irc_dispatch_trust_client((struct link_client*)l, line);
1270
return ERR_PROTOCOL; /* never reached */
1273
static int origin_is_me(struct line *l, struct link_server *server)
1279
nick = nick_from_ircmask(l->origin);
1280
if (strcasecmp(nick, server->nick) == 0) {
1288
static int irc_join(struct link_server *server, struct line *line)
1292
struct channel *channel;
1294
if (irc_line_count(line) != 2 && irc_line_count(line) != 3)
1295
return ERR_PROTOCOL;
1297
s_chan = irc_line_elem(line, 1);
1298
log_join(LINK(server)->log, line->origin, s_chan);
1300
channel = hash_get(&server->channels, s_chan);
1301
if (origin_is_me(line, server)) {
1303
channel = channel_new(s_chan);
1304
hash_insert(&server->channels, s_chan, channel);
1308
/* if we're not on channel and !origin_is_me, we should not get any
1311
return ERR_PROTOCOL;
1313
return ERR_PROTOCOL;
1315
s_nick = nick_from_ircmask(line->origin);
1316
hash_insert(&channel->ovmasks, s_nick, 0);
1321
static int irc_332(struct link_server *server, struct line *line)
1323
struct channel *channel;
1324
if (irc_line_count(line) != 4)
1325
return ERR_PROTOCOL;
1327
channel = hash_get(&server->channels, irc_line_elem(line, 2));
1328
/* we can get topic reply for chans we're not on */
1333
free(channel->topic);
1334
channel->topic = bip_strdup(irc_line_elem(line, 3));
1336
log_init_topic(LINK(server)->log, channel->name, channel->topic);
1340
static int irc_333(struct link_server *server, struct line *line)
1342
struct channel *channel;
1343
if (!irc_line_includes(line, 2))
1344
return ERR_PROTOCOL;
1346
channel = hash_get(&server->channels, irc_line_elem(line, 2));
1347
/* we can get topic info reply for chans we're not on */
1350
if (channel->creator)
1351
free(channel->creator);
1352
if (channel->create_ts)
1353
free(channel->create_ts);
1354
if (irc_line_count(line) == 5) {
1355
channel->creator = bip_strdup(irc_line_elem(line, 3));
1356
channel->create_ts = bip_strdup(irc_line_elem(line, 4));
1358
channel->creator = bip_strdup("");
1359
channel->create_ts = bip_strdup("0");
1361
log_init_topic_time(LINK(server)->log, channel->name, channel->creator,
1362
channel->create_ts);
1366
static int irc_353(struct link_server *server, struct line *line)
1368
struct channel *channel;
1369
const char *names, *eon;
1373
if (irc_line_count(line) != 5)
1374
return ERR_PROTOCOL;
1376
channel = hash_get(&server->channels, irc_line_elem(line, 3));
1377
/* we can get names reply for chans we're not on */
1381
if (!channel->running_names) {
1382
channel->running_names = 1;
1383
hash_clean(&channel->ovmasks);
1386
/* TODO check that type is one of "=" / "*" / "@" */
1387
channel->type = irc_line_elem(line, 2)[0];
1389
names = irc_line_elem(line, 4);
1392
long int ovmask = 0;
1394
/* some ircds (e.g. unreal) may display several flags for the
1404
ovmask |= NICKVOICED;
1406
case '%': /* unrealircd and others: halfop */
1408
ovmask |= NICKHALFOP;
1410
case '&': /* unrealircd: protect */
1411
case '~': /* unrealircd: owner */
1420
while (*eon && *eon != ' ')
1424
nick = bip_malloc(len + 1);
1425
memcpy(nick, names, len);
1428
/* we just ignore names for nicks that are crazy long */
1429
if (len + 2 < NAMESIZE)
1430
hash_insert(&channel->ovmasks, nick, (void *)ovmask);
1433
while (*eon && *eon == ' ')
1440
static int irc_366(struct link_server *server, struct line *line)
1442
struct channel *channel;
1444
if (irc_line_count(line) != 4)
1445
return ERR_PROTOCOL;
1447
channel = hash_get(&server->channels, irc_line_elem(line, 2));
1448
if (channel && channel->running_names)
1449
channel->running_names = 0;
1453
static int irc_367(struct link_server *server, struct line *l)
1460
/* same as irc_315 */
1461
static int irc_368(struct link_server *server, struct line *l)
1463
struct link *link = LINK(server);
1464
if (link->who_client) {
1465
if (link->who_client->who_count == 0) {
1466
mylog(LOG_DEBUG, "Spurious irc_368");
1469
link->who_client->whoc_tstamp = time(NULL);
1471
if (link->who_client->who_count > 0) {
1472
--link->who_client->who_count;
1474
"RPL_ENDOFBANLIST: "
1475
"Decrementing who count for %p: %d",
1476
link->who_client, link->who_client->who_count);
1479
l = NULL; /* keep gcc happy */
1484
static void channel_free(struct channel *c)
1499
hash_clean(&c->ovmasks);
1503
static int irc_part(struct link_server *server, struct line *line)
1507
struct channel *channel;
1509
if (irc_line_count(line) != 2 && irc_line_count(line) != 3)
1510
return ERR_PROTOCOL;
1512
s_chan = irc_line_elem(line, 1);
1514
channel = hash_get(&server->channels, s_chan);
1515
/* we can't get part message for chans we're not on */
1517
return ERR_PROTOCOL;
1519
if (origin_is_me(line, server)) {
1520
log_part(LINK(server)->log, line->origin, s_chan,
1521
irc_line_count(line) == 3 ? irc_line_elem(line, 2) :
1523
log_reset_store(LINK(server)->log, s_chan);
1524
log_drop(LINK(server)->log, s_chan);
1526
hash_remove(&server->channels, s_chan);
1527
channel_free(channel);
1532
return ERR_PROTOCOL;
1533
s_nick = nick_from_ircmask(line->origin);
1534
if (!hash_includes(&channel->ovmasks, s_nick)) {
1536
return ERR_PROTOCOL;
1538
hash_remove(&channel->ovmasks, s_nick);
1541
log_part(LINK(server)->log, line->origin, s_chan,
1542
irc_line_count(line) == 3 ?
1543
irc_line_elem(line, 2) : NULL);
1548
static void mode_add_letter_uniq(struct link_server *s, char c)
1551
for (i = 0; i < s->user_mode_len; i++) {
1552
if (s->user_mode[i] == c)
1555
s->user_mode = bip_realloc(s->user_mode, s->user_mode_len + 1);
1556
s->user_mode[s->user_mode_len++] = c;
1559
static void mode_remove_letter(struct link_server *s, char c)
1562
for (i = 0; i < s->user_mode_len; i++) {
1563
if (s->user_mode[i] == c) {
1564
for (; i < s->user_mode_len - 1; i++)
1565
s->user_mode[i] = s->user_mode[i + 1];
1567
s->user_mode = bip_realloc(s->user_mode,
1574
static void irc_user_mode(struct link_server *server, struct line *line)
1579
for (mode = irc_line_elem(line, 2); *mode; mode++) {
1582
else if (*mode == '+')
1586
mode_add_letter_uniq(server, *mode);
1588
mode_remove_letter(server, *mode);
1594
static int irc_mode(struct link_server *server, struct line *line)
1596
struct channel *channel;
1599
unsigned cur_arg = 0;
1600
array_t *mode_args = NULL;
1602
if (!irc_line_includes(line, 2))
1603
return ERR_PROTOCOL;
1605
/* nick mode change */
1606
if (irc_line_elem_equals(line, 1, server->nick)) {
1607
if (irc_line_includes(line, 3))
1608
mode_args = array_extract(&line->words, 3, -1);
1609
log_mode(LINK(server)->log, line->origin,
1610
irc_line_elem(line, 1), irc_line_elem(line, 2),
1613
array_free(mode_args);
1614
irc_user_mode(server, line);
1618
if (!ischannel(irc_line_elem(line, 1)[0]))
1619
return ERR_PROTOCOL;
1621
/* channel mode change */
1622
channel = hash_get(&server->channels, irc_line_elem(line, 1));
1623
/* we can't get mode message for chans we're not on */
1625
return ERR_PROTOCOL;
1628
if (irc_line_includes(line, 3))
1629
mode_args = array_extract(&line->words, 3, -1);
1630
log_mode(LINK(server)->log, line->origin, irc_line_elem(line, 1),
1631
irc_line_elem(line, 2), mode_args);
1633
array_free(mode_args);
1636
* MODE -a+b.. #channel args
1642
for (mode = irc_line_elem(line, 2); *mode; mode++) {
1651
if (!irc_line_includes(line, cur_arg + 3))
1652
return ERR_PROTOCOL;
1656
if (!irc_line_includes(line, cur_arg + 3))
1657
return ERR_PROTOCOL;
1658
nick = irc_line_elem(line, cur_arg + 3);
1660
if (!hash_includes(&channel->ovmasks, nick))
1661
return ERR_PROTOCOL;
1662
ovmask = (long int)hash_remove(&channel->ovmasks, nick);
1667
hash_insert(&channel->ovmasks, nick, (void *)ovmask);
1671
if (!irc_line_includes(line, cur_arg + 3))
1672
return ERR_PROTOCOL;
1673
nick = irc_line_elem(line, cur_arg + 3);
1675
if (!hash_includes(&channel->ovmasks, nick))
1676
return ERR_PROTOCOL;
1678
ovmask = (long int)hash_remove(&channel->ovmasks, nick);
1680
ovmask |= NICKHALFOP;
1682
ovmask &= ~NICKHALFOP;
1683
hash_insert(&channel->ovmasks, nick, (void *)ovmask);
1687
if (!irc_line_includes(line, cur_arg + 3))
1688
return ERR_PROTOCOL;
1689
nick = irc_line_elem(line, cur_arg + 3);
1691
if (!hash_includes(&channel->ovmasks, nick))
1692
return ERR_PROTOCOL;
1694
ovmask = (long int)hash_remove(&channel->ovmasks, nick);
1696
ovmask |= NICKVOICED;
1698
ovmask &= ~NICKVOICED;
1699
hash_insert(&channel->ovmasks, nick, (void *)ovmask);
1704
if (!irc_line_includes(line, cur_arg + 3))
1705
return ERR_PROTOCOL;
1707
channel->key = bip_strdup(
1708
irc_line_elem(line, cur_arg + 3));
1713
channel->key = NULL;
1725
/* Sucky way to try to deal with all the different mode
1727
if (irc_line_includes(line, cur_arg + 3))
1737
static char *irc_timestamp(void)
1739
char *ts = bip_malloc(21);
1740
snprintf(ts, 20, "%ld", (long int)time(NULL));
1744
static int irc_topic(struct link_server *server, struct line *line)
1746
struct channel *channel;
1749
if (irc_line_count(line) != 3)
1750
return ERR_PROTOCOL;
1752
channel = hash_get(&server->channels, irc_line_elem(line, 1));
1753
/* we can't get topic message for chans we're not on */
1755
return ERR_PROTOCOL;
1758
free(channel->topic);
1759
topic = irc_line_elem(line, 2);
1762
channel->topic = bip_strdup(topic);
1765
* :arion.oftc.net 333 bip`luser #bipqSDFQE3
1766
* nohar!~nohar@borne28.noc.nerim.net 1107338095
1769
if (channel->creator)
1770
free(channel->creator);
1771
channel->creator = bip_strmaydup(line->origin);
1772
if (channel->create_ts)
1773
free(channel->create_ts);
1774
channel->create_ts = irc_timestamp();
1776
log_topic(LINK(server)->log, line->origin, irc_line_elem(line, 1),
1781
static int irc_kick(struct link_server *server, struct line *line)
1783
struct channel *channel;
1785
if (irc_line_count(line) != 3 && irc_line_count(line) != 4)
1786
return ERR_PROTOCOL;
1788
channel = hash_get(&server->channels, irc_line_elem(line, 1));
1789
/* we can't get kick message for chans we're not on */
1791
return ERR_PROTOCOL;
1793
if (!hash_includes(&channel->ovmasks, irc_line_elem(line, 2)))
1794
return ERR_PROTOCOL;
1796
if (strcasecmp(irc_line_elem(line, 2), server->nick) == 0) {
1797
/* we get kicked !! */
1798
log_kick(LINK(server)->log, line->origin, channel->name,
1799
irc_line_elem(line, 2),
1800
irc_line_count(line) == 4 ?
1801
irc_line_elem(line, 3) : NULL);
1802
log_reset_store(LINK(server)->log, channel->name);
1803
log_drop(LINK(server)->log, channel->name);
1805
if (LINK(server)->autojoin_on_kick) {
1807
WRITE_LINE1(CONN(server), NULL, "JOIN",
1810
WRITE_LINE2(CONN(server), NULL, "JOIN",
1811
channel->name, channel->key);
1814
hash_remove(&server->channels, channel->name);
1815
channel_free(channel);
1819
hash_remove(&channel->ovmasks, irc_line_elem(line, 2));
1820
log_kick(LINK(server)->log, line->origin, irc_line_elem(line, 1),
1821
irc_line_elem(line, 2),
1822
irc_line_count(line) == 4 ? irc_line_elem(line, 3) : NULL);
1828
static void irc_privmsg_check_ctcp(struct link_server *server,
1831
if (irc_line_count(line) != 3)
1838
nick = nick_from_ircmask(line->origin);
1839
if (irc_line_elem_equals(line, 2, "\001VERSION\001")) {
1840
WRITE_LINE2(CONN(server), NULL, "NOTICE", nick,
1841
"\001VERSION bip-" BIP_VERSION "\001");
1846
static int irc_privmsg(struct link_server *server, struct line *line)
1848
if (!irc_line_includes(line, 2))
1849
return ERR_PROTOCOL;
1850
if (LINK(server)->s_state == IRCS_CONNECTED)
1851
log_privmsg(LINK(server)->log, line->origin,
1852
irc_line_elem(line, 1), irc_line_elem(line, 2));
1853
irc_privmsg_check_ctcp(server, line);
1857
static int irc_notice(struct link_server *server, struct line *line)
1859
if (!irc_line_includes(line, 2))
1860
return ERR_PROTOCOL;
1861
if (LINK(server)->s_state == IRCS_CONNECTED)
1862
log_notice(LINK(server)->log, line->origin,
1863
irc_line_elem(line, 1), irc_line_elem(line, 2));
1867
static int irc_quit(struct link_server *server, struct line *line)
1869
return irc_generic_quit(server, line);
1872
static int irc_nick(struct link_server *server, struct line *line)
1874
struct channel *channel;
1877
const char *dst_nick;
1879
if (irc_line_count(line) != 2)
1880
return ERR_PROTOCOL;
1883
return ERR_PROTOCOL;
1885
org_nick = nick_from_ircmask(line->origin);
1886
dst_nick = irc_line_elem(line, 1);
1888
for (hash_it_init(&server->channels, &hi); hash_it_item(&hi);
1889
hash_it_next(&hi)) {
1890
channel = hash_it_item(&hi);
1891
if (!hash_includes(&channel->ovmasks, org_nick))
1893
hash_rename_key(&channel->ovmasks, org_nick, dst_nick);
1894
log_nick(LINK(server)->log, org_nick, channel->name, dst_nick);
1897
if (origin_is_me(line, server)) {
1899
server->nick = bip_strdup(dst_nick);
1900
if (LINK(server)->follow_nick &&
1901
(LINK(server)->away_nick == NULL ||
1902
strcmp(server->nick, LINK(server)->away_nick))
1904
free(LINK(server)->connect_nick);
1905
LINK(server)->connect_nick = bip_strdup(server->nick);
1913
static int irc_generic_quit(struct link_server *server, struct line *line)
1915
struct channel *channel;
1919
if (irc_line_count(line) != 2 && irc_line_count(line) != 1)
1920
return ERR_PROTOCOL;
1923
return ERR_PROTOCOL;
1924
s_nick = nick_from_ircmask(line->origin);
1925
for (hash_it_init(&server->channels, &hi); hash_it_item(&hi);
1926
hash_it_next(&hi)) {
1927
channel = hash_it_item(&hi);
1928
if (!hash_includes(&channel->ovmasks, s_nick))
1930
hash_remove(&channel->ovmasks, s_nick);
1931
log_quit(LINK(server)->log, line->origin, channel->name,
1932
irc_line_includes(line, 1) ?
1933
irc_line_elem(line, 1) : NULL);
1939
static void ls_set_nick(struct link_server *ircs, char *nick)
1945
if (ircs->ircmask) {
1946
char *eom = strchr(ircs->ircmask, '!');
1948
free(ircs->ircmask);
1951
eom = bip_strdup(eom);
1952
free(ircs->ircmask);
1953
ircs->ircmask = bip_malloc(strlen(nick) + strlen(eom) + 1);
1954
strcpy(ircs->ircmask, nick);
1955
strcat(ircs->ircmask, eom);
1960
ircs->ircmask = bip_malloc(strlen(nick) + strlen(BIP_FAKEMASK) + 1);
1961
strcpy(ircs->ircmask, nick);
1962
strcat(ircs->ircmask, BIP_FAKEMASK);
1966
static void irc_server_startup(struct link_server *ircs)
1969
char *username, *realname;
1971
/* lower the token number as freenode hates fast login */
1972
CONN(ircs)->token = 1;
1974
if (LINK(ircs)->s_password)
1975
WRITE_LINE1(CONN(ircs), NULL, "PASS", LINK(ircs)->s_password);
1977
username = LINK(ircs)->username;
1979
username = LINK(ircs)->user->default_username;
1980
realname = LINK(ircs)->realname;
1982
realname = LINK(ircs)->user->default_realname;
1983
WRITE_LINE4(CONN(ircs), NULL, "USER", username, "0", "*", realname);
1986
if (LINK(ircs)->away_nick && LINK(ircs)->l_clientc == 0) {
1989
nick = bip_strdup(LINK(ircs)->away_nick);
1991
if ((!LINK(ircs)->follow_nick && !LINK(ircs)->away_nick)
1995
if (!LINK(ircs)->connect_nick)
1996
LINK(ircs)->connect_nick =
1997
bip_strdup(LINK(ircs)->user->default_nick);
1998
nick = bip_strdup(LINK(ircs)->connect_nick);
2001
ls_set_nick(ircs, nick);
2002
WRITE_LINE1(CONN(ircs), NULL, "NICK", ircs->nick);
2005
static void server_next(struct link *l)
2008
if (l->cur_server >= l->network->serverc)
2012
static struct link_client *irc_accept_new(connection_t *conn)
2014
struct link_client *ircc;
2015
connection_t *newconn;
2017
newconn = accept_new(conn);
2021
ircc = bip_calloc(sizeof(struct link_client), 1);
2022
CONN(ircc) = newconn;
2023
TYPE(ircc) = IRC_TYPE_LOGING_CLIENT;
2024
CONN(ircc)->user_data = ircc;
2028
void server_cleanup(struct link_server *server)
2032
server->nick = NULL;
2034
if (LINK(server)->s_state == IRCS_CONNECTED) {
2035
LINK(server)->s_state = IRCS_WAS_CONNECTED;
2038
LINK(server)->s_state = IRCS_NONE;
2039
while ((s = list_remove_first(&LINK(server)->init_strings)))
2044
for (hash_it_init(&server->channels, &hi); hash_it_item(&hi);
2046
channel_free(hash_it_item(&hi));
2047
hash_clean(&server->channels);
2050
connection_free(CONN(server));
2051
CONN(server) = NULL;
2053
irc_lag_init(server);
2056
void irc_client_close(struct link_client *ic)
2058
if (TYPE(ic) == IRC_TYPE_CLIENT) {
2059
struct link_server *is = LINK(ic)->l_server;
2060
log_client_disconnected(LINK(ic)->log);
2061
unbind_from_link(ic);
2062
if (LINK(ic)->l_clientc == 0) {
2063
if (is && LINK(ic)->away_nick)
2064
WRITE_LINE1(CONN(is), NULL, "NICK",
2065
LINK(ic)->away_nick);
2066
if (is && LINK(ic)->no_client_away_msg)
2067
WRITE_LINE1(CONN(is), NULL, "AWAY",
2068
LINK(ic)->no_client_away_msg);
2069
log_client_none_connected(LINK(ic)->log);
2071
irc_client_free(ic);
2072
} else if (TYPE(ic) == IRC_TYPE_LOGING_CLIENT) {
2073
irc_client_free(ic);
2077
static void server_setup_reconnect_timer(struct link *link)
2081
if (link->last_connection_attempt &&
2082
time(NULL) - link->last_connection_attempt
2084
timer = RECONN_TIMER * (link->s_conn_attempt);
2085
if (timer > RECONN_TIMER_MAX)
2086
timer = RECONN_TIMER_MAX;
2088
mylog(LOG_ERROR, "[%s] reconnecting in %d seconds", link->name,
2090
link->recon_timer = timer;
2093
static void irc_close(struct link_any *l)
2096
connection_free(CONN(l));
2099
if (TYPE(l) == IRC_TYPE_SERVER) {
2100
/* TODO: free link_server as a whole */
2101
struct link_server *is = (struct link_server *)l;
2103
if (LINK(is)->s_state == IRCS_CONNECTED)
2104
irc_notify_disconnection(is);
2105
irc_server_shutdown(is);
2106
log_disconnected(LINK(is)->log);
2108
server_next(LINK(is));
2110
server_setup_reconnect_timer(LINK(is));
2112
LINK(is)->l_server = NULL;
2113
irc_server_free((struct link_server *)is);
2115
irc_client_close((struct link_client *)l);
2119
struct link_client *irc_client_new(void)
2121
struct link_client *c;
2123
c = bip_calloc(sizeof(struct link_client), 1);
2124
list_init(&c->who_queue, list_ptr_cmp);
2129
struct link_server *irc_server_new(struct link *link, connection_t *conn)
2131
struct link_server *s;
2133
s = bip_calloc(sizeof(struct link_server), 1);
2135
TYPE(s) = IRC_TYPE_SERVER;
2136
hash_init(&s->channels, HASH_NOCASE);
2146
void irc_server_free(struct link_server *s)
2149
connection_free(CONN(s));
2156
for (hash_it_init(&s->channels, &hi); hash_it_item(&hi);
2157
hash_it_next(&hi)) {
2158
struct channel *chan = hash_it_item(&hi);
2161
hash_clean(&s->channels);
2166
connection_t *irc_server_connect(struct link *link)
2168
struct link_server *ls;
2171
link->s_conn_attempt++;
2173
mylog(LOG_INFO, "[%s] Connecting user '%s' using server "
2174
"%s:%d", link->name, link->user->name,
2175
link->network->serverv[link->cur_server].host,
2176
link->network->serverv[link->cur_server].port);
2177
conn = connection_new(link->network->serverv[link->cur_server].host,
2178
link->network->serverv[link->cur_server].port,
2179
link->vhost, link->bind_port,
2181
link->network->ssl, link->ssl_check_mode,
2182
link->user->ssl_check_store,
2183
link->user->ssl_client_certfile,
2189
if (conn->handle == -1) {
2190
mylog(LOG_INFO, "[%s] Cannot connect.", link->name);
2191
connection_free(conn);
2196
ls = irc_server_new(link, conn);
2197
conn->user_data = ls;
2199
list_add_last(&_bip->conn_list, conn);
2203
irc_server_startup(ls);
2207
int irc_server_lag_compute(struct link *l)
2209
struct link_server *server = l->l_server;
2211
if (LINK(server)->s_state == IRCS_CONNECTED) {
2212
if (server->laginit_ts != -1) {
2213
irc_compute_lag(server);
2214
if (!irc_lags_out(server))
2218
server->lagtest_timeout--;
2219
if (server->lagtest_timeout == 0)
2220
irc_start_lagtest(server);
2226
void irc_server_shutdown(struct link_server *s)
2230
if (LINK(s)->prev_nick)
2231
free(LINK(s)->prev_nick);
2232
LINK(s)->prev_nick = bip_strdup(s->nick);
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)
2242
void oidentd_dump(bip_t *bip)
2246
char *bipstart = NULL, *bipend = NULL;
2248
char tag_written = 0;
2250
if (stat(bip->oidentdpath, &stats) == -1) {
2251
if (errno == ENOENT && (f = fopen(bip->oidentdpath, "w+"))) {
2252
fchmod(fileno(f), 0644);
2254
mylog(LOG_WARN, "Can't open/create %s",
2259
/* strip previously autogenerated content */
2261
f = fopen(bip->oidentdpath, "r+");
2264
mylog(LOG_WARN, "Can't open/create %s",
2269
content = (char *)bip_malloc(stats.st_size + 1);
2271
if (fread(content, 1, stats.st_size, f) !=
2272
(size_t)stats.st_size) {
2273
mylog(LOG_WARN, "Can't read %s fully",
2279
/* Set terminating zero for strstr */
2280
content[stats.st_size] = '\0';
2282
bipstart = strstr(content, BIP_OIDENTD_START);
2283
if (bipstart != NULL) {
2284
/* We have some config left, rewrite the file
2286
fseek(f, SEEK_SET, 0);
2287
if (ftruncate(fileno(f), 0) == -1) {
2288
mylog(LOG_DEBUG, "Can't reset %s size",
2294
bipend = strstr(bipstart, BIP_OIDENTD_END);
2296
/* data preceeding the tag */
2297
fwrite(content, 1, bipstart - content, f);
2299
/* data following the tag, if any */
2301
fwrite(bipend + BIP_OIDENTD_END_LENGTH, 1,
2303
(bipend - content) -
2304
BIP_OIDENTD_END_LENGTH, f);
2306
mylog(LOG_WARN, "No %s mark found in %s",
2310
/* No previous conf */
2311
if (stats.st_size != 0 &&
2312
content[stats.st_size - 1] != '\n')
2318
for (list_it_init(&bip->conn_list, &it); list_it_item(&it);
2319
list_it_next(&it)) {
2320
connection_t *c = list_it_item(&it);
2321
struct link_any *la = c->user_data;
2322
if (la && TYPE(la) == IRC_TYPE_SERVER && (
2323
c->connected == CONN_OK ||
2324
c->connected == CONN_NEED_SSLIZE ||
2325
c->connected == CONN_UNTRUSTED)) {
2326
struct link_server *ls;
2330
fprintf(f, BIP_OIDENTD_START);
2334
ls = (struct link_server*)la;
2337
fprintf(f, "to %s fport %d from %s lport %d {\n",
2338
c->remoteip, c->remoteport, c->localip,
2340
fprintf(f, "\treply \"%s\"\n", l->username);
2345
fprintf(f, BIP_OIDENTD_END);
2352
void timeout_clean_who_counts(list_t *conns)
2355
for (list_it_init(conns, &it); list_it_item(&it); list_it_next(&it)) {
2356
struct link *l = list_it_item(&it);
2357
struct link_client *client = l->who_client;
2359
if (client && client->whoc_tstamp) {
2362
if (now - client->whoc_tstamp > 10) {
2363
mylog(LOG_DEBUG, "Yawn, "
2364
"forgetting one who reply");
2365
if (client->who_count > 0)
2366
--client->who_count;
2367
client->whoc_tstamp = time(NULL);
2368
if (client->who_count == 0)
2369
rotate_who_client(l);
2375
void bip_init(bip_t *bip)
2377
memset(bip, 0, sizeof(bip_t));
2378
list_init(&bip->link_list, list_ptr_cmp);
2379
list_init(&bip->conn_list, list_ptr_cmp);
2380
list_init(&bip->connecting_client_list, list_ptr_cmp);
2382
hash_init(&bip->users, HASH_NOCASE);
2383
hash_init(&bip->networks, HASH_NOCASE);
2386
/* Called each second. */
2387
void bip_tick(bip_t *bip)
2389
static int logflush_timer = 0;
2394
if (logflush_timer-- <= 0) {
2395
logflush_timer = conf_log_sync_interval;
2399
/* handle tick for links: detect lags or start a reconnection */
2400
for (list_it_init(&bip->link_list, &li); (link = list_it_item(&li));
2401
list_it_next(&li)) {
2402
if (link->l_server) {
2403
if (irc_server_lag_compute(link)) {
2404
log_ping_timeout(link->log);
2405
list_remove(&bip->conn_list,
2406
CONN(link->l_server));
2407
irc_close((struct link_any *) link->l_server);
2410
if (link->recon_timer == 0) {
2412
link->last_connection_attempt = time(NULL);
2413
conn = irc_server_connect(link);
2415
server_setup_reconnect_timer(link);
2417
link->recon_timer--;
2422
/* drop lagging connecting client */
2423
for (list_it_init(&bip->connecting_client_list, &li); list_it_item(&li);
2424
list_it_next(&li)) {
2425
struct link_client *ic = list_it_item(&li);
2426
ic->logging_timer++;
2427
if (ic->logging_timer > LOGGING_TIMEOUT) {
2429
list_remove(&bip->conn_list, CONN(ic));
2430
irc_close((struct link_any *)ic);
2431
list_it_remove(&li);
2436
* Cleanup lagging or dangling who_count buffers
2438
timeout_clean_who_counts(&bip->link_list);
2441
void bip_on_event(bip_t *bip, connection_t *conn)
2443
struct link_any *lc = (struct link_any *)conn->user_data;
2445
if (conn == bip->listener) {
2446
struct link_client *n = irc_accept_new(conn);
2448
list_add_last(&bip->conn_list, CONN(n));
2449
list_add_last(&bip->connecting_client_list, n);
2453
/* reached only if socket is not listening */
2455
list_t *linel = read_lines(conn, &err);
2457
if (TYPE(lc) == IRC_TYPE_SERVER) {
2458
mylog(LOG_ERROR, "[%s] read_lines error, closing...",
2460
irc_server_shutdown(LINK(lc)->l_server);
2462
mylog(LOG_ERROR, "client read_lines error, closing...");
2470
while ((line_s = list_remove_first(linel))) {
2472
mylog(LOG_DEBUG, "\"%s\"", line_s);
2473
if (*line_s == 0) { /* irssi does that.*/
2478
line = irc_line_new_from_string(line_s);
2480
mylog(LOG_ERROR, "[%s] Error in protocol, closing...",
2483
goto prot_err_lines;
2486
r = irc_dispatch(bip, lc, line);
2487
irc_line_free(line);
2489
if (r == ERR_PROTOCOL) {
2490
mylog(LOG_ERROR, "[%s] Error in protocol, closing...",
2492
goto prot_err_lines;
2495
goto prot_err_lines;
2496
/* XXX: not real error */
2498
goto prot_err_lines;
2504
while ((line_s = list_remove_first(linel)))
2507
list_remove(&bip->conn_list, conn);
2511
if (TYPE(lc) == IRC_TYPE_LOGING_CLIENT)
2512
list_remove(&bip->connecting_client_list, lc);
2519
* inc is the incoming connection, clientl list a list of client struct that
2520
* represent the accepcted credentials
2522
void irc_main(bip_t *bip)
2524
int timeleft = 1000;
2526
if (bip->reloading_client) {
2529
while ((l = list_remove_first(&bip->errors)))
2530
bip_notify(bip->reloading_client, "%s", l);
2531
bip->reloading_client = NULL;
2535
* If the list is empty, we are starting. Otherwise we are reloading,
2536
* and conn_list is kept accross reloads.
2538
if (list_is_empty(&bip->conn_list))
2539
list_add_first(&bip->conn_list, bip->listener);
2544
if (timeleft == 0) {
2546
* Compute timeouts for next reconnections and lagouts
2555
list_t *ready = wait_event(&bip->conn_list, &timeleft, &nc);
2560
while ((conn = list_remove_first(ready)))
2561
bip_on_event(bip, conn);
2564
while (list_remove_first(&bip->connecting_client_list))
2569
void irc_client_free(struct link_client *cli)
2572
connection_free(CONN(cli));
2574
free(cli->init_pass);
2576
free(cli->init_nick);
2580
struct link *irc_link_new()
2583
link = bip_calloc(sizeof(struct link), 1);
2585
link->l_server = NULL;
2586
hash_init(&link->chan_infos, HASH_NOCASE);
2587
list_init(&link->chan_infos_order, list_ptr_cmp);
2588
list_init(&link->on_connect_send, list_ptr_cmp);
2589
link->autojoin_on_kick = 1;
2590
link->ignore_server_capab = 1;
2594
void link_kill(bip_t *bip, struct link *link)
2596
/* in case in never got connected */
2597
if (link->l_server) {
2598
list_remove(&bip->conn_list, CONN(link->l_server));
2599
server_cleanup(link->l_server);
2600
irc_server_free(link->l_server);
2602
while (link->l_clientc) {
2603
struct link_client *lc = link->l_clientv[0];
2604
if (lc == bip->reloading_client)
2605
bip->reloading_client = NULL;
2606
list_remove(&bip->conn_list, CONN(lc));
2607
unbind_from_link(lc);
2608
irc_client_free(lc);
2611
hash_remove(&link->user->connections, link->name);
2613
log_free(link->log);
2614
MAYFREE(link->prev_nick);
2615
MAYFREE(link->cli_nick);
2618
while ((p = list_remove_first(&link->init_strings)))
2620
while ((p = list_remove_first(&link->on_connect_send)))
2622
MAYFREE(link->no_client_away_msg);
2623
MAYFREE(link->away_nick);
2624
hash_clean(&link->chan_infos);
2626
struct chan_infos *ci;
2627
while ((ci = list_remove_first(&link->chan_infos_order)))
2630
MAYFREE(link->username);
2631
MAYFREE(link->realname);
2632
MAYFREE(link->s_password);
2633
MAYFREE(link->connect_nick);
2634
MAYFREE(link->vhost);
2636
sk_X509_free(link->untrusted_certs);