isupport patch by David Leadbeater

git-svn-id: http://svn.irssi.org/repos/irssi/trunk@3211 dbcabf3a-b0e7-0310-adc4-f8d773084564
This commit is contained in:
Timo Sirainen 2004-01-20 10:57:57 +00:00 committed by cras
commit 217283caea
30 changed files with 520 additions and 133 deletions

View file

@ -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", "");