kike: allow changing user mode
This commit is contained in:
parent
f53fa42ac3
commit
6382ecb016
108
src/kike.c
108
src/kike.c
|
@ -292,20 +292,24 @@ client_free (struct client *self)
|
||||||
free (self->away_message);
|
free (self->away_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
client_mode_to_str (unsigned m, struct str *out)
|
||||||
|
{
|
||||||
|
if (m & IRC_USER_MODE_INVISIBLE) str_append_c (out, 'i');
|
||||||
|
if (m & IRC_USER_MODE_RX_WALLOPS) str_append_c (out, 'w');
|
||||||
|
if (m & IRC_USER_MODE_RESTRICTED) str_append_c (out, 'r');
|
||||||
|
if (m & IRC_USER_MODE_OPERATOR) str_append_c (out, 'o');
|
||||||
|
if (m & IRC_USER_MODE_RX_SERVER_NOTICES) str_append_c (out, 's');
|
||||||
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
client_get_mode (struct client *self)
|
client_get_mode (struct client *self)
|
||||||
{
|
{
|
||||||
struct str mode;
|
struct str mode;
|
||||||
str_init (&mode);
|
str_init (&mode);
|
||||||
|
if (self->away_message)
|
||||||
if (self->away_message) str_append_c (&mode, 'a');
|
str_append_c (&mode, 'a');
|
||||||
|
client_mode_to_str (self->mode, &mode);
|
||||||
unsigned m = self->mode;
|
|
||||||
if (m & IRC_USER_MODE_INVISIBLE) str_append_c (&mode, 'i');
|
|
||||||
if (m & IRC_USER_MODE_RX_WALLOPS) str_append_c (&mode, 'w');
|
|
||||||
if (m & IRC_USER_MODE_RESTRICTED) str_append_c (&mode, 'r');
|
|
||||||
if (m & IRC_USER_MODE_OPERATOR) str_append_c (&mode, 'o');
|
|
||||||
if (m & IRC_USER_MODE_RX_SERVER_NOTICES) str_append_c (&mode, 's');
|
|
||||||
return str_steal (&mode);
|
return str_steal (&mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -887,6 +891,7 @@ enum
|
||||||
IRC_ERR_NOPRIVILEGES = 481,
|
IRC_ERR_NOPRIVILEGES = 481,
|
||||||
IRC_ERR_CHANOPRIVSNEEDED = 482,
|
IRC_ERR_CHANOPRIVSNEEDED = 482,
|
||||||
|
|
||||||
|
IRC_ERR_UMODEUNKNOWNFLAG = 501,
|
||||||
IRC_ERR_USERSDONTMATCH = 502
|
IRC_ERR_USERSDONTMATCH = 502
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -963,6 +968,7 @@ static const char *g_default_replies[] =
|
||||||
[IRC_ERR_NOPRIVILEGES] = ":Permission Denied- You're not an IRC operator",
|
[IRC_ERR_NOPRIVILEGES] = ":Permission Denied- You're not an IRC operator",
|
||||||
[IRC_ERR_CHANOPRIVSNEEDED] = "%s :You're not channel operator",
|
[IRC_ERR_CHANOPRIVSNEEDED] = "%s :You're not channel operator",
|
||||||
|
|
||||||
|
[IRC_ERR_UMODEUNKNOWNFLAG] = ":Unknown MODE flag",
|
||||||
[IRC_ERR_USERSDONTMATCH] = ":Cannot change mode for other users",
|
[IRC_ERR_USERSDONTMATCH] = ":Cannot change mode for other users",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1295,6 +1301,83 @@ irc_maybe_send_channel_list (struct client *c, struct channel *chan,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
irc_modify_mode (unsigned *mask, unsigned mode, bool add)
|
||||||
|
{
|
||||||
|
if (add)
|
||||||
|
*mask |= mode;
|
||||||
|
else
|
||||||
|
*mask &= ~mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
irc_update_user_mode (struct client *c, unsigned new_mode)
|
||||||
|
{
|
||||||
|
unsigned old_mode = c->mode;
|
||||||
|
c->mode = new_mode;
|
||||||
|
|
||||||
|
unsigned added = new_mode & ~old_mode;
|
||||||
|
unsigned removed = old_mode & ~new_mode;
|
||||||
|
|
||||||
|
struct str diff;
|
||||||
|
str_init (&diff);
|
||||||
|
|
||||||
|
if (added)
|
||||||
|
{
|
||||||
|
str_append_c (&diff, '+');
|
||||||
|
client_mode_to_str (added, &diff);
|
||||||
|
}
|
||||||
|
if (removed)
|
||||||
|
{
|
||||||
|
str_append_c (&diff, '-');
|
||||||
|
client_mode_to_str (removed, &diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff.len)
|
||||||
|
irc_send (c, ":%s MODE %s :%s",
|
||||||
|
c->nickname, c->nickname, diff.str);
|
||||||
|
str_free (&diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
irc_handle_user_mode_change (struct client *c, const char *mode_string)
|
||||||
|
{
|
||||||
|
unsigned new_mode = c->mode;
|
||||||
|
bool adding = true;
|
||||||
|
|
||||||
|
while (*mode_string)
|
||||||
|
switch (*mode_string++)
|
||||||
|
{
|
||||||
|
case '+': adding = true; break;
|
||||||
|
case '-': adding = false; break;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
// Ignore, the client should use AWAY
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
irc_modify_mode (&new_mode, IRC_USER_MODE_INVISIBLE, adding);
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
irc_modify_mode (&new_mode, IRC_USER_MODE_RX_WALLOPS, adding);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
if (adding)
|
||||||
|
irc_modify_mode (&new_mode, IRC_USER_MODE_RESTRICTED, true);
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
if (!adding)
|
||||||
|
irc_modify_mode (&new_mode, IRC_USER_MODE_OPERATOR, false);
|
||||||
|
// TODO: check public key fingerprint when adding
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
irc_modify_mode (&new_mode, IRC_USER_MODE_RX_SERVER_NOTICES, adding);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
RETURN_WITH_REPLY (c, IRC_ERR_UMODEUNKNOWNFLAG);
|
||||||
|
}
|
||||||
|
irc_update_user_mode (c, new_mode);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
irc_handle_mode (const struct irc_message *msg, struct client *c)
|
irc_handle_mode (const struct irc_message *msg, struct client *c)
|
||||||
{
|
{
|
||||||
|
@ -1308,11 +1391,14 @@ irc_handle_mode (const struct irc_message *msg, struct client *c)
|
||||||
if (irc_strcmp (target, c->nickname))
|
if (irc_strcmp (target, c->nickname))
|
||||||
RETURN_WITH_REPLY (c, IRC_ERR_USERSDONTMATCH);
|
RETURN_WITH_REPLY (c, IRC_ERR_USERSDONTMATCH);
|
||||||
|
|
||||||
|
if (msg->params.len < 2)
|
||||||
|
{
|
||||||
char *mode = client_get_mode (client);
|
char *mode = client_get_mode (client);
|
||||||
irc_send_reply (c, IRC_RPL_UMODEIS, mode);
|
irc_send_reply (c, IRC_RPL_UMODEIS, mode);
|
||||||
free (mode);
|
free (mode);
|
||||||
|
}
|
||||||
// TODO: mode modification
|
else
|
||||||
|
irc_handle_user_mode_change (c, msg->params.vector[1]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue