diff --git a/src/fe-common/irc/fe-events-numeric.c b/src/fe-common/irc/fe-events-numeric.c index fb506d68..7fdbdbbe 100644 --- a/src/fe-common/irc/fe-events-numeric.c +++ b/src/fe-common/irc/fe-events-numeric.c @@ -32,6 +32,8 @@ #include "printtext.h" +static void event_received(const char *data, IRC_SERVER_REC *server); + static char *last_away_nick = NULL; static char *last_away_msg = NULL; @@ -547,16 +549,25 @@ static void event_end_of_whowas(const char *data, IRC_SERVER_REC *server) static void event_target_unavailable(const char *data, IRC_SERVER_REC *server) { char *params, *channel; + IRC_CHANNEL_REC *chanrec; g_return_if_fail(data != NULL); params = event_get_params(data, 2, NULL, &channel); if (!ischannel(*channel)) { /* nick unavailable */ - printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_NICK_UNAVAILABLE, channel); + printformat(server, NULL, MSGLEVEL_CRAP, + IRCTXT_NICK_UNAVAILABLE, channel); } else { - /* channel is unavailable. */ - printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_JOINERROR_UNAVAIL, channel); + chanrec = irc_channel_find(server, channel); + if (chanrec != NULL && chanrec->joined) { + /* dalnet - can't change nick while being banned */ + event_received(data, server); + } else { + /* channel is unavailable. */ + printformat(server, NULL, MSGLEVEL_CRAP, + IRCTXT_JOINERROR_UNAVAIL, channel); + } } g_free(params); @@ -667,8 +678,7 @@ static void event_not_chanop(const char *data, IRC_SERVER_REC *server) g_free(params); } -static void event_received(const char *data, IRC_SERVER_REC *server, - const char *nick, const char *addr) +static void event_received(const char *data, IRC_SERVER_REC *server) { char *params, *args, *ptr; @@ -760,6 +770,8 @@ void fe_events_numeric_init(void) signal_add("event 004", (SIGNAL_FUNC) event_received); signal_add("event 364", (SIGNAL_FUNC) event_received); signal_add("event 365", (SIGNAL_FUNC) event_received); + signal_add("event 432", (SIGNAL_FUNC) event_received); + signal_add("event 438", (SIGNAL_FUNC) event_received); signal_add("event 465", (SIGNAL_FUNC) event_received); } @@ -820,5 +832,7 @@ void fe_events_numeric_deinit(void) signal_remove("event 004", (SIGNAL_FUNC) event_received); signal_remove("event 364", (SIGNAL_FUNC) event_received); signal_remove("event 365", (SIGNAL_FUNC) event_received); + signal_remove("event 432", (SIGNAL_FUNC) event_received); + signal_remove("event 438", (SIGNAL_FUNC) event_received); signal_remove("event 465", (SIGNAL_FUNC) event_received); } diff --git a/src/irc/core/channel-rejoin.c b/src/irc/core/channel-rejoin.c index 7552efcc..e9b783ed 100644 --- a/src/irc/core/channel-rejoin.c +++ b/src/irc/core/channel-rejoin.c @@ -104,14 +104,22 @@ static void channel_rejoin(IRC_SERVER_REC *server, const char *channel) static void event_target_unavailable(const char *data, IRC_SERVER_REC *server) { char *params, *channel; + IRC_CHANNEL_REC *chanrec; g_return_if_fail(data != NULL); params = event_get_params(data, 2, NULL, &channel); if (ischannel(*channel)) { - /* channel is unavailable - try to join again a bit later */ - channel_rejoin(server, channel); - signal_stop(); + chanrec = irc_channel_find(server, channel); + if (chanrec != NULL && chanrec->joined) { + /* dalnet event - can't change nick while + banned in channel */ + } else { + /* channel is unavailable - try to join again + a bit later */ + channel_rejoin(server, channel); + signal_stop(); + } } g_free(params); diff --git a/src/irc/core/irc-commands.c b/src/irc/core/irc-commands.c index 12d21219..e1f73b7e 100644 --- a/src/irc/core/irc-commands.c +++ b/src/irc/core/irc-commands.c @@ -388,6 +388,46 @@ static void cmd_names(const char *data, IRC_SERVER_REC *server, WI_ITEM_REC *ite irc_send_cmdv(server, "NAMES %s", data); } +/* SYNTAX: NICK */ +static void cmd_nick(const char *data, IRC_SERVER_REC *server, WI_ITEM_REC *item) +{ + char *nick; + void *free_arg; + + g_return_if_fail(data != NULL); + + if (!IS_IRC_SERVER(server) || !server->connected) + cmd_return_error(CMDERR_NOT_CONNECTED); + + if (!cmd_get_params(data, &free_arg, 1, &nick)) + return; + + server->nick_changing = TRUE; + irc_send_cmdv(server, "NICK %s", nick); + server_redirect_event(SERVER(server), nick, 1, + "event nick", "nickchange over", -1, + "event 433", "nickchange over", 1, + /* 437: ircnet = target unavailable, + dalnet = banned in channel, + can't change nick */ + "event 437", "nickchange over", -1, + "event 432", "nickchange over", 1, + "event 438", "nickchange over", 1, NULL); + cmd_params_free(free_arg); +} + +static void sig_nickchange_over(const char *data, IRC_SERVER_REC *server, + const char *nick, const char *addr) +{ + char *signal; + + server->nick_changing = FALSE; + + signal = g_strconcat("event ", current_server_event, NULL); + signal_emit(signal, 4, data, server, nick, addr); + g_free(signal); +} + static char *get_redirect_nicklist(const char *nicks, int *free) { char *str, *ret; @@ -452,7 +492,7 @@ static void cmd_whois(const char *data, IRC_SERVER_REC *server, /* do automatic /WHOWAS if any of the nicks wasn't found */ query = get_redirect_nicklist(query, &free_nick); - server_redirect_event((SERVER_REC *) server, query, 2, + server_redirect_event(SERVER(server), query, 2, "event 318", "event 318", 1, "event 402", event_402, -1, "event 311", "whois event", 1, @@ -461,7 +501,8 @@ static void cmd_whois(const char *data, IRC_SERVER_REC *server, cmd_params_free(free_arg); } -static void event_whois(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr) +static void event_whois(const char *data, IRC_SERVER_REC *server, + const char *nick, const char *addr) { server->whois_found = TRUE; signal_emit("event 311", 4, data, server, nick, addr); @@ -477,7 +518,7 @@ static void sig_whois_not_found(const char *data, IRC_SERVER_REC *server) irc_send_cmdv(server, "WHOWAS %s 1", nick); server->whowas_found = FALSE; - server_redirect_event((SERVER_REC *) server, nick, 1, + server_redirect_event(SERVER(server), nick, 1, "event 369", "whowas event end", 1, "event 314", "whowas event", 1, "event 406", "event empty", 1, NULL); @@ -510,7 +551,7 @@ static void cmd_whowas(const char *data, IRC_SERVER_REC *server) "WHOWAS %s %s", nicks, count); nicks = get_redirect_nicklist(nicks, &free_nick); - server_redirect_event((SERVER_REC *) server, nicks, 1, + server_redirect_event(SERVER(server), nicks, 1, "event 369", "event 369", 1, "event 314", "whowas event", 1, NULL); if (free_nick) g_free(nicks); @@ -892,8 +933,8 @@ static void sig_connected(IRC_SERVER_REC *server) /* gui-gnome can use server_redirect_event() in who/list commands so we can't use "command who" or list here.. */ - server_redirect_init((SERVER_REC *) server, "bogus command who", 2, "event 401", "event 315", "event 352", NULL); - server_redirect_init((SERVER_REC *) server, "bogus command list", 1, "event 321", "event 322", "event 323", NULL); + server_redirect_init(SERVER(server), "bogus command who", 2, "event 401", "event 315", "event 352", NULL); + server_redirect_init(SERVER(server), "bogus command list", 1, "event 321", "event 322", "event 323", NULL); } void irc_commands_init(void) @@ -919,8 +960,7 @@ void irc_commands_init(void) command_bind("list", NULL, (SIGNAL_FUNC) cmd_list); command_bind("who", NULL, (SIGNAL_FUNC) cmd_who); command_bind("names", NULL, (SIGNAL_FUNC) cmd_names); - /* SYNTAX: NICK */ - command_bind("nick", NULL, (SIGNAL_FUNC) command_self); + command_bind("nick", NULL, (SIGNAL_FUNC) cmd_nick); /* SYNTAX: NOTE [&] [+|-] [] */ command_bind("note", NULL, (SIGNAL_FUNC) command_self); command_bind("whois", NULL, (SIGNAL_FUNC) cmd_whois); @@ -990,6 +1030,7 @@ void irc_commands_init(void) signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed); signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected); + signal_add("nickchange over", (SIGNAL_FUNC) sig_nickchange_over); signal_add("whois not found", (SIGNAL_FUNC) sig_whois_not_found); signal_add("whois event", (SIGNAL_FUNC) event_whois); signal_add("whowas event", (SIGNAL_FUNC) event_whowas); @@ -1018,7 +1059,7 @@ void irc_commands_deinit(void) command_unbind("list", (SIGNAL_FUNC) cmd_list); command_unbind("who", (SIGNAL_FUNC) cmd_who); command_unbind("names", (SIGNAL_FUNC) cmd_names); - command_unbind("nick", (SIGNAL_FUNC) command_self); + command_unbind("nick", (SIGNAL_FUNC) cmd_nick); command_unbind("note", (SIGNAL_FUNC) command_self); command_unbind("whois", (SIGNAL_FUNC) cmd_whois); command_unbind("whowas", (SIGNAL_FUNC) cmd_whowas); @@ -1060,6 +1101,7 @@ void irc_commands_deinit(void) command_unbind("knockout", (SIGNAL_FUNC) cmd_knockout); signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed); signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected); + signal_remove("nickchange over", (SIGNAL_FUNC) sig_nickchange_over); signal_remove("whois not found", (SIGNAL_FUNC) sig_whois_not_found); signal_remove("whois event", (SIGNAL_FUNC) event_whois); signal_remove("whowas event", (SIGNAL_FUNC) event_whowas); diff --git a/src/irc/core/irc-servers.h b/src/irc/core/irc-servers.h index 25b6f422..c35fb0c8 100644 --- a/src/irc/core/irc-servers.h +++ b/src/irc/core/irc-servers.h @@ -38,6 +38,7 @@ typedef struct { char *usermode; /* The whole mode string .. */ char *userhost; /* /USERHOST - set when joined to first channel */ + int nick_changing:1; /* We've sent nick change command to server */ int whois_coming:1; /* Mostly just to display away message right.. */ int whois_found:1; /* Did WHOIS return any entries? */ int whowas_found:1; /* Did WHOWAS return any entries? */ diff --git a/src/irc/core/lag.c b/src/irc/core/lag.c index 3ab8b13b..2107801d 100644 --- a/src/irc/core/lag.c +++ b/src/irc/core/lag.c @@ -60,6 +60,11 @@ static void lag_get(IRC_SERVER_REC *server) g_return_if_fail(server != NULL); + /* nick changes may fail this check, so we should never do this + while there's nick change request waiting for reply in server.. */ + if (server->nick_changing) + return; + lag = g_new0(LAG_REC, 1); lags = g_slist_append(lags, lag); lag->server = server; @@ -70,9 +75,6 @@ static void lag_get(IRC_SERVER_REC *server) server->lag_sent = time(NULL); server->lag_last_check = time(NULL); - /* NOTE: this will fail if there's any nick changes in buffer - - that's why this function should be called only when the buffer - is empty */ irc_send_cmdv(server, "NOTICE %s :\001IRSSILAG %ld %ld\001", server->nick, lag->time.tv_sec, lag->time.tv_usec); } @@ -141,8 +143,7 @@ static int sig_check_lag(void) rec->connection_lost = TRUE; server_disconnect((SERVER_REC *) rec); } - } - else if (rec->lag_last_check+lag_check_time < now && + } else if (rec->lag_last_check+lag_check_time < now && rec->cmdcount == 0 && rec->connected) { /* no commands in buffer - get the lag */ lag_get(rec);