diff options
Diffstat (limited to 'src/irc/core/modes.c')
-rw-r--r-- | src/irc/core/modes.c | 192 |
1 files changed, 121 insertions, 71 deletions
diff --git a/src/irc/core/modes.c b/src/irc/core/modes.c index ec41889b..159d375c 100644 --- a/src/irc/core/modes.c +++ b/src/irc/core/modes.c @@ -32,7 +32,7 @@ /* Change nick's mode in channel */ static void nick_mode_change(IRC_CHANNEL_REC *channel, const char *nick, - const char mode, int type, const char *setby) + char mode, int type, const char *setby) { NICK_REC *nickrec; char modestr[2], typestr[2]; @@ -44,8 +44,10 @@ static void nick_mode_change(IRC_CHANNEL_REC *channel, const char *nick, if (nickrec == NULL) return; /* No /names list got yet */ if (mode == '@') nickrec->op = type == '+'; - if (mode == '+') nickrec->voice = type == '+'; - if (mode == '%') nickrec->halfop = type == '+'; + else if (mode == '+') nickrec->voice = type == '+'; + else if (mode == '%') nickrec->halfop = type == '+'; + else if (channel->server->prefix[(unsigned char) mode] != '\0') + nickrec->other = (type == '+' ? mode : '\0'); modestr[0] = mode; modestr[1] = '\0'; typestr[0] = type; typestr[1] = '\0'; @@ -97,13 +99,15 @@ static void mode_add_arg(GString *str, int pos, int updating, const char *arg) } /* Add mode character to list sorted alphabetically */ -static void mode_add_sorted(GString *str, char mode, const char *arg) +static void mode_add_sorted(IRC_SERVER_REC *server, GString *str, + char mode, const char *arg, int user) { char *p; int updating, argpos = 0; /* check that mode isn't already set */ - if (!HAS_MODE_ARG_SET(mode) && mode_is_set(str->str, mode)) + if ((!user && !HAS_MODE_ARG_SET(server, mode)) && + mode_is_set(str->str, mode)) return; updating = FALSE; @@ -114,7 +118,7 @@ static void mode_add_sorted(GString *str, char mode, const char *arg) updating = TRUE; break; } - if (HAS_MODE_ARG_SET(*p)) + if (!user && HAS_MODE_ARG_SET(server, *p)) argpos++; } @@ -154,7 +158,7 @@ static void node_remove_arg(GString *str, int pos) } /* remove mode (and it's argument) from string */ -static void mode_remove(GString *str, char mode) +static void mode_remove(IRC_SERVER_REC *server, GString *str, char mode, int user) { char *p; int argpos = 0; @@ -162,34 +166,91 @@ static void mode_remove(GString *str, char mode) for (p = str->str; *p != '\0' && *p != ' '; p++) { if (mode == *p) { g_string_erase(str, (int) (p-str->str), 1); - if (HAS_MODE_ARG_SET(mode)) + if (!user && HAS_MODE_ARG_SET(server, mode)) node_remove_arg(str, argpos); break; } - if (HAS_MODE_ARG_SET(*p)) + if (!user && HAS_MODE_ARG_SET(server, *p)) argpos++; } } -static void mode_set(GString *str, char type, char mode) +static void mode_set(IRC_SERVER_REC *server, GString *str, + char type, char mode, int user) { g_return_if_fail(str != NULL); if (type == '-') - mode_remove(str, mode); + mode_remove(server, str, mode, user); else - mode_add_sorted(str, mode, NULL); + mode_add_sorted(server, str, mode, NULL, user); } -static void mode_set_arg(GString *str, char type, char mode, const char *arg) +static void mode_set_arg(IRC_SERVER_REC *server, GString *str, + char type, char mode, const char *arg) { g_return_if_fail(str != NULL); g_return_if_fail(type == '-' || arg != NULL); if (type == '-') - mode_remove(str, mode); + mode_remove(server, str, mode, TRUE); else - mode_add_sorted(str, mode, arg); + mode_add_sorted(server, str, mode, arg, TRUE); +} + +/* Mode that needs a parameter of a mask for both setting and removing (eg: bans) */ +void modes_type_a(IRC_CHANNEL_REC *channel, const char *setby, char type, + char mode, char *arg, GString *newmode) +{ + /* Currently only +b is dealt with */ + if (mode == 'b') { + if (type == '+') + banlist_add(channel, arg, setby, time(NULL)); + else + banlist_remove(channel, arg); + } +} + +/* 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) +{ + if (mode == 'k') { + if (*arg == '\0' && type == '+') + arg = channel->key != NULL ? channel->key : "???"; + mode_set_arg(channel->server, newmode, type, 'k', arg); + + if (arg != channel->key) { + g_free_and_null(channel->key); + if (type == '+') + channel->key = g_strdup(arg); + } + } +} + +/* Mode that needs parameter only for adding */ +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); + channel->limit = type == '-' ? 0 : atoi(arg); + } +} + +/* Mode that takes no parameter */ +void modes_type_d(IRC_CHANNEL_REC *channel, const char *setby, + char type, char mode, char *arg, GString *newmode) +{ + mode_set(channel->server, newmode, type, mode, FALSE); +} + +void modes_type_prefix(IRC_CHANNEL_REC *channel, const char *setby, + char type, char mode, char *arg, GString *newmode) +{ + int umode = (unsigned char) mode; + nick_mode_change(channel, arg, channel->server->modes[umode].prefix, + type, setby); } int channel_mode_is_set(IRC_CHANNEL_REC *channel, char mode) @@ -204,8 +265,10 @@ int channel_mode_is_set(IRC_CHANNEL_REC *channel, char mode) void parse_channel_modes(IRC_CHANNEL_REC *channel, const char *setby, const char *mode, int update_key) { + IRC_SERVER_REC *server = channel->server; GString *newmode; char *dup, *modestr, *arg, *curmode, type; + int umode; g_return_if_fail(IS_IRC_CHANNEL(channel)); g_return_if_fail(mode != NULL); @@ -216,7 +279,7 @@ void parse_channel_modes(IRC_CHANNEL_REC *channel, const char *setby, dup = modestr = g_strdup(mode); curmode = cmd_get_param(&modestr); while (*curmode != '\0') { - if (HAS_MODE_ARG(type, *curmode)) { + if (HAS_MODE_ARG(server, type, *curmode)) { /* get the argument for the mode. NOTE: We don't get the +k's argument when joining to channel. */ arg = cmd_get_param(&modestr); @@ -229,54 +292,17 @@ void parse_channel_modes(IRC_CHANNEL_REC *channel, const char *setby, case '-': type = *curmode; break; - - case 'b': - if (type == '+') - banlist_add(channel, arg, setby, time(NULL)); - else - banlist_remove(channel, arg); - break; - case 'o': - case 'O': /* channel owner in !channels */ - if (g_strcasecmp(channel->server->nick, arg) == 0) - channel->chanop = type == '+'; - nick_mode_change(channel, arg, '@', type, setby); - break; - case 'h': - nick_mode_change(channel, arg, '%', type, setby); - break; - case 'v': - nick_mode_change(channel, arg, '+', type, setby); - break; - - case 'l': - mode_set_arg(newmode, type, 'l', arg); - channel->limit = type == '-' ? 0 : atoi(arg); - break; - case 'k': - if ((*arg == '\0' && type == '+') || - (channel->key != NULL && !update_key)) { - arg = channel->key != NULL ? channel->key : - "???"; - } - mode_set_arg(newmode, type, 'k', arg); - - if (arg != channel->key) { - g_free_and_null(channel->key); - if (type == '+') - channel->key = g_strdup(arg); - } - break; - case 'e': - case 'I': - case 'q': - case 'd': - /* Don't set it as channel mode */ - break; - default: - mode_set(newmode, type, *curmode); - break; + umode = (unsigned char) *curmode; + if (server->modes[umode].func != NULL) { + server->modes[umode].func(channel, setby, + type, *curmode, arg, + newmode); + } else { + /* Treat unknown modes as ones without params */ + modes_type_d(channel, setby, type, *curmode, + arg, newmode); + } } curmode++; @@ -305,7 +331,8 @@ void parse_channel_modes(IRC_CHANNEL_REC *channel, const char *setby, /* add `mode' to `old' - return newly allocated mode. `channel' specifies if we're parsing channel mode and we should try to join mode arguments too. */ -char *modes_join(const char *old, const char *mode, int channel) +char *modes_join(IRC_SERVER_REC *server, const char *old, + const char *mode, int channel) { GString *newmode; char *dup, *modestr, *curmode, type; @@ -324,10 +351,10 @@ char *modes_join(const char *old, const char *mode, int channel) continue; } - if (!channel || !HAS_MODE_ARG(type, *curmode)) - mode_set(newmode, type, *curmode); + if (!channel || !HAS_MODE_ARG(server, type, *curmode)) + mode_set(server, newmode, type, *curmode, !channel); else { - mode_set_arg(newmode, type, *curmode, + mode_set_arg(server, newmode, type, *curmode, cmd_get_param(&modestr)); } @@ -348,7 +375,7 @@ static void parse_user_mode(IRC_SERVER_REC *server, const char *modestr) g_return_if_fail(IS_IRC_SERVER(server)); g_return_if_fail(modestr != NULL); - newmode = modes_join(server->usermode, modestr, FALSE); + newmode = modes_join(NULL, server->usermode, modestr, FALSE); oldmode = server->usermode; server->usermode = newmode; server->server_operator = (strchr(newmode, 'o') != NULL); @@ -430,7 +457,7 @@ static void sig_req_usermode_change(IRC_SERVER_REC *server, const char *data, &target, &mode); if (!ischannel(*target)) { /* we requested a user mode change, save this */ - mode = modes_join(server->wanted_usermode, mode, FALSE); + mode = modes_join(NULL, server->wanted_usermode, mode, FALSE); g_free_not_null(server->wanted_usermode); server->wanted_usermode = mode; } @@ -520,7 +547,7 @@ void channel_set_mode(IRC_SERVER_REC *server, const char *channel, } if (count == server->max_modes_in_cmd && - HAS_MODE_ARG(type, *curmode)) { + HAS_MODE_ARG(chanrec->server, type, *curmode)) { irc_send_cmdv(server, "MODE %s %s%s", channel, tmode->str, targs->str); @@ -535,7 +562,7 @@ void channel_set_mode(IRC_SERVER_REC *server, const char *channel, } g_string_append_c(tmode, *curmode); - if (HAS_MODE_ARG(type, *curmode)) { + if (HAS_MODE_ARG(chanrec->server, type, *curmode)) { char *arg; count++; @@ -762,6 +789,29 @@ static void cmd_mode(const char *data, IRC_SERVER_REC *server, cmd_params_free(free_arg); } +void modes_server_init(IRC_SERVER_REC *server) +{ + server->modes['b'].func = modes_type_a; + server->modes['e'].func = modes_type_a; + server->modes['I'].func = modes_type_a; + + server->modes['h'].func = modes_type_prefix; + server->modes['h'].prefix = '%'; + server->modes['o'].func = modes_type_prefix; + server->modes['o'].prefix = '@'; + server->modes['O'].func = modes_type_prefix; + server->modes['O'].prefix = '@'; + server->modes['v'].func = modes_type_prefix; + server->modes['v'].prefix = '+'; + + server->prefix['%'] = 'h'; + server->prefix['@'] = 'o'; + server->prefix['+'] = 'v'; + + server->modes['l'].func = modes_type_b; + server->modes['k'].func = modes_type_c; +} + void modes_init(void) { settings_add_str("misc", "opermode", ""); |