~rcr/rirc

e6d3db5de630bf9f20c462f3e91503df21f188fa — Richard Robbins a month ago dec8769
cleanup mode string handling
M src/components/channel.c => src/components/channel.c +2 -2
@@ 16,7 16,6 @@ channel(const char *name, enum channel_type type)
	if ((c = calloc(1, sizeof(*c) + len + 1)) == NULL)
		fatal("calloc: %s", strerror(errno));

	c->chanmodes_str.type = MODE_STR_CHANMODE;
	c->name_len = len;
	c->name = memcpy(c->_, name, len + 1);
	c->type = type;


@@ 119,7 118,8 @@ channel_part(struct channel *c)
void
channel_reset(struct channel *c)
{
	mode_reset(&(c->chanmodes), &(c->chanmodes_str));
	memset(&(c->chanmodes), 0, sizeof(c->chanmodes));
	memset(&(c->chanmodes_str), 0, sizeof(c->chanmodes_str));
	user_list_free(&(c->users));
	c->joined = 0;
}

M src/components/mode.c => src/components/mode.c +17 -41
@@ 191,7 191,7 @@ mode_usermode_set(struct mode *m, const struct mode_cfg *cfg, int flag, int set)
}

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



@@ 200,13 200,11 @@ mode_str(const struct mode *m, struct mode_str *m_str)
	uint32_t lower = m->lower;
	uint32_t upper = m->upper;

	switch (m_str->type) {
	switch (type) {
		case MODE_STR_CHANMODE:
		case MODE_STR_USERMODE:
		case MODE_STR_PRFXMODE:
			break;
		case MODE_STR_UNSET:
			fatal("mode_str type not set");
		default:
			fatal("mode_str type unknown");
	}


@@ 224,22 222,6 @@ mode_str(const struct mode *m, struct mode_str *m_str)
	return m_str->str;
}

void
mode_reset(struct mode *m, struct mode_str *s)
{
	/* Set mode and mode_str to initial state */

	if (!m || !s)
		fatal("mode or mode_str is null");

	enum mode_str_type type = s->type;

	memset(m, 0, sizeof(*m));
	memset(s, 0, sizeof(*s));

	s->type = type;
}

static enum mode_err
mode_cfg_chanmodes(struct mode_cfg *cfg, const char *str)
{


@@ 422,31 404,25 @@ error:
enum mode_type
mode_type(const struct mode_cfg *cfg, int flag, int set)
{
	/* Return the chanmode flag type specified by config
	 *
	 *   A = Always has a parameter.
	 *   B = Always has a parameter.
	 *   C = Only has a parameter when set.
	 *   D = Never has a parameter.
	 */

	if (mode_isset(&(cfg->chanmodes), flag)) {
	/* Chanmode PREFIX */
	if (strchr(cfg->PREFIX.F, flag))
		return MODE_FLAG_PREFIX;

		if (strchr(cfg->PREFIX.F, flag))
			return MODE_FLAG_PREFIX;

		if (mode_isset(&(cfg->CHANMODES.A), flag))
			return MODE_FLAG_CHANMODE_PARAM;
	/* Chanmode subtype A, Always has a parameter. */
	if (mode_isset(&(cfg->CHANMODES.A), flag))
		return MODE_FLAG_CHANMODE_PARAM;

		if (mode_isset(&(cfg->CHANMODES.B), flag))
			return MODE_FLAG_CHANMODE_PARAM;
	/* Chanmode subtype B, Always has a parameter. */
	if (mode_isset(&(cfg->CHANMODES.B), flag))
		return MODE_FLAG_CHANMODE_PARAM;

		if (mode_isset(&(cfg->CHANMODES.C), flag))
			return (set ? MODE_FLAG_CHANMODE_PARAM : MODE_FLAG_CHANMODE);
	/* Chanmode subtype C, Only has a parameter when set. */
	if (mode_isset(&(cfg->CHANMODES.C), flag))
		return (set ? MODE_FLAG_CHANMODE_PARAM : MODE_FLAG_CHANMODE);

		if (mode_isset(&(cfg->CHANMODES.D), flag))
			return MODE_FLAG_CHANMODE;
	}
	/* Chanmode subtype D, Never has a parameter. */
	if (mode_isset(&(cfg->CHANMODES.D), flag))
		return MODE_FLAG_CHANMODE;

	return MODE_FLAG_INVALID_FLAG;
}

M src/components/mode.h => src/components/mode.h +13 -16
@@ 49,6 49,14 @@ enum mode_err
	MODE_ERR_NONE
};

enum mode_type
{
	MODE_FLAG_INVALID_FLAG,
	MODE_FLAG_CHANMODE,       /* Chanmode flag without parameter */
	MODE_FLAG_CHANMODE_PARAM, /* Chanmode flag with parameter */
	MODE_FLAG_PREFIX,         /* Chanmode flag that sets prfxmode */
};

enum mode_cfg_type
{
	MODE_CFG_DEFAULTS,  /* Set RFC2811 mode defaults */


@@ 58,12 66,11 @@ enum mode_cfg_type
	MODE_CFG_PREFIX,    /* Set numeric 005 PREFIX */
};

enum mode_type
enum mode_str_type
{
	MODE_FLAG_INVALID_FLAG,
	MODE_FLAG_CHANMODE,       /* Chanmode flag without parameter */
	MODE_FLAG_CHANMODE_PARAM, /* Chanmode flag with parameter */
	MODE_FLAG_PREFIX,         /* Chanmode flag that sets prfxmode */
	MODE_STR_CHANMODE,
	MODE_STR_USERMODE,
	MODE_STR_PRFXMODE,
};

struct mode


@@ 94,17 101,9 @@ struct mode_cfg
struct mode_str
{
	char str[MODE_STR_LEN + 1];
	enum mode_str_type
	{
		MODE_STR_UNSET = 0,
		MODE_STR_CHANMODE,
		MODE_STR_USERMODE,
		MODE_STR_PRFXMODE,
	} type;
};


const char* mode_str(const struct mode*, struct mode_str*);
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);


@@ 113,6 112,4 @@ enum mode_err mode_usermode_set(struct mode*, const struct mode_cfg*, int, int);

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

void mode_reset(struct mode*, struct mode_str*);

#endif

M src/components/server.c => src/components/server.c +2 -2
@@ 50,7 50,6 @@ server(
	s->mode = (mode ? strdup(mode) : NULL);

	s->casemapping = CASEMAPPING_RFC1459;
	s->mode_str.type = MODE_STR_USERMODE;
	ircv3_caps(&(s->ircv3_caps));
	ircv3_sasl(&(s->ircv3_sasl));
	mode_cfg(&(s->mode_cfg), NULL, MODE_CFG_DEFAULTS);


@@ 141,7 140,8 @@ server_reset(struct server *s)
{
	ircv3_caps_reset(&(s->ircv3_caps));
	ircv3_sasl_reset(&(s->ircv3_sasl));
	mode_reset(&(s->usermodes), &(s->mode_str));
	memset(&(s->usermodes), 0, sizeof(s->usermodes));
	memset(&(s->mode_str), 0, sizeof(s->mode_str));
	s->ping = 0;
	s->quitting = 0;
	s->registered = 0;

M src/handlers/irc_recv.c => src/handlers/irc_recv.c +2 -2
@@ 997,7 997,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(&(c->chanmodes), &(c->chanmodes_str), MODE_STR_CHANMODE);
	draw(DRAW_STATUS);

	return 0;


@@ 1048,7 1048,7 @@ recv_mode_usermodes(struct irc_message *m, const struct mode_cfg *cfg, struct se
		}
	} while (irc_message_param(m, &modestring));

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

	return 0;

M src/state.c => src/state.c +0 -2
@@ 210,8 210,6 @@ _newline(struct channel *c, enum buffer_line_type type, const char *from, const 
		}
	}

	// TODO: preformat the time string here

	buffer_newline(
		&(c->buffer),
		type,

M test/components/mode.c => test/components/mode.c +35 -44
@@ 28,35 28,26 @@ test_mode_str(void)
	struct mode m = MODE_EMPTY;
	struct mode_str str;

	memset(&str, 0, sizeof(struct mode_str));

	/* mode_str type not set */
	assert_fatal(mode_str(&m, &str));

	str.type = -1;

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

	str.type = MODE_STR_USERMODE;
	assert_fatal(mode_str(&m, &str, -1));

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

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

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

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

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

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

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

static void


@@ 66,38 57,38 @@ test_mode_chanmode_set(void)

	struct mode m = MODE_EMPTY;
	struct mode_cfg cfg;
	struct mode_str str = { .type = MODE_STR_CHANMODE };
	struct mode_str str;

	mode_cfg_chanmodes(&cfg, "abcdefghijsp");
	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), "");
	assert_strcmp(mode_str(&m, &str, MODE_STR_CHANMODE), "");

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

	/* 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), "");
	assert_strcmp(mode_str(&m, &str, MODE_STR_CHANMODE), "");

	/* 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), "d");
	assert_strcmp(mode_str(&m, &str, MODE_STR_CHANMODE), "d");

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

	assert_eq(mode_chanmode_set(&m, &cfg, 'j', 1), MODE_ERR_NONE);
	assert_strcmp(mode_str(&m, &str), "dej");
	assert_strcmp(mode_str(&m, &str, MODE_STR_CHANMODE), "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), "");
	assert_strcmp(mode_str(&m, &str, MODE_STR_CHANMODE), "");
}

static void


@@ 106,13 97,13 @@ test_mode_prfxmode_set(void)
	/* Test setting/unsetting prfxmode flag and prefix */

	struct mode m = MODE_EMPTY;
	struct mode_str str = { .type = MODE_STR_PRFXMODE };
	struct mode_cfg cfg = {
		.PREFIX = {
			.F = "abc",
			.T = "123"
		}
	};
	struct mode_str str;

	mode_cfg_chanmodes(&cfg, "abc");



@@ 150,7 141,7 @@ test_mode_prfxmode_set(void)
	assert_eq(mode_prfxmode_set(&m, &cfg, '3', 1), MODE_ERR_NONE);
	assert_eq(m.prefix, '2');

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

static void


@@ 159,8 150,8 @@ test_mode_usermode_set(void)
	/* Test setting/unsetting usermode flag and mode string */

	struct mode m = MODE_EMPTY;
	struct mode_str str = { .type = MODE_STR_USERMODE };
	struct mode_cfg cfg;
	struct mode_str str;

	mode_cfg_usermodes(&cfg, "azAZ");



@@ 170,11 161,11 @@ test_mode_usermode_set(void)
	/* 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), "aZ");
	assert_strcmp(mode_str(&m, &str, MODE_STR_USERMODE), "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), "azAZ");
	assert_strcmp(mode_str(&m, &str, MODE_STR_USERMODE), "azAZ");

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


@@ 182,11 173,11 @@ test_mode_usermode_set(void)
	/* 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), "aA");
	assert_strcmp(mode_str(&m, &str, MODE_STR_USERMODE), "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), "");
	assert_strcmp(mode_str(&m, &str, MODE_STR_USERMODE), "");
}

static void


@@ 195,23 186,23 @@ test_mode_cfg_usermodes(void)
	/* Test configuring server usermodes */

	struct mode_cfg cfg;
	struct mode_str str = { .type = MODE_STR_USERMODE };
	struct mode_str str;

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

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

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

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

static void


@@ 220,23 211,23 @@ test_mode_cfg_chanmodes(void)
	/* Test configuring server chanmodes */

	struct mode_cfg cfg;
	struct mode_str str = { .type = MODE_STR_USERMODE };
	struct mode_str str;

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

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

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

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

static void


@@ 245,13 236,13 @@ test_mode_cfg_subtypes(void)
	/* Test configuring CHANMODE subtypes */

	struct mode_cfg cfg;
	struct mode_str str = { .type = MODE_STR_USERMODE };
	struct mode_str str;

#define CHECK(_A, _B, _C, _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));
	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));

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