diff --git a/src/fe-common/irc/fe-netjoin.c b/src/fe-common/irc/fe-netjoin.c index 2629d462..70833a3d 100644 --- a/src/fe-common/irc/fe-netjoin.c +++ b/src/fe-common/irc/fe-netjoin.c @@ -321,10 +321,11 @@ static void msg_join(IRC_SERVER_REC *server, const char *channel, signal_stop(); } -static int netjoin_set_nickmode(NETJOIN_REC *rec, const char *channel, - char mode) +static int netjoin_set_nickmode(IRC_SERVER_REC *server, NETJOIN_REC *rec, + const char *channel, char prefix) { GSList *pos; + const char *flags; char *found_chan = NULL; for (pos = rec->now_channels; pos != NULL; pos = pos->next) { @@ -338,26 +339,25 @@ static int netjoin_set_nickmode(NETJOIN_REC *rec, const char *channel, if (found_chan == NULL) return FALSE; - if (found_chan[0] == '@') - return TRUE; - if (found_chan[0] == '%' && mode == '+') - return TRUE; - - found_chan[0] = mode; + flags = server->get_nick_flags(SERVER(server)); + while (*flags != '\0') { + if (found_chan[0] == *flags) + break; + if (prefix == *flags) { + found_chan[0] = prefix; + break; + } + flags++; + } return TRUE; } -#define isnickmode(c) \ - ((c) == 'o' || (c) == 'v' || (c) == 'h') -#define nickmodechar(c) \ - ((c) == 'o' ? '@' : ((c) == 'v' ? '+' : ((c) == 'h' ? '%' : '\0'))) - static void msg_mode(IRC_SERVER_REC *server, const char *channel, const char *sender, const char *addr, const char *data) { NETJOIN_REC *rec; char *params, *mode, *nicks; - char **nicklist, **nick, type, modechr; + char **nicklist, **nick, type, prefix; int show; g_return_if_fail(data != NULL); @@ -378,12 +378,12 @@ static void msg_mode(IRC_SERVER_REC *server, const char *channel, continue; } - if (*nick != NULL && isnickmode(*mode)) { + if (*nick != NULL && GET_MODE_PREFIX(server, *mode)) { /* give/remove ops */ rec = netjoin_find(server, *nick); - modechr = nickmodechar(*mode); - if (rec == NULL || type != '+' || modechr == '\0' || - !netjoin_set_nickmode(rec, channel, modechr)) + prefix = GET_MODE_PREFIX(server, *mode); + if (rec == NULL || type != '+' || prefix == '\0' || + !netjoin_set_nickmode(server, rec, channel, prefix)) show = TRUE; nick++; } else { diff --git a/src/irc/core/irc-nicklist.c b/src/irc/core/irc-nicklist.c index e5d25d5c..53c4abe0 100644 --- a/src/irc/core/irc-nicklist.c +++ b/src/irc/core/irc-nicklist.c @@ -404,15 +404,11 @@ static void sig_usermode(SERVER_REC *server) static const char *get_nick_flags(SERVER_REC *server) { IRC_SERVER_REC *irc_server = (IRC_SERVER_REC *) server; - static char *std = "@%+"; - char *prefix = g_hash_table_lookup(irc_server->isupport, "prefix"); + const char *prefix = + g_hash_table_lookup(irc_server->isupport, "PREFIX"); - if (prefix == NULL) - return std; prefix = strchr(prefix, ')'); - if (prefix != NULL || *++prefix == '\0') /* FIXME: ugly to modify it */ - return std; - return prefix; + return prefix == NULL ? "" : prefix+1; } static void sig_connected(IRC_SERVER_REC *server) diff --git a/src/irc/core/irc-servers.c b/src/irc/core/irc-servers.c index 6e139c9b..c3a342c5 100644 --- a/src/irc/core/irc-servers.c +++ b/src/irc/core/irc-servers.c @@ -162,7 +162,11 @@ static void server_init(IRC_SERVER_REC *server) } server->isupport = g_hash_table_new((GHashFunc) g_istr_hash, - (GCompareFunc) g_istr_equal); + (GCompareFunc) g_istr_equal); + + /* set the standards */ + g_hash_table_insert(server->isupport, "CHANMODES", "b,k,l,imnpst"); + g_hash_table_insert(server->isupport, "PREFIX", "(ohv)@%+"); server->cmdcount = 0; } @@ -309,7 +313,11 @@ static void sig_disconnected(IRC_SERVER_REC *server) g_slist_free(server->cmdqueue); server->cmdqueue = NULL; - g_hash_table_foreach(server->isupport, (GHFunc) isupport_destroy_hash, server); + if (server->isupport_sent) { + /* these are dynamically allocated only if isupport was sent */ + g_hash_table_foreach(server->isupport, + (GHFunc) isupport_destroy_hash, server); + } g_hash_table_destroy(server->isupport); server->isupport = NULL; @@ -588,6 +596,11 @@ static void parse_prefix(IRC_SERVER_REC *server, const char *sptr) } } +static gboolean hash_clear(gpointer key, gpointer value, gpointer user_data) +{ + return TRUE; +} + static void event_isupport(IRC_SERVER_REC *server, const char *data) { char **item, *sptr, *eptr; @@ -602,6 +615,9 @@ static void event_isupport(IRC_SERVER_REC *server, const char *data) return; sptr++; + /* remove defaults */ + g_hash_table_foreach_remove(server->isupport, hash_clear, NULL); + isupport = g_strsplit(sptr, " ", -1); for(item = isupport; *item != NULL; item++) { @@ -639,12 +655,19 @@ static void event_isupport(IRC_SERVER_REC *server, const char *data) } g_strfreev(isupport); + /* chanmodes/prefix will fully override defaults */ + memset(server->modes, 0, sizeof(server->modes)); + memset(server->prefix, 0, sizeof(server->prefix)); + if ((sptr = g_hash_table_lookup(server->isupport, "CHANMODES"))) parse_chanmodes(server, sptr); /* This is after chanmode because some servers define modes in both */ - if ((sptr = g_hash_table_lookup(server->isupport, "PREFIX"))) - parse_prefix(server, sptr); + if ((sptr = g_hash_table_lookup(server->isupport, "PREFIX")) == NULL) { + sptr = g_strdup("(ohv)@%+"); + g_hash_table_insert(server->isupport, g_strdup("PREFIX"), sptr); + } + parse_prefix(server, sptr); if ((sptr = g_hash_table_lookup(server->isupport, "MODES"))) { server->max_modes_in_cmd = atoi(sptr); diff --git a/src/irc/core/modes.c b/src/irc/core/modes.c index 159d375c..57609e71 100644 --- a/src/irc/core/modes.c +++ b/src/irc/core/modes.c @@ -187,15 +187,15 @@ static void mode_set(IRC_SERVER_REC *server, GString *str, } static void mode_set_arg(IRC_SERVER_REC *server, GString *str, - char type, char mode, const char *arg) + char type, char mode, const char *arg, int user) { g_return_if_fail(str != NULL); g_return_if_fail(type == '-' || arg != NULL); if (type == '-') - mode_remove(server, str, mode, TRUE); + mode_remove(server, str, mode, user); else - mode_add_sorted(server, str, mode, arg, TRUE); + mode_add_sorted(server, str, mode, arg, user); } /* Mode that needs a parameter of a mask for both setting and removing (eg: bans) */ @@ -213,12 +213,12 @@ void modes_type_a(IRC_CHANNEL_REC *channel, const char *setby, char type, /* Mode that needs parameter for both setting and removing (eg: +k) */ void modes_type_b(IRC_CHANNEL_REC *channel, const char *setby, char type, - char mode, char *arg, GString *newmode) + char mode, char *arg, GString *newmode) { if (mode == 'k') { if (*arg == '\0' && type == '+') arg = channel->key != NULL ? channel->key : "???"; - mode_set_arg(channel->server, newmode, type, 'k', arg); + mode_set_arg(channel->server, newmode, type, 'k', arg, FALSE); if (arg != channel->key) { g_free_and_null(channel->key); @@ -233,7 +233,7 @@ void modes_type_c(IRC_CHANNEL_REC *channel, const char *setby, char type, char mode, char *arg, GString *newmode) { if (mode == 'l') { - mode_set_arg(channel->server, newmode, type, 'l', arg); + mode_set_arg(channel->server, newmode, type, 'l', arg, FALSE); channel->limit = type == '-' ? 0 : atoi(arg); } } @@ -355,7 +355,7 @@ char *modes_join(IRC_SERVER_REC *server, const char *old, mode_set(server, newmode, type, *curmode, !channel); else { mode_set_arg(server, newmode, type, *curmode, - cmd_get_param(&modestr)); + cmd_get_param(&modestr), !channel); } curmode++; diff --git a/src/irc/core/modes.h b/src/irc/core/modes.h index d5af8403..70b19042 100644 --- a/src/irc/core/modes.h +++ b/src/irc/core/modes.h @@ -30,6 +30,11 @@ struct modes_type { ((type) == '+' ? HAS_MODE_ARG_SET(server,mode) : \ HAS_MODE_ARG_UNSET(server, mode)) +#define GET_MODE_PREFIX(server, c) \ + ((server)->modes[(int)(unsigned char)c].prefix) +#define GET_PREFIX_MODE(server, c) \ + ((server)->prefix[(int)(unsigned char)c]) + void modes_init(void); void modes_deinit(void); void modes_server_init(IRC_SERVER_REC *);