~rcr/rirc

489286229ea1e0e8e94809faf64de9cf71b6d9ca — Richard Robbins 11 months ago 69b0e64
cleanup mode string, mode error handling
M src/components/mode.c => src/components/mode.c +26 -35
@@ 12,10 12,10 @@ static int mode_isset(const struct mode*, int);
static void mode_set(struct mode*, int, int);
static uint32_t mode_bit(uint8_t);

static enum mode_err mode_cfg_chanmodes(struct mode_cfg*, const char*);
static enum mode_err mode_cfg_usermodes(struct mode_cfg*, const char*);
static enum mode_err mode_cfg_subtypes(struct mode_cfg*, const char*);
static enum mode_err mode_cfg_prefix(struct mode_cfg*, const char*);
static int mode_cfg_chanmodes(struct mode_cfg*, const char*);
static int mode_cfg_usermodes(struct mode_cfg*, const char*);
static int mode_cfg_subtypes(struct mode_cfg*, const char*);
static int mode_cfg_prefix(struct mode_cfg*, const char*);

static uint32_t
mode_bit(uint8_t c)


@@ 57,7 57,7 @@ mode_isset(const struct mode *m, int flag)
	return 0;
}

enum mode_err
int
mode_cfg(struct mode_cfg *cfg, const char *cfg_str, enum mode_cfg_type cfg_type)
{
	/* Initialize a mode_cfg to the RFC2812, RFC2811 defaults


@@ 123,26 123,26 @@ mode_cfg(struct mode_cfg *cfg, const char *cfg_str, enum mode_cfg_type cfg_type)
			fatal("mode configuration type unknown: %d", cfg_type);
	}

	return MODE_ERR_NONE;
	return 0;
}

enum mode_err
int
mode_chanmode_set(struct mode *m, const struct mode_cfg *cfg, int flag, int set)
{
	/* Set/unset chanmode flags */

	if (!mode_isset(&(cfg->chanmodes), flag))
		return MODE_ERR_INVALID_FLAG;
		return -1;

	if (mode_isset(&(cfg->CHANMODES.A), flag))
		return MODE_ERR_NONE;
		return 0;

	mode_set(m, flag, set);

	return MODE_ERR_NONE;
	return 0;
}

enum mode_err
int
mode_prfxmode_set(struct mode *m, const struct mode_cfg *cfg, int flag, int set)
{
	/* Set/unset prfxmode flag or prefix */


@@ 156,7 156,7 @@ mode_prfxmode_set(struct mode *m, const struct mode_cfg *cfg, int flag, int set)
	}

	if (!*f || !*t)
		return MODE_ERR_INVALID_FLAG;
		return -1;

	mode_set(m, *f, set);



@@ 174,24 174,24 @@ mode_prfxmode_set(struct mode *m, const struct mode_cfg *cfg, int flag, int set)

	m->prefix = *t;

	return MODE_ERR_NONE;
	return 0;
}

enum mode_err
int
mode_usermode_set(struct mode *m, const struct mode_cfg *cfg, int flag, int set)
{
	/* Set/unset usermode flags */

	if (!mode_isset(&(cfg->usermodes), flag))
		return MODE_ERR_INVALID_FLAG;
		return -1;

	mode_set(m, flag, set);

	return MODE_ERR_NONE;
	return 0;
}

const char*
mode_str(const struct mode *m, struct mode_str *m_str, enum mode_str_type type)
mode_str(const struct mode *m, struct mode_str *m_str)
{
	/* Write the mode bits to a mode string */



@@ 200,15 200,6 @@ mode_str(const struct mode *m, struct mode_str *m_str, enum mode_str_type type)
	uint32_t lower = m->lower;
	uint32_t upper = m->upper;

	switch (type) {
		case MODE_STR_CHANMODE:
		case MODE_STR_USERMODE:
		case MODE_STR_PRFXMODE:
			break;
		default:
			fatal("mode_str type unknown");
	}

	for (char c = 'a'; c <= 'z' && lower; c++, lower >>= 1)
		if (lower & 1)
			*str++ = c;


@@ 222,7 213,7 @@ mode_str(const struct mode *m, struct mode_str *m_str, enum mode_str_type type)
	return m_str->str;
}

static enum mode_err
static int
mode_cfg_chanmodes(struct mode_cfg *cfg, const char *str)
{
	/* Parse and configure chanmodes string */


@@ 244,10 235,10 @@ mode_cfg_chanmodes(struct mode_cfg *cfg, const char *str)
		mode_set(chanmodes, c, 1);
	}

	return MODE_ERR_NONE;
	return 0;
}

static enum mode_err
static int
mode_cfg_usermodes(struct mode_cfg *cfg, const char *str)
{
	/* Parse and configure usermodes string */


@@ 269,10 260,10 @@ mode_cfg_usermodes(struct mode_cfg *cfg, const char *str)
		mode_set(usermodes, c, 1);
	}

	return MODE_ERR_NONE;
	return 0;
}

static enum mode_err
static int
mode_cfg_subtypes(struct mode_cfg *cfg, const char *str)
{
	/* Parse and configure CHANMODE subtypes, e.g.:


@@ 322,7 313,7 @@ mode_cfg_subtypes(struct mode_cfg *cfg, const char *str)
		mode_set(setting, c, 1);
	}

	return MODE_ERR_NONE;
	return 0;

error:



@@ 331,10 322,10 @@ error:
	memset(&(cfg->CHANMODES.C), 0, sizeof(struct mode));
	memset(&(cfg->CHANMODES.D), 0, sizeof(struct mode));

	return MODE_ERR_INVALID_CONFIG;
	return -1;
}

static enum mode_err
static int
mode_cfg_prefix(struct mode_cfg *cfg, const char *str)
{
	/* Parse and configure PREFIX e.g.:


@@ 389,7 380,7 @@ mode_cfg_prefix(struct mode_cfg *cfg, const char *str)

	free(dup);

	return MODE_ERR_NONE;
	return 0;

error:


M src/components/mode.h => src/components/mode.h +11 -26
@@ 37,17 37,7 @@
#include <stdint.h>

/* [azAZ] */
#define MODE_STR_LEN 26 * 2

#define MODE_EMPTY (struct mode) { 0 }

enum mode_err
{
	MODE_ERR_INVALID_CONFIG = -3,
	MODE_ERR_INVALID_PREFIX = -2,
	MODE_ERR_INVALID_FLAG   = -1,
	MODE_ERR_NONE
};
#define MODE_STR_LEN ((26 * 2) + 1)

enum mode_type
{


@@ 66,13 56,6 @@ enum mode_cfg_type
	MODE_CFG_PREFIX,    /* Set numeric 005 PREFIX */
};

enum mode_str_type
{
	MODE_STR_CHANMODE,
	MODE_STR_USERMODE,
	MODE_STR_PRFXMODE,
};

struct mode
{
	char prefix;    /* Prefix character for chanmode, prfxmode */


@@ 93,21 76,23 @@ struct mode_cfg
	} CHANMODES;
	struct
	{
		char F[MODE_STR_LEN + 1]; /* prfxmode mapping `from` */
		char T[MODE_STR_LEN + 1]; /* prfxmode mapping `to`  */
		char F[MODE_STR_LEN]; /* prfxmode mapping `from` */
		char T[MODE_STR_LEN]; /* prfxmode mapping `to`  */
	} PREFIX;
};

struct mode_str
{
	char str[MODE_STR_LEN + 1];
	char str[MODE_STR_LEN];
};

const char* mode_str(const struct mode*, struct mode_str*, enum mode_str_type);
enum mode_err mode_cfg(struct mode_cfg*, const char*, enum mode_cfg_type);
enum mode_err mode_chanmode_set(struct mode*, const struct mode_cfg*, int, int);
enum mode_err mode_prfxmode_set(struct mode*, const struct mode_cfg*, int, int);
enum mode_err mode_usermode_set(struct mode*, const struct mode_cfg*, int, int);
const char* mode_str(const struct mode*, struct mode_str*);

enum mode_type mode_type(const struct mode_cfg*, int, int);

int mode_cfg(struct mode_cfg*, const char*, enum mode_cfg_type);
int mode_chanmode_set(struct mode*, const struct mode_cfg*, int, int);
int mode_prfxmode_set(struct mode*, const struct mode_cfg*, int, int);
int mode_usermode_set(struct mode*, const struct mode_cfg*, int, int);

#endif

M src/components/server.c => src/components/server.c +5 -5
@@ 281,14 281,14 @@ server_set_004(struct server *s, char *str)
		server_error(s, "invalid numeric 004: chan_modes is null");

	if (user_modes) {
		if (mode_cfg(&(s->mode_cfg), user_modes, MODE_CFG_USERMODES) == MODE_ERR_NONE)
		if (!mode_cfg(&(s->mode_cfg), user_modes, MODE_CFG_USERMODES))
			debug("Setting numeric 004 user_modes: %s", user_modes);
		else
			server_error(s, "invalid numeric 004 user_modes: %s", user_modes);
	}

	if (chan_modes) {
		if (mode_cfg(&(s->mode_cfg), chan_modes, MODE_CFG_CHANMODES) == MODE_ERR_NONE)
		if (!mode_cfg(&(s->mode_cfg), chan_modes, MODE_CFG_CHANMODES))
			debug("Setting numeric 004 chan_modes: %s", chan_modes);
		else
			server_error(s, "invalid numeric 004 chan_modes: %s", chan_modes);


@@ 445,19 445,19 @@ server_set_CASEMAPPING(struct server *s, char *val)
		return 0;
	}

	return 1;
	return -1;
}

static int
server_set_CHANMODES(struct server *s, char *val)
{
	return mode_cfg(&(s->mode_cfg), val, MODE_CFG_SUBTYPES) != MODE_ERR_NONE;
	return mode_cfg(&(s->mode_cfg), val, MODE_CFG_SUBTYPES);
}

static int
server_set_PREFIX(struct server *s, char *val)
{
	return mode_cfg(&(s->mode_cfg), val, MODE_CFG_PREFIX) != MODE_ERR_NONE;
	return mode_cfg(&(s->mode_cfg), val, MODE_CFG_PREFIX);
}

void

M src/components/server.h => src/components/server.h +1 -1
@@ 30,8 30,8 @@ struct server
	struct ircv3_caps ircv3_caps;
	struct ircv3_sasl ircv3_sasl;
	struct mode usermodes;
	struct mode_str mode_str;
	struct mode_cfg mode_cfg;
	struct mode_str mode_str;
	struct server *next;
	struct server *prev;
	unsigned ping;

M src/handlers/irc_recv.c => src/handlers/irc_recv.c +19 -25
@@ 563,9 563,9 @@ irc_numeric_353(struct server *s, struct irc_message *m)

	while ((prefix = nick = irc_strsep(&nicks))) {

		struct mode m = MODE_EMPTY;
		struct mode m = {0};

		while (mode_prfxmode_set(&m, &(s->mode_cfg), *nick, 1) == MODE_ERR_NONE)
		while (!mode_prfxmode_set(&m, &(s->mode_cfg), *nick, 1))
			nick++;

		if (*nick == 0)


@@ 764,7 764,7 @@ recv_join(struct server *s, struct irc_message *m)
	if ((c = channel_list_get(&s->clist, chan, s->casemapping)) == NULL)
		failf(s, "JOIN: channel '%s' not found", chan);

	if (user_list_add(&(c->users), s->casemapping, m->from, MODE_EMPTY) == USER_ERR_DUPLICATE)
	if (user_list_add(&(c->users), s->casemapping, m->from, (struct mode){0}) == USER_ERR_DUPLICATE)
		failf(s, "JOIN: user '%s' already on channel '%s'", m->from, chan);

	if (!threshold_join || threshold_join > c->users.count) {


@@ 894,7 894,6 @@ recv_mode_chanmodes(struct irc_message *m, const struct mode_cfg *cfg, struct se
	char flag;
	char *modestring;
	char *modearg;
	enum mode_err mode_err;
	struct mode *chanmodes = &(c->chanmodes);
	struct user *user;



@@ 905,7 904,6 @@ recv_mode_chanmodes(struct irc_message *m, const struct mode_cfg *cfg, struct se

	do {
		int set = -1;
		mode_err = MODE_ERR_NONE;

		while ((flag = *modestring++)) {



@@ 931,9 929,9 @@ recv_mode_chanmodes(struct irc_message *m, const struct mode_cfg *cfg, struct se
				/* Doesn't consume an argument */
				case MODE_FLAG_CHANMODE:

					mode_err = mode_chanmode_set(chanmodes, cfg, flag, set);

					if (mode_err == MODE_ERR_NONE) {
					if (mode_chanmode_set(chanmodes, cfg, flag, set)) {
						server_error(s, "MODE: invalid flag '%c'", flag);
					} else {
						newlinef(c, 0, FROM_INFO, "%s%s%s mode: %c%c",
								(m->from ? m->from : ""),
								(m->from ? " set " : ""),


@@ 958,9 956,9 @@ recv_mode_chanmodes(struct irc_message *m, const struct mode_cfg *cfg, struct se
							channel_key_del(c);
					}

					mode_err = mode_chanmode_set(chanmodes, cfg, flag, set);

					if (mode_err == MODE_ERR_NONE) {
					if (mode_chanmode_set(chanmodes, cfg, flag, set)) {
						server_error(s, "MODE: invalid flag '%c'", flag);
					} else {
						newlinef(c, 0, FROM_INFO, "%s%s%s mode: %c%c %s",
								(m->from ? m->from : ""),
								(m->from ? " set " : ""),


@@ 984,9 982,9 @@ recv_mode_chanmodes(struct irc_message *m, const struct mode_cfg *cfg, struct se
						continue;
					}

					mode_prfxmode_set(&(user->prfxmodes), cfg, flag, set);

					if (mode_err == MODE_ERR_NONE) {
					if (mode_prfxmode_set(&(user->prfxmodes), cfg, flag, set)) {
						server_error(s, "MODE: invalid flag '%c'", flag);
					} else {
						newlinef(c, 0, FROM_INFO, "%s%suser %s mode: %c%c",
								(m->from ? m->from : ""),
								(m->from ? " set " : ""),


@@ 1007,7 1005,7 @@ recv_mode_chanmodes(struct irc_message *m, const struct mode_cfg *cfg, struct se
		}
	} while (irc_message_param(m, &modestring));

	mode_str(&(c->chanmodes), &(c->chanmodes_str), MODE_STR_CHANMODE);
	mode_str(&(c->chanmodes), &(c->chanmodes_str));
	draw(DRAW_STATUS);

	return 0;


@@ 1016,15 1014,13 @@ recv_mode_chanmodes(struct irc_message *m, const struct mode_cfg *cfg, struct se
static int
recv_mode_usermodes(struct irc_message *m, const struct mode_cfg *cfg, struct server *s)
{
	char flag;
	char *modestring;
	enum mode_err mode_err;
	struct mode *usermodes = &(s->usermodes);

	if (!irc_message_param(m, &modestring))
		failf(s, "MODE: modestring is null");

	do {
		char flag;
		int set = -1;

		while ((flag = *modestring++)) {


@@ 1044,21 1040,19 @@ recv_mode_usermodes(struct irc_message *m, const struct mode_cfg *cfg, struct se
				continue;
			}

			mode_err = mode_usermode_set(usermodes, cfg, flag, set);

			if (mode_err == MODE_ERR_NONE)
			if (mode_usermode_set(&(s->usermodes), cfg, flag, set)) {
				server_error(s, "MODE: invalid flag '%c'", flag);
			} else {
				server_info(s, "%s%smode: %c%c",
						(m->from ? m->from : ""),
						(m->from ? " set " : ""),
						(set ? '+' : '-'),
						flag);

			else if (mode_err == MODE_ERR_INVALID_FLAG)
				server_error(s, "MODE: invalid flag '%c'", flag);
			}
		}
	} while (irc_message_param(m, &modestring));

	mode_str(usermodes, &(s->mode_str), MODE_STR_USERMODE);
	mode_str(&(s->usermodes), &(s->mode_str));
	draw(DRAW_STATUS);

	return 0;

M test/components/mode.c => test/components/mode.c +89 -92
@@ 25,29 25,26 @@ test_mode_str(void)
{
	/* Test setting mode string */

	struct mode m = MODE_EMPTY;
	struct mode m = {0};
	struct mode_str str;

	/* mode_str type unknown */
	assert_fatal(mode_str(&m, &str, -1));

	/* Test no mode */
	assert_strcmp(mode_str(&m, &str, MODE_STR_USERMODE), "");
	assert_strcmp(mode_str(&m, &str), "");

	m.lower = UINT32_MAX;
	m.upper = 0;

	assert_strcmp(mode_str(&m, &str, MODE_STR_USERMODE), ALL_LOWERS);
	assert_strcmp(mode_str(&m, &str), ALL_LOWERS);

	m.lower = 0;
	m.upper = UINT32_MAX;

	assert_strcmp(mode_str(&m, &str, MODE_STR_USERMODE), ALL_UPPERS);
	assert_strcmp(mode_str(&m, &str), ALL_UPPERS);

	m.lower = UINT32_MAX;
	m.upper = UINT32_MAX;

	assert_strcmp(mode_str(&m, &str, MODE_STR_USERMODE), ALL_LOWERS ALL_UPPERS);
	assert_strcmp(mode_str(&m, &str), ALL_LOWERS ALL_UPPERS);
}

static void


@@ 55,7 52,7 @@ test_mode_chanmode_set(void)
{
	/* Test setting/unsetting chanmode flags */

	struct mode m = MODE_EMPTY;
	struct mode m = {0};
	struct mode_cfg cfg;
	struct mode_str str;



@@ 63,32 60,32 @@ test_mode_chanmode_set(void)
	mode_cfg_subtypes(&cfg, "abc,def,ghi,jsp");

	/* Test setting/unsetting invalid chanmode flag */
	assert_eq(mode_chanmode_set(&m, &cfg, 'z', 1), MODE_ERR_INVALID_FLAG);
	assert_strcmp(mode_str(&m, &str, MODE_STR_CHANMODE), "");
	assert_eq(mode_chanmode_set(&m, &cfg, 'z', 1), -1);
	assert_strcmp(mode_str(&m, &str), "");

	assert_eq(mode_chanmode_set(&m, &cfg, 'z', 0), MODE_ERR_INVALID_FLAG);
	assert_strcmp(mode_str(&m, &str, MODE_STR_CHANMODE), "");
	assert_eq(mode_chanmode_set(&m, &cfg, 'z', 0), -1);
	assert_strcmp(mode_str(&m, &str), "");

	/* Test valid CHANMODE subtype A doesn't set flag */
	assert_eq(mode_chanmode_set(&m, &cfg, 'a', 1), MODE_ERR_NONE);
	assert_strcmp(mode_str(&m, &str, MODE_STR_CHANMODE), "");
	assert_eq(mode_chanmode_set(&m, &cfg, 'a', 1), 0);
	assert_strcmp(mode_str(&m, &str), "");

	/* Test valid CHANMODE subtypes B,C,D set flags */
	assert_eq(mode_chanmode_set(&m, &cfg, 'd', 1), MODE_ERR_NONE);
	assert_strcmp(mode_str(&m, &str, MODE_STR_CHANMODE), "d");
	assert_eq(mode_chanmode_set(&m, &cfg, 'd', 1), 0);
	assert_strcmp(mode_str(&m, &str), "d");

	assert_eq(mode_chanmode_set(&m, &cfg, 'e', 1), MODE_ERR_NONE);
	assert_strcmp(mode_str(&m, &str, MODE_STR_CHANMODE), "de");
	assert_eq(mode_chanmode_set(&m, &cfg, 'e', 1), 0);
	assert_strcmp(mode_str(&m, &str), "de");

	assert_eq(mode_chanmode_set(&m, &cfg, 'j', 1), MODE_ERR_NONE);
	assert_strcmp(mode_str(&m, &str, MODE_STR_CHANMODE), "dej");
	assert_eq(mode_chanmode_set(&m, &cfg, 'j', 1), 0);
	assert_strcmp(mode_str(&m, &str), "dej");

	/* test unsetting flags */
	assert_eq(mode_chanmode_set(&m, &cfg, 's', 0), MODE_ERR_NONE);
	assert_eq(mode_chanmode_set(&m, &cfg, 'j', 0), MODE_ERR_NONE);
	assert_eq(mode_chanmode_set(&m, &cfg, 'e', 0), MODE_ERR_NONE);
	assert_eq(mode_chanmode_set(&m, &cfg, 'd', 0), MODE_ERR_NONE);
	assert_strcmp(mode_str(&m, &str, MODE_STR_CHANMODE), "");
	assert_eq(mode_chanmode_set(&m, &cfg, 's', 0), 0);
	assert_eq(mode_chanmode_set(&m, &cfg, 'j', 0), 0);
	assert_eq(mode_chanmode_set(&m, &cfg, 'e', 0), 0);
	assert_eq(mode_chanmode_set(&m, &cfg, 'd', 0), 0);
	assert_strcmp(mode_str(&m, &str), "");
}

static void


@@ 96,7 93,7 @@ test_mode_prfxmode_set(void)
{
	/* Test setting/unsetting prfxmode flag and prefix */

	struct mode m = MODE_EMPTY;
	struct mode m = {0};
	struct mode_cfg cfg = {
		.PREFIX = {
			.F = "abc",


@@ 108,40 105,40 @@ test_mode_prfxmode_set(void)
	mode_cfg_chanmodes(&cfg, "abc");

	/* Test setting/unsetting invalid prfxmode flag */
	assert_eq(mode_prfxmode_set(&m, &cfg, 'd', 1), MODE_ERR_INVALID_FLAG);
	assert_eq(mode_prfxmode_set(&m, &cfg, 'd', 1), -1);
	assert_eq(m.prefix, 0);
	assert_eq(mode_prfxmode_set(&m, &cfg, 'd', 0), MODE_ERR_INVALID_FLAG);
	assert_eq(mode_prfxmode_set(&m, &cfg, 'd', 0), -1);
	assert_eq(m.prefix, 0);

	/* Test setting/unsetting invalid prfxmode prefix */
	assert_eq(mode_prfxmode_set(&m, &cfg, '4', 1), MODE_ERR_INVALID_FLAG);
	assert_eq(mode_prfxmode_set(&m, &cfg, '4', 1), -1);
	assert_eq(m.prefix, 0);
	assert_eq(mode_prfxmode_set(&m, &cfg, '4', 0), MODE_ERR_INVALID_FLAG);
	assert_eq(mode_prfxmode_set(&m, &cfg, '4', 0), -1);
	assert_eq(m.prefix, 0);

	/* Test setting valid flags respects PREFIX precedence */
	assert_eq(mode_prfxmode_set(&m, &cfg, 'b', 1), MODE_ERR_NONE);
	assert_eq(mode_prfxmode_set(&m, &cfg, 'b', 1), 0);
	assert_eq(m.prefix, '2');
	assert_eq(mode_prfxmode_set(&m, &cfg, 'c', 1), MODE_ERR_NONE);
	assert_eq(mode_prfxmode_set(&m, &cfg, 'c', 1), 0);
	assert_eq(m.prefix, '2');
	assert_eq(mode_prfxmode_set(&m, &cfg, 'a', 1), MODE_ERR_NONE);
	assert_eq(mode_prfxmode_set(&m, &cfg, 'a', 1), 0);
	assert_eq(m.prefix, '1');

	/* Test unsetting valid flags respects PREFIX precedence */
	assert_eq(mode_prfxmode_set(&m, &cfg, 'b', 0), MODE_ERR_NONE);
	assert_eq(mode_prfxmode_set(&m, &cfg, 'b', 0), 0);
	assert_eq(m.prefix, '1');
	assert_eq(mode_prfxmode_set(&m, &cfg, 'a', 0), MODE_ERR_NONE);
	assert_eq(mode_prfxmode_set(&m, &cfg, 'a', 0), 0);
	assert_eq(m.prefix, '3');
	assert_eq(mode_prfxmode_set(&m, &cfg, 'c', 0), MODE_ERR_NONE);
	assert_eq(mode_prfxmode_set(&m, &cfg, 'c', 0), 0);
	assert_eq(m.prefix, 0);

	/* Test setting valid prefixes */
	assert_eq(mode_prfxmode_set(&m, &cfg, '2', 1), MODE_ERR_NONE);
	assert_eq(mode_prfxmode_set(&m, &cfg, '2', 1), 0);
	assert_eq(m.prefix, '2');
	assert_eq(mode_prfxmode_set(&m, &cfg, '3', 1), MODE_ERR_NONE);
	assert_eq(mode_prfxmode_set(&m, &cfg, '3', 1), 0);
	assert_eq(m.prefix, '2');

	assert_strcmp(mode_str(&m, &str, MODE_STR_PRFXMODE), "bc");
	assert_strcmp(mode_str(&m, &str), "bc");
}

static void


@@ 149,35 146,35 @@ test_mode_usermode_set(void)
{
	/* Test setting/unsetting usermode flag and mode string */

	struct mode m = MODE_EMPTY;
	struct mode m = {0};
	struct mode_cfg cfg;
	struct mode_str str;

	mode_cfg_usermodes(&cfg, "azAZ");

	/* Test setting invalid usermode flag */
	assert_eq(mode_usermode_set(&m, &cfg, 'b', 1), MODE_ERR_INVALID_FLAG);
	assert_eq(mode_usermode_set(&m, &cfg, 'b', 1), -1);

	/* Test setting valid flags */
	assert_eq(mode_usermode_set(&m, &cfg, 'a', 1), MODE_ERR_NONE);
	assert_eq(mode_usermode_set(&m, &cfg, 'Z', 1), MODE_ERR_NONE);
	assert_strcmp(mode_str(&m, &str, MODE_STR_USERMODE), "aZ");
	assert_eq(mode_usermode_set(&m, &cfg, 'a', 1), 0);
	assert_eq(mode_usermode_set(&m, &cfg, 'Z', 1), 0);
	assert_strcmp(mode_str(&m, &str), "aZ");

	assert_eq(mode_usermode_set(&m, &cfg, 'z', 1), MODE_ERR_NONE);
	assert_eq(mode_usermode_set(&m, &cfg, 'A', 1), MODE_ERR_NONE);
	assert_strcmp(mode_str(&m, &str, MODE_STR_USERMODE), "azAZ");
	assert_eq(mode_usermode_set(&m, &cfg, 'z', 1), 0);
	assert_eq(mode_usermode_set(&m, &cfg, 'A', 1), 0);
	assert_strcmp(mode_str(&m, &str), "azAZ");

	/* Test unsetting invalid usermode flag */
	assert_eq(mode_usermode_set(&m, &cfg, 'c', 0), MODE_ERR_INVALID_FLAG);
	assert_eq(mode_usermode_set(&m, &cfg, 'c', 0), -1);

	/* Test unsetting valid flags */
	assert_eq(mode_usermode_set(&m, &cfg, 'z', 0), MODE_ERR_NONE);
	assert_eq(mode_usermode_set(&m, &cfg, 'Z', 0), MODE_ERR_NONE);
	assert_strcmp(mode_str(&m, &str, MODE_STR_USERMODE), "aA");
	assert_eq(mode_usermode_set(&m, &cfg, 'z', 0), 0);
	assert_eq(mode_usermode_set(&m, &cfg, 'Z', 0), 0);
	assert_strcmp(mode_str(&m, &str), "aA");

	assert_eq(mode_usermode_set(&m, &cfg, 'a', 0), MODE_ERR_NONE);
	assert_eq(mode_usermode_set(&m, &cfg, 'A', 0), MODE_ERR_NONE);
	assert_strcmp(mode_str(&m, &str, MODE_STR_USERMODE), "");
	assert_eq(mode_usermode_set(&m, &cfg, 'a', 0), 0);
	assert_eq(mode_usermode_set(&m, &cfg, 'A', 0), 0);
	assert_strcmp(mode_str(&m, &str), "");
}

static void


@@ 189,20 186,20 @@ test_mode_cfg_usermodes(void)
	struct mode_str str;

	/* Test empty string */
	assert_eq(mode_cfg_usermodes(&cfg, ""), MODE_ERR_NONE);
	assert_strcmp(mode_str(&(cfg.usermodes), &str, MODE_STR_USERMODE), "");
	assert_eq(mode_cfg_usermodes(&cfg, ""), 0);
	assert_strcmp(mode_str(&(cfg.usermodes), &str), "");

	/* Test invalid flags */
	assert_eq(mode_cfg_usermodes(&cfg, "$abc1!xyz."), MODE_ERR_NONE);
	assert_strcmp(mode_str(&(cfg.usermodes), &str, MODE_STR_USERMODE), "abcxyz");
	assert_eq(mode_cfg_usermodes(&cfg, "$abc1!xyz."), 0);
	assert_strcmp(mode_str(&(cfg.usermodes), &str), "abcxyz");

	/* Test duplicate flags */
	assert_eq(mode_cfg_usermodes(&cfg, "aaabbc"), MODE_ERR_NONE);
	assert_strcmp(mode_str(&(cfg.usermodes), &str, MODE_STR_USERMODE), "abc");
	assert_eq(mode_cfg_usermodes(&cfg, "aaabbc"), 0);
	assert_strcmp(mode_str(&(cfg.usermodes), &str), "abc");

	/* Test valid string */
	assert_eq(mode_cfg_usermodes(&cfg, ALL_LOWERS ALL_UPPERS), MODE_ERR_NONE);
	assert_strcmp(mode_str(&(cfg.usermodes), &str, MODE_STR_USERMODE), ALL_LOWERS ALL_UPPERS);
	assert_eq(mode_cfg_usermodes(&cfg, ALL_LOWERS ALL_UPPERS), 0);
	assert_strcmp(mode_str(&(cfg.usermodes), &str), ALL_LOWERS ALL_UPPERS);
}

static void


@@ 214,20 211,20 @@ test_mode_cfg_chanmodes(void)
	struct mode_str str;

	/* Test empty string */
	assert_eq(mode_cfg_chanmodes(&cfg, ""), MODE_ERR_NONE);
	assert_strcmp(mode_str(&(cfg.chanmodes), &str, MODE_STR_USERMODE), "");
	assert_eq(mode_cfg_chanmodes(&cfg, ""), 0);
	assert_strcmp(mode_str(&(cfg.chanmodes), &str), "");

	/* Test invalid flags */
	assert_eq(mode_cfg_chanmodes(&cfg, "$abc1!xyz."), MODE_ERR_NONE);
	assert_strcmp(mode_str(&(cfg.chanmodes), &str, MODE_STR_USERMODE), "abcxyz");
	assert_eq(mode_cfg_chanmodes(&cfg, "$abc1!xyz."), 0);
	assert_strcmp(mode_str(&(cfg.chanmodes), &str), "abcxyz");

	/* Test duplicate flags */
	assert_eq(mode_cfg_chanmodes(&cfg, "aaabbc"), MODE_ERR_NONE);
	assert_strcmp(mode_str(&(cfg.chanmodes), &str, MODE_STR_USERMODE), "abc");
	assert_eq(mode_cfg_chanmodes(&cfg, "aaabbc"), 0);
	assert_strcmp(mode_str(&(cfg.chanmodes), &str), "abc");

	/* Test valid string */
	assert_eq(mode_cfg_chanmodes(&cfg, ALL_LOWERS ALL_UPPERS), MODE_ERR_NONE);
	assert_strcmp(mode_str(&(cfg.chanmodes), &str, MODE_STR_USERMODE), ALL_LOWERS ALL_UPPERS);
	assert_eq(mode_cfg_chanmodes(&cfg, ALL_LOWERS ALL_UPPERS), 0);
	assert_strcmp(mode_str(&(cfg.chanmodes), &str), ALL_LOWERS ALL_UPPERS);
}

static void


@@ 239,25 236,25 @@ test_mode_cfg_subtypes(void)
	struct mode_str str;

#define CHECK(_A, _B, _C, _D) \
	assert_strcmp(mode_str(&(cfg.CHANMODES.A), &str, MODE_STR_USERMODE), (_A)); \
	assert_strcmp(mode_str(&(cfg.CHANMODES.B), &str, MODE_STR_USERMODE), (_B)); \
	assert_strcmp(mode_str(&(cfg.CHANMODES.C), &str, MODE_STR_USERMODE), (_C)); \
	assert_strcmp(mode_str(&(cfg.CHANMODES.D), &str, MODE_STR_USERMODE), (_D));
	assert_strcmp(mode_str(&(cfg.CHANMODES.A), &str), (_A)); \
	assert_strcmp(mode_str(&(cfg.CHANMODES.B), &str), (_B)); \
	assert_strcmp(mode_str(&(cfg.CHANMODES.C), &str), (_C)); \
	assert_strcmp(mode_str(&(cfg.CHANMODES.D), &str), (_D));

	/* Test empty string */
	assert_eq(mode_cfg_subtypes(&cfg, ""), MODE_ERR_NONE);
	assert_eq(mode_cfg_subtypes(&cfg, ""), 0);
	CHECK("", "", "", "");

	/* Test missing commas */
	assert_eq(mode_cfg_subtypes(&cfg, "abc,def"), MODE_ERR_NONE);
	assert_eq(mode_cfg_subtypes(&cfg, "abc,def"), 0);
	CHECK("abc", "def", "", "");

	/* Test extra commas */
	assert_eq(mode_cfg_subtypes(&cfg, "abc,def,,xyz,,,abc"), MODE_ERR_INVALID_CONFIG);
	assert_eq(mode_cfg_subtypes(&cfg, "abc,def,,xyz,,,abc"), -1);
	CHECK("", "", "", "");

	/* Test invalid flags */
	assert_eq(mode_cfg_subtypes(&cfg, "!!abc,d123e,fg!-@,^&"), MODE_ERR_INVALID_CONFIG);
	assert_eq(mode_cfg_subtypes(&cfg, "!!abc,d123e,fg!-@,^&"), -1);
	CHECK("", "", "", "");

	const char *all_flags =


@@ 267,7 264,7 @@ test_mode_cfg_subtypes(void)
		ALL_LOWERS ALL_UPPERS;

	/* Test valid string */
	assert_eq(mode_cfg_subtypes(&cfg, all_flags), MODE_ERR_NONE);
	assert_eq(mode_cfg_subtypes(&cfg, all_flags), 0);
	CHECK(ALL_LOWERS ALL_UPPERS,
	      ALL_LOWERS ALL_UPPERS,
	      ALL_LOWERS ALL_UPPERS,


@@ 288,43 285,43 @@ test_mode_cfg_prefix(void)
	assert_strcmp(cfg.PREFIX.T, (_T));

	/* Test empty string */
	assert_eq(mode_cfg_prefix(&cfg, ""), MODE_ERR_INVALID_CONFIG);
	assert_eq(mode_cfg_prefix(&cfg, ""), -1);
	CHECK("", "");

	/* Test invalid formats */
	assert_eq(mode_cfg_prefix(&cfg, "abc123"), MODE_ERR_INVALID_CONFIG);
	assert_eq(mode_cfg_prefix(&cfg, "abc123"), -1);
	CHECK("", "");

	assert_eq(mode_cfg_prefix(&cfg, "abc)123"), MODE_ERR_INVALID_CONFIG);
	assert_eq(mode_cfg_prefix(&cfg, "abc)123"), -1);
	CHECK("", "");

	assert_eq(mode_cfg_prefix(&cfg, "(abc123"), MODE_ERR_INVALID_CONFIG);
	assert_eq(mode_cfg_prefix(&cfg, "(abc123"), -1);
	CHECK("", "");

	assert_eq(mode_cfg_prefix(&cfg, ")(abc"), MODE_ERR_INVALID_CONFIG);
	assert_eq(mode_cfg_prefix(&cfg, ")(abc"), -1);
	CHECK("", "");

	/* Test unequal lengths */
	assert_eq(mode_cfg_prefix(&cfg, "(abc)12"), MODE_ERR_INVALID_CONFIG);
	assert_eq(mode_cfg_prefix(&cfg, "(abc)12"), -1);
	CHECK("", "");

	assert_eq(mode_cfg_prefix(&cfg, "(ab)123"), MODE_ERR_INVALID_CONFIG);
	assert_eq(mode_cfg_prefix(&cfg, "(ab)123"), -1);
	CHECK("", "");

	/* Test invalid flags */
	assert_eq(mode_cfg_prefix(&cfg, "(ab1)12"), MODE_ERR_INVALID_CONFIG);
	assert_eq(mode_cfg_prefix(&cfg, "(ab1)12"), -1);
	CHECK("", "");

	/* Test unprintable prefix */
	assert_eq(mode_cfg_prefix(&cfg, "(abc)1" "\x01" "3"), MODE_ERR_INVALID_CONFIG);
	assert_eq(mode_cfg_prefix(&cfg, "(abc)1" "\x01" "3"), -1);
	CHECK("", "");

	/* Test duplicates flags */
	assert_eq(mode_cfg_prefix(&cfg, "(aabc)1234"), MODE_ERR_INVALID_CONFIG);
	assert_eq(mode_cfg_prefix(&cfg, "(aabc)1234"), -1);
	CHECK("", "");

	/* Test valid string */
	assert_eq(mode_cfg_prefix(&cfg, "(abc)123"), MODE_ERR_NONE);
	assert_eq(mode_cfg_prefix(&cfg, "(abc)123"), 0);
	CHECK("abc", "123");

#undef CHECK


@@ 344,7 341,7 @@ test_mode_type(void)
	config_errs -= mode_cfg(&cfg, "b,c,d,e", MODE_CFG_SUBTYPES);
	config_errs -= mode_cfg(&cfg, "(f)@",    MODE_CFG_PREFIX);

	if (config_errs != MODE_ERR_NONE)
	if (config_errs != 0)
		test_abort("Configuration error");

	/* Test invalid flag */

M test/components/user.c => test/components/user.c +11 -11
@@ 13,15 13,15 @@ test_user_list(void)
	memset(&ulist, 0, sizeof(ulist));

	/* Test adding users to list */
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "aaa", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "bbb", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "ccc", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "aaa", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "bbb", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "ccc", (struct mode){0}), USER_ERR_NONE);

	if (ulist.count != 3)
		test_abort("Failed to add users to list");

	/* Test adding duplicates */
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "aaa", MODE_EMPTY), USER_ERR_DUPLICATE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "aaa", (struct mode){0}), USER_ERR_DUPLICATE);

	/* Test retrieving by name, failure */
	assert_ptr_null(user_list_get(&ulist, CASEMAPPING_RFC1459, "a", 0));


@@ 101,11 101,11 @@ test_user_list_casemapping(void)

	memset(&ulist, 0, sizeof(ulist));

	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "aaa", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "AaA", MODE_EMPTY), USER_ERR_DUPLICATE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "{}^", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "[}~", MODE_EMPTY), USER_ERR_DUPLICATE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "zzz", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "aaa", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "AaA", (struct mode){0}), USER_ERR_DUPLICATE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "{}^", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "[}~", (struct mode){0}), USER_ERR_DUPLICATE);
	assert_eq(user_list_add(&ulist, CASEMAPPING_RFC1459, "zzz", (struct mode){0}), USER_ERR_NONE);

	assert_eq(ulist.count, 3);



@@ 150,14 150,14 @@ test_user_list_free(void)
	};

	for (p = users; *p; p++) {
		if (user_list_add(&ulist, CASEMAPPING_RFC1459, *p, MODE_EMPTY) != USER_ERR_NONE)
		if (user_list_add(&ulist, CASEMAPPING_RFC1459, *p, (struct mode){0}) != USER_ERR_NONE)
			test_failf("Failed to add user to list: %s", *p);
	}

	user_list_free(&ulist);

	for (p = users; *p; p++) {
		if (user_list_add(&ulist, CASEMAPPING_RFC1459, *p, MODE_EMPTY) != USER_ERR_NONE)
		if (user_list_add(&ulist, CASEMAPPING_RFC1459, *p, (struct mode){0}) != USER_ERR_NONE)
			test_failf("Failed to remove user from list: %s", *p);
	}


M test/handlers/irc_recv.c => test/handlers/irc_recv.c +31 -31
@@ 434,8 434,8 @@ test_recv_join(void)
	/* :nick!user@host JOIN <channel>
	 * :nick!user@host JOIN <channel> <account> :<realname> */

	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c2->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c2->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);

	threshold_join = 0;



@@ 496,9 496,9 @@ test_recv_kick(void)
{
	/* :nick!user@host KICK <channel> <user> [:message] */

	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick3", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick3", (struct mode){0}), USER_ERR_NONE);

	CHECK_RECV("KICK #c1", 1, 1, 0);
	assert_strcmp(mock_chan[0], "host");


@@ 571,10 571,10 @@ test_recv_nick(void)
{
	/* :nick!user@host NICK <nick> */

	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick2", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick2", (struct mode){0}), USER_ERR_NONE);

	CHECK_RECV("NICK new_nick", 1, 1, 0);
	assert_strcmp(mock_chan[0], "host");


@@ 606,7 606,7 @@ test_recv_nick(void)
	assert_strcmp(mock_line[0], "Your nick is now 'new_me'");

	/* user can change own nick case */
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "abc{}|^", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "abc{}|^", (struct mode){0}), USER_ERR_NONE);

	CHECK_RECV(":abc{}|^!user@host NICK AbC{]|~", 0, 1, 0);
	assert_strcmp(mock_chan[0], "#c1");


@@ 662,11 662,11 @@ test_recv_part(void)
{
	/* :nick!user@host PART <channel> [:message] */

	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick3", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick4", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick5", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick3", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick4", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick5", (struct mode){0}), USER_ERR_NONE);

	threshold_part = 0;



@@ 760,14 760,14 @@ test_recv_quit(void)
{
	/* :nick!user@host QUIT [:message] */

	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick3", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick4", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick5", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick3", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick4", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick5", (struct mode){0}), USER_ERR_NONE);

	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick2", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick2", (struct mode){0}), USER_ERR_NONE);

	threshold_quit = 0;



@@ 860,9 860,9 @@ test_recv_ircv3_account(void)
{
	/* :nick!user@host ACCOUNT <account> */

	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);

	threshold_account = 0;



@@ 901,9 901,9 @@ test_recv_ircv3_away(void)
{
	/* :nick!user@host AWAY [:message] */

	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);

	threshold_away = 0;



@@ 939,9 939,9 @@ test_recv_ircv3_chghost(void)
{
	/* :nick!user@host CHGHOST new_user new_host */

	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick1", MODE_EMPTY), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c1->users), CASEMAPPING_RFC1459, "nick2", (struct mode){0}), USER_ERR_NONE);
	assert_eq(user_list_add(&(c3->users), CASEMAPPING_RFC1459, "nick1", (struct mode){0}), USER_ERR_NONE);

	threshold_chghost = 0;