degesch: hack together preliminary MODE parsing

This commit is contained in:
Přemysl Eric Janouch 2015-06-04 23:55:10 +02:00
parent 9b1664f968
commit c8aff23ab2
1 changed files with 168 additions and 3 deletions

171
degesch.c
View File

@ -3826,8 +3826,6 @@ irc_is_highlight (struct server *s, const char *message)
// --- Input handling ---------------------------------------------------------- // --- Input handling ----------------------------------------------------------
// TODO: we will need a proper mode parser; to be shared with kike
static void static void
irc_handle_join (struct server *s, const struct irc_message *msg) irc_handle_join (struct server *s, const struct irc_message *msg)
{ {
@ -3932,6 +3930,170 @@ irc_handle_kick (struct server *s, const struct irc_message *msg)
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
struct mode_processor
{
// Inputs to set after initialization:
char **params; ///< Mode string parameters
struct server *s; ///< Who does the changes
struct channel *channel; ///< The channel we're modifying
// Internals:
bool adding; ///< Currently adding modes
char mode_char; ///< Currently processed mode char
};
static void
mode_processor_init (struct mode_processor *self)
{
memset (self, 0, sizeof *self);
}
static const char *
mode_processor_next_param (struct mode_processor *self)
{
if (!*self->params)
return NULL;
return *self->params++;
}
static void
mode_processor_do_user (struct mode_processor *self)
{
const char *nickname;
struct user *user;
if (!(nickname = mode_processor_next_param (self))
|| !(user = str_map_find (&self->s->irc_users, nickname)))
return;
// TODO: factor out, also use in unlink_user or whatever
struct channel_user *channel_user = NULL;
LIST_FOR_EACH (struct channel_user, iter, self->channel->users)
if (iter->user == user)
channel_user = iter;
if (!channel_user)
return;
char prefix = self->s->irc_chanuser_prefixes
[strchr (self->s->irc_chanuser_modes, self->mode_char)
- self->s->irc_chanuser_modes];
// XXX: shouldn't this rather be a "struct str"?
char *modes = channel_user->modes;
char *pos = strchr (modes, self->mode_char);
if (self->adding == !!pos)
return;
if (self->adding)
{
// FIXME: this doesn't give two fucks about the correct order
channel_user->modes = xstrdup_printf ("%s%c", modes, prefix);
free (modes);
}
else
memmove (pos, pos + 1, strlen (pos + 1));
}
static void
mode_processor_do_param_always (struct mode_processor *self)
{
const char *param = NULL;
if (!(param = mode_processor_next_param (self)))
return;
char key[2] = { self->mode_char, 0 };
if (self->adding)
str_map_set (&self->channel->param_modes, key, xstrdup (param));
else
str_map_set (&self->channel->param_modes, key, NULL);
}
static void
mode_processor_do_param_when_set (struct mode_processor *self)
{
const char *param = NULL;
if (self->adding && !(param = mode_processor_next_param (self)))
return;
char key[2] = { self->mode_char, 0 };
if (self->adding)
str_map_set (&self->channel->param_modes, key, xstrdup (param));
else
str_map_set (&self->channel->param_modes, key, NULL);
}
static void
mode_processor_do_param_never (struct mode_processor *self)
{
struct str *modes = &self->channel->no_param_modes;
const char *pos = strchr (modes->str, self->mode_char);
if (self->adding == !!pos)
return;
if (self->adding)
{
str_append_c (modes, self->mode_char);
// TODO: sort the modes
}
else
str_remove_slice (modes, pos - modes->str, 1);
}
static bool
mode_processor_step (struct mode_processor *self, char mode_char)
{
struct server *s = self->s;
self->mode_char = mode_char;
if (mode_char == '+') self->adding = true;
else if (mode_char == '-') self->adding = false;
else if (strchr (s->irc_chanuser_modes, mode_char))
mode_processor_do_user (self);
else if (strchr (s->irc_chanmodes_list, mode_char))
// Nothing to do here, really
(void) mode_processor_next_param (self);
else if (strchr (s->irc_chanmodes_param_always, mode_char))
mode_processor_do_param_always (self);
else if (strchr (s->irc_chanmodes_param_when_set, mode_char))
mode_processor_do_param_when_set (self);
else if (strchr (s->irc_chanmodes_param_never, mode_char))
mode_processor_do_param_never (self);
else
// It's not safe to continue, results could be undesired
return false;
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void
irc_handle_mode_channel
(struct server *s, struct channel *channel, char **params)
{
struct mode_processor p;
mode_processor_init (&p);
p.params = params;
p.s = s;
p.channel = channel;
const char *mode_string;
while ((mode_string = mode_processor_next_param (&p)))
{
mode_processor_step (&p, '+');
while (*mode_string)
if (!mode_processor_step (&p, *mode_string++))
break;
}
}
static void static void
irc_handle_mode (struct server *s, const struct irc_message *msg) irc_handle_mode (struct server *s, const struct irc_message *msg)
{ {
@ -3950,7 +4112,7 @@ irc_handle_mode (struct server *s, const struct irc_message *msg)
char *modes = irc_to_utf8 (s->ctx, reconstructed); char *modes = irc_to_utf8 (s->ctx, reconstructed);
free (reconstructed); free (reconstructed);
// TODO: parse the mode change and apply it // TODO: parse the mode change and apply it (our user & channel user modes)
if (irc_is_channel (s, context)) if (irc_is_channel (s, context))
{ {
@ -3959,6 +4121,9 @@ irc_handle_mode (struct server *s, const struct irc_message *msg)
hard_assert ((channel && buffer) || hard_assert ((channel && buffer) ||
(channel && !buffer) || (!channel && !buffer)); (channel && !buffer) || (!channel && !buffer));
if (channel)
irc_handle_mode_channel (s, channel, msg->params.vector + 1);
// FIXME: logging // FIXME: logging
if (buffer) if (buffer)
{ {