kike: implement INVITE
This commit is contained in:
parent
0ddc0458ef
commit
5b1690ede4
|
@ -28,6 +28,7 @@
|
||||||
331 IRC_RPL_NOTOPIC "%s :No topic is set"
|
331 IRC_RPL_NOTOPIC "%s :No topic is set"
|
||||||
332 IRC_RPL_TOPIC "%s :%s"
|
332 IRC_RPL_TOPIC "%s :%s"
|
||||||
333 IRC_RPL_TOPICWHOTIME "%s %s %lld"
|
333 IRC_RPL_TOPICWHOTIME "%s %s %lld"
|
||||||
|
341 IRC_RPL_INVITING "%s %s"
|
||||||
346 IRC_RPL_INVITELIST "%s %s"
|
346 IRC_RPL_INVITELIST "%s %s"
|
||||||
347 IRC_RPL_ENDOFINVITELIST "%s :End of channel invite list"
|
347 IRC_RPL_ENDOFINVITELIST "%s :End of channel invite list"
|
||||||
348 IRC_RPL_EXCEPTLIST "%s %s"
|
348 IRC_RPL_EXCEPTLIST "%s %s"
|
||||||
|
@ -57,6 +58,7 @@
|
||||||
433 IRC_ERR_NICKNAMEINUSE "%s :Nickname is already in use"
|
433 IRC_ERR_NICKNAMEINUSE "%s :Nickname is already in use"
|
||||||
441 IRC_ERR_USERNOTINCHANNEL "%s %s :They aren't on that channel"
|
441 IRC_ERR_USERNOTINCHANNEL "%s %s :They aren't on that channel"
|
||||||
442 IRC_ERR_NOTONCHANNEL "%s :You're not on that channel"
|
442 IRC_ERR_NOTONCHANNEL "%s :You're not on that channel"
|
||||||
|
443 IRC_ERR_USERONCHANNEL "%s %s :is already on channel"
|
||||||
445 IRC_ERR_SUMMONDISABLED ":SUMMON has been disabled"
|
445 IRC_ERR_SUMMONDISABLED ":SUMMON has been disabled"
|
||||||
446 IRC_ERR_USERSDISABLED ":USERS has been disabled"
|
446 IRC_ERR_USERSDISABLED ":USERS has been disabled"
|
||||||
451 IRC_ERR_NOTREGISTERED ":You have not registered"
|
451 IRC_ERR_NOTREGISTERED ":You have not registered"
|
||||||
|
|
77
kike.c
77
kike.c
|
@ -327,6 +327,8 @@ struct client
|
||||||
unsigned mode; ///< User's mode
|
unsigned mode; ///< User's mode
|
||||||
char *away_message; ///< Away message
|
char *away_message; ///< Away message
|
||||||
time_t last_active; ///< Last PRIVMSG, to get idle time
|
time_t last_active; ///< Last PRIVMSG, to get idle time
|
||||||
|
// XXX: maybe this should rather be a str_map
|
||||||
|
struct str_vector invites; ///< Channel invitations
|
||||||
struct flood_detector antiflood; ///< Flood detector
|
struct flood_detector antiflood; ///< Flood detector
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -340,6 +342,7 @@ client_init (struct client *self)
|
||||||
str_init (&self->write_buffer);
|
str_init (&self->write_buffer);
|
||||||
// TODO: make this configurable and more fine-grained
|
// TODO: make this configurable and more fine-grained
|
||||||
flood_detector_init (&self->antiflood, 10, 20);
|
flood_detector_init (&self->antiflood, 10, 20);
|
||||||
|
str_vector_init (&self->invites);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -361,6 +364,7 @@ client_free (struct client *self)
|
||||||
free (self->address);
|
free (self->address);
|
||||||
free (self->away_message);
|
free (self->away_message);
|
||||||
flood_detector_free (&self->antiflood);
|
flood_detector_free (&self->antiflood);
|
||||||
|
str_vector_free (&self->invites);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void client_close_link (struct client *, const char *);
|
static void client_close_link (struct client *, const char *);
|
||||||
|
@ -2296,6 +2300,67 @@ irc_handle_kick (const struct irc_message *msg, struct client *c)
|
||||||
str_vector_free (&users);
|
str_vector_free (&users);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
irc_is_invited (struct client *c, const char *channel_name)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < c->invites.len; i++)
|
||||||
|
if (!irc_strcmp (c->invites.vector[i], channel_name))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
irc_handle_invite (const struct irc_message *msg, struct client *c)
|
||||||
|
{
|
||||||
|
if (msg->params.len < 2)
|
||||||
|
RETURN_WITH_REPLY (c, IRC_ERR_NEEDMOREPARAMS, msg->command);
|
||||||
|
|
||||||
|
const char *target = msg->params.vector[0];
|
||||||
|
const char *channel_name = msg->params.vector[1];
|
||||||
|
|
||||||
|
struct client *client = str_map_find (&c->ctx->users, target);
|
||||||
|
if (!client)
|
||||||
|
RETURN_WITH_REPLY (c, IRC_ERR_NOSUCHNICK, target);
|
||||||
|
|
||||||
|
struct channel *chan = str_map_find (&c->ctx->channels, channel_name);
|
||||||
|
if (chan)
|
||||||
|
{
|
||||||
|
struct channel_user *inviting_user;
|
||||||
|
if (!(inviting_user = channel_get_user (chan, c)))
|
||||||
|
RETURN_WITH_REPLY (c, IRC_ERR_NOTONCHANNEL, channel_name);
|
||||||
|
if (channel_get_user (chan, client))
|
||||||
|
RETURN_WITH_REPLY (c, IRC_ERR_USERONCHANNEL, target, channel_name);
|
||||||
|
|
||||||
|
if ((chan->modes & IRC_CHAN_MODE_INVITE_ONLY))
|
||||||
|
{
|
||||||
|
if (!(inviting_user->modes & IRC_CHAN_MODE_OPERATOR))
|
||||||
|
RETURN_WITH_REPLY (c, IRC_ERR_CHANOPRIVSNEEDED, channel_name);
|
||||||
|
|
||||||
|
// Only storing the invite if it makes sense
|
||||||
|
if (!irc_is_invited (client, channel_name))
|
||||||
|
str_vector_add (&client->invites, channel_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client_send (client, ":%s!%s@%s INVITE %s %s",
|
||||||
|
c->nickname, c->username, c->hostname, client->nickname, channel_name);
|
||||||
|
if (client->away_message)
|
||||||
|
irc_send_reply (c, IRC_RPL_AWAY,
|
||||||
|
client->nickname, client->away_message);
|
||||||
|
irc_send_reply (c, IRC_RPL_INVITING, client->nickname, channel_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
irc_remove_invite (struct client *c, const char *channel_name)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < c->invites.len; i++)
|
||||||
|
if (!irc_strcmp (c->invites.vector[i], channel_name))
|
||||||
|
{
|
||||||
|
str_vector_remove (&c->invites, i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
irc_try_join (struct client *c, const char *channel_name, const char *key)
|
irc_try_join (struct client *c, const char *channel_name, const char *key)
|
||||||
{
|
{
|
||||||
|
@ -2311,9 +2376,10 @@ irc_try_join (struct client *c, const char *channel_name, const char *key)
|
||||||
else if (channel_get_user (chan, c))
|
else if (channel_get_user (chan, c))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
bool invited = irc_is_invited (c, channel_name);
|
||||||
if ((chan->modes & IRC_CHAN_MODE_INVITE_ONLY)
|
if ((chan->modes & IRC_CHAN_MODE_INVITE_ONLY)
|
||||||
&& !client_in_mask_list (c, &chan->invite_list))
|
&& !client_in_mask_list (c, &chan->invite_list)
|
||||||
// TODO: exceptions caused by INVITE
|
&& !invited)
|
||||||
RETURN_WITH_REPLY (c, IRC_ERR_INVITEONLYCHAN, channel_name);
|
RETURN_WITH_REPLY (c, IRC_ERR_INVITEONLYCHAN, channel_name);
|
||||||
if (chan->key && (!key || strcmp (key, chan->key)))
|
if (chan->key && (!key || strcmp (key, chan->key)))
|
||||||
RETURN_WITH_REPLY (c, IRC_ERR_BADCHANNELKEY, channel_name);
|
RETURN_WITH_REPLY (c, IRC_ERR_BADCHANNELKEY, channel_name);
|
||||||
|
@ -2321,9 +2387,13 @@ irc_try_join (struct client *c, const char *channel_name, const char *key)
|
||||||
&& channel_user_count (chan) >= (size_t) chan->user_limit)
|
&& channel_user_count (chan) >= (size_t) chan->user_limit)
|
||||||
RETURN_WITH_REPLY (c, IRC_ERR_CHANNELISFULL, channel_name);
|
RETURN_WITH_REPLY (c, IRC_ERR_CHANNELISFULL, channel_name);
|
||||||
if (client_in_mask_list (c, &chan->ban_list)
|
if (client_in_mask_list (c, &chan->ban_list)
|
||||||
&& !client_in_mask_list (c, &chan->exception_list))
|
&& !client_in_mask_list (c, &chan->exception_list)
|
||||||
|
&& !invited)
|
||||||
RETURN_WITH_REPLY (c, IRC_ERR_BANNEDFROMCHAN, channel_name);
|
RETURN_WITH_REPLY (c, IRC_ERR_BANNEDFROMCHAN, channel_name);
|
||||||
|
|
||||||
|
// Destroy any invitation as there's no other way to get rid of it
|
||||||
|
irc_remove_invite (c, channel_name);
|
||||||
|
|
||||||
channel_add_user (chan, c)->modes = user_mode;
|
channel_add_user (chan, c)->modes = user_mode;
|
||||||
|
|
||||||
char *message = xstrdup_printf (":%s!%s@%s JOIN %s",
|
char *message = xstrdup_printf (":%s!%s@%s JOIN %s",
|
||||||
|
@ -2494,6 +2564,7 @@ irc_register_handlers (struct server_context *ctx)
|
||||||
{ "JOIN", true, irc_handle_join },
|
{ "JOIN", true, irc_handle_join },
|
||||||
{ "PART", true, irc_handle_part },
|
{ "PART", true, irc_handle_part },
|
||||||
{ "KICK", true, irc_handle_kick },
|
{ "KICK", true, irc_handle_kick },
|
||||||
|
{ "INVITE", true, irc_handle_invite },
|
||||||
{ "TOPIC", true, irc_handle_topic },
|
{ "TOPIC", true, irc_handle_topic },
|
||||||
{ "LIST", true, irc_handle_list },
|
{ "LIST", true, irc_handle_list },
|
||||||
{ "NAMES", true, irc_handle_names },
|
{ "NAMES", true, irc_handle_names },
|
||||||
|
|
Loading…
Reference in New Issue