refactor nick management code

- drop struct nick.
- follow nick changes in a basic way.
  right now it does not work if one changes nick and somebody else takes
  the old unused nick.
This commit is contained in:
Arnaud Cornet 2008-12-20 17:59:16 +01:00
parent 4d231e8ddc
commit e8bb841e5f
5 changed files with 108 additions and 127 deletions

185
src/irc.c
View File

@ -78,7 +78,7 @@ struct channel *channel_new(const char *name)
struct channel *chan;
chan = bip_calloc(sizeof(struct channel), 1);
chan->name = bip_strdup(name);
hash_init(&chan->nicks, HASH_NOCASE);
hash_init(&chan->ovmasks, HASH_NOCASE);
return chan;
}
@ -108,23 +108,21 @@ list_t *channel_name_list(struct channel *c)
{
list_t *ret;
hash_iterator_t hi;
size_t s = NAMESIZE;
ret = list_new(NULL);
size_t len = 0;
char *str = bip_malloc(NAMESIZE);
char *str = bip_malloc(NAMESIZE + 1);
ret = list_new(NULL);
*str = 0;
for (hash_it_init(&c->nicks, &hi); hash_it_item(&hi);
for (hash_it_init(&c->ovmasks, &hi); hash_it_item(&hi);
hash_it_next(&hi)){
struct nick *n = hash_it_item(&hi);
const char *nick = hash_it_key(&hi);
long int ovmask = (long int)hash_it_item(&hi);
if (strlen(n->name) + 2 >= NAMESIZE)
fatal("nick too big for me"); /* FIXME */
assert(strlen(nick) + 2 < NAMESIZE);
if (len + strlen(n->name) + 2 + (n->ovmask ? 1 : 0)
>= NAMESIZE) {
if (len + strlen(nick) + 2 + (ovmask ? 1 : 0) >= NAMESIZE) {
list_add_last(ret, str);
str = bip_malloc(s);
str = bip_malloc(NAMESIZE + 1);
*str = 0;
len = 0;
}
@ -132,20 +130,17 @@ list_t *channel_name_list(struct channel *c)
strncat(str, " ", NAMESIZE);
len++;
}
if (n->ovmask & NICKOP) {
if (ovmask & NICKOP)
strncat(str, "@", NAMESIZE);
len++;
} else if (n->ovmask & NICKHALFOP) {
else if (ovmask & NICKHALFOP)
strncat(str, "%", NAMESIZE);
len++;
} else if (n->ovmask & NICKVOICED) {
else if (ovmask & NICKVOICED)
strncat(str, "+", NAMESIZE);
len++;
}
strncat(str, n->name, NAMESIZE);
len += strlen(n->name);
if (len >= NAMESIZE)
fatal("internal error 5");
len++;
strncat(str, nick, NAMESIZE);
len += strlen(nick);
assert(len < NAMESIZE);
}
list_add_last(ret, str);
return ret;
@ -542,7 +537,6 @@ static void irc_send_join(struct link_client *ic, struct channel *chan)
WRITE_LINE3(CONN(ic), P_SERV, "366", LINK(ic)->l_server->nick,
chan->name, "End of /NAMES list.");
}
static void write_init_string(connection_t *c, struct line *line, char *nick)
@ -666,7 +660,7 @@ static void irc_cli_backlog(struct link_client *ic)
user = LINK(ic)->user;
if (!user)
fatal("irc_send_join: No user associated");
fatal("irc_cli_backlog: No user associated");
if (!user->backlog) {
mylog(LOG_DEBUG, "Backlog disabled for %s, not backlogging",
user->name);
@ -871,7 +865,7 @@ static int irc_cli_privmsg(bip_t *bip, struct link_client *ic,
return OK_FORGET;
log_cli_privmsg(LINK(ic)->log, LINK(ic)->l_server->nick,
irc_line_elem(line, 1), irc_line_elem(line, 2));
irc_line_elem(line, 1), irc_line_elem(line, 2));
if (irc_line_elem_equals(line, 1, "-bip"))
return adm_bip(bip, ic, line, 1);
@ -1254,7 +1248,6 @@ static int irc_join(struct link_server *server, struct line *line)
char *s_nick;
const char *s_chan;
struct channel *channel;
struct nick *nick;
if (irc_line_count(line) != 2 && irc_line_count(line) != 3)
return ERR_PROTOCOL;
@ -1278,9 +1271,7 @@ static int irc_join(struct link_server *server, struct line *line)
return ERR_PROTOCOL;
s_nick = nick_from_ircmask(line->origin);
nick = bip_calloc(sizeof(struct nick), 1);
nick->name = s_nick; /* not freeing s_nick */
hash_insert(&channel->nicks, s_nick, nick);
hash_insert(&channel->ovmasks, s_nick, 0);
return OK_COPY;
}
@ -1329,20 +1320,12 @@ static int irc_333(struct link_server *server, struct line *line)
return OK_COPY;
}
static void nick_free(struct nick *nick)
{
if (nick->name)
free(nick->name);
free(nick);
}
static int irc_353(struct link_server *server, struct line *line)
{
struct channel *channel;
struct nick *nick;
const char *names, *eon;
size_t len;
char *tmp;
char *nick;
if (irc_line_count(line) != 5)
return ERR_PROTOCOL;
@ -1354,12 +1337,7 @@ static int irc_353(struct link_server *server, struct line *line)
if (!channel->running_names) {
channel->running_names = 1;
hash_iterator_t hi;
for (hash_it_init(&channel->nicks, &hi); hash_it_item(&hi);
hash_it_next(&hi)) {
nick_free(hash_it_item(&hi));
}
hash_clean(&channel->nicks);
hash_clean(&channel->ovmasks);
}
/* TODO check that type is one of "=" / "*" / "@" */
@ -1368,7 +1346,7 @@ static int irc_353(struct link_server *server, struct line *line)
names = irc_line_elem(line, 4);
while (*names) {
int ovmask = 0;
long int ovmask = 0;
int flagchars = 1;
/* some ircds (e.g. unreal) may display several flags for the
same nick */
@ -1400,15 +1378,14 @@ static int irc_353(struct link_server *server, struct line *line)
eon++;
len = eon - names;
tmp = bip_malloc(len + 1);
memcpy(tmp, names, len);
tmp[len] = 0;
nick = bip_malloc(len + 1);
memcpy(nick, names, len);
nick[len] = 0;
nick = bip_malloc(sizeof(struct nick));
nick->name = tmp;
nick->ovmask = ovmask;
/* we just ignore names for nicks that are crazy long */
if (len + 2 < NAMESIZE)
hash_insert(&channel->ovmasks, nick, (void *)ovmask);
hash_insert(&channel->nicks, nick->name, nick);
while (*eon && *eon == ' ')
eon++;
names = eon;
@ -1475,10 +1452,7 @@ static void channel_free(struct channel *c)
if (c->create_ts)
free(c->create_ts);
hash_iterator_t hi;
for (hash_it_init(&c->nicks, &hi); hash_it_item(&hi); hash_it_next(&hi))
nick_free(hash_it_item(&hi));
hash_clean(&c->nicks);
hash_clean(&c->ovmasks);
free(c);
}
@ -1487,7 +1461,6 @@ static int irc_part(struct link_server *server, struct line *line)
char *s_nick;
const char *s_chan;
struct channel *channel;
struct nick *nick;
if (irc_line_count(line) != 2 && irc_line_count(line) != 3)
return ERR_PROTOCOL;
@ -1512,18 +1485,14 @@ static int irc_part(struct link_server *server, struct line *line)
if (!line->origin)
return ERR_PROTOCOL;
s_nick = nick_from_ircmask(line->origin);
nick = hash_get(&channel->nicks, s_nick);
if (!nick) {
free(s_nick);
if (!hash_includes(&channel->ovmasks, s_nick))
return ERR_PROTOCOL;
}
nick = hash_remove(&channel->nicks, s_nick);
free(s_nick);
hash_remove(&channel->ovmasks, s_nick);
log_part(LINK(server)->log, line->origin, s_chan,
irc_line_count(line) == 3 ? irc_line_elem(line, 2) : NULL);
irc_line_count(line) == 3 ?
irc_line_elem(line, 2) : NULL);
nick_free(nick);
return OK_COPY;
}
@ -1579,10 +1548,8 @@ static int irc_mode(struct link_server *server, struct line *line)
const char *mode;
int add = 1;
unsigned cur_arg = 0;
struct nick *nick;
array_t *mode_args = NULL;
if (!irc_line_includes(line, 2))
return ERR_PROTOCOL;
@ -1621,6 +1588,8 @@ static int irc_mode(struct link_server *server, struct line *line)
* ^ ^
* mode cur_arg
*/
const char *nick;
long int ovmask;
for (mode = irc_line_elem(line, 2); *mode; mode++) {
switch (*mode) {
case '-':
@ -1637,43 +1606,48 @@ static int irc_mode(struct link_server *server, struct line *line)
case 'o':
if (!irc_line_includes(line, cur_arg + 3))
return ERR_PROTOCOL;
nick = irc_line_elem(line, cur_arg + 3);
nick = hash_get(&channel->nicks,
irc_line_elem(line, cur_arg + 3));
if (!nick)
if (!hash_includes(&channel->ovmasks, nick))
return ERR_PROTOCOL;
ovmask = (long int)hash_remove(&channel->ovmasks, nick);
if (add)
nick->ovmask |= NICKOP;
ovmask |= NICKOP;
else
nick->ovmask &= ~NICKOP;
ovmask &= ~NICKOP;
hash_insert(&channel->ovmasks, nick, (void *)ovmask);
cur_arg++;
break;
case 'h':
if (!irc_line_includes(line, cur_arg + 3))
return ERR_PROTOCOL;
nick = irc_line_elem(line, cur_arg + 3);
nick = hash_get(&channel->nicks,
irc_line_elem(line, cur_arg + 3));
if (!nick)
if (!hash_includes(&channel->ovmasks, nick))
return ERR_PROTOCOL;
ovmask = (long int)hash_get(&channel->ovmasks, nick);
if (add)
nick->ovmask |= NICKHALFOP;
ovmask |= NICKHALFOP;
else
nick->ovmask &= ~NICKHALFOP;
ovmask &= ~NICKHALFOP;
hash_insert(&channel->ovmasks, nick, (void *)ovmask);
cur_arg++;
break;
case 'v':
if (!irc_line_includes(line, cur_arg + 3))
return ERR_PROTOCOL;
nick = irc_line_elem(line, cur_arg + 3);
nick = hash_get(&channel->nicks,
irc_line_elem(line, cur_arg + 3));
if (!nick)
if (!hash_includes(&channel->ovmasks, nick))
return ERR_PROTOCOL;
ovmask = (long int)hash_get(&channel->ovmasks, nick);
if (add)
nick->ovmask |= NICKVOICED;
ovmask |= NICKVOICED;
else
nick->ovmask &= ~NICKVOICED;
ovmask &= ~NICKVOICED;
hash_insert(&channel->ovmasks, nick, (void *)ovmask);
cur_arg++;
break;
case 'k':
@ -1749,14 +1723,14 @@ static int irc_topic(struct link_server *server, struct line *line)
free(channel->create_ts);
channel->create_ts = irc_timestamp();
log_topic(LINK(server)->log, line->origin, irc_line_elem(line, 1), topic);
log_topic(LINK(server)->log, line->origin, irc_line_elem(line, 1),
topic);
return OK_COPY;
}
static int irc_kick(struct link_server *server, struct line *line)
{
struct channel *channel;
struct nick *nick;
if (irc_line_count(line) != 3 && irc_line_count(line) != 4)
return ERR_PROTOCOL;
@ -1766,22 +1740,21 @@ static int irc_kick(struct link_server *server, struct line *line)
if (!channel)
return ERR_PROTOCOL;
nick = hash_get(&channel->nicks, irc_line_elem(line, 2));
if (!nick)
if (!hash_includes(&channel->ovmasks, irc_line_elem(line, 2)))
return ERR_PROTOCOL;
if (strcmp(nick->name, server->nick) == 0) {
if (strcasecmp(irc_line_elem(line, 2), server->nick) == 0) {
log_kick(LINK(server)->log, line->origin, channel->name,
nick->name,
irc_line_count(line) == 4 ? irc_line_elem(line, 3) : NULL);
irc_line_elem(line, 2),
irc_line_count(line) == 4 ?
irc_line_elem(line, 3) : NULL);
hash_remove(&server->channels, channel->name);
channel_free(channel);
return OK_COPY;
}
hash_remove(&channel->nicks, nick->name);
nick_free(nick);
hash_remove(&channel->ovmasks, irc_line_elem(line, 2));
log_kick(LINK(server)->log, line->origin, irc_line_elem(line, 1),
irc_line_elem(line, 2),
irc_line_count(line) == 4 ? irc_line_elem(line, 3) : NULL);
@ -1834,9 +1807,9 @@ static int irc_quit(struct link_server *server, struct line *line)
static int irc_nick(struct link_server *server, struct line *line)
{
struct channel *channel;
struct nick *nick;
hash_iterator_t hi;
char *org_nick;
const char *dst_nick;
if (irc_line_count(line) != 2)
return ERR_PROTOCOL;
@ -1845,24 +1818,20 @@ static int irc_nick(struct link_server *server, struct line *line)
return ERR_PROTOCOL;
org_nick = nick_from_ircmask(line->origin);
dst_nick = irc_line_elem(line, 1);
for (hash_it_init(&server->channels, &hi); hash_it_item(&hi);
hash_it_next(&hi)) {
channel = hash_it_item(&hi);
nick = hash_get(&channel->nicks, org_nick);
if (!nick)
if (!hash_includes(&channel->ovmasks, org_nick))
continue;
hash_remove(&channel->nicks, org_nick);
free(nick->name);
nick->name = bip_strdup(irc_line_elem(line, 1));
hash_insert(&channel->nicks, nick->name, nick);
log_nick(LINK(server)->log, org_nick, channel->name,
irc_line_elem(line, 1));
hash_rename_key(&channel->ovmasks, org_nick, dst_nick);
log_nick(LINK(server)->log, org_nick, channel->name, dst_nick);
}
if (origin_is_me(line, server)) {
free(server->nick);
server->nick = bip_strdup(irc_line_elem(line, 1));
server->nick = bip_strdup(dst_nick);
if (LINK(server)->follow_nick &&
(LINK(server)->away_nick == NULL ||
strcmp(server->nick, LINK(server)->away_nick))
@ -1879,7 +1848,6 @@ static int irc_nick(struct link_server *server, struct line *line)
static int irc_generic_quit(struct link_server *server, struct line *line)
{
struct channel *channel;
struct nick *nick;
hash_iterator_t hi;
char *s_nick;
@ -1889,18 +1857,15 @@ static int irc_generic_quit(struct link_server *server, struct line *line)
if (!line->origin)
return ERR_PROTOCOL;
s_nick = nick_from_ircmask(line->origin);
for (hash_it_init(&server->channels, &hi); hash_it_item(&hi);
hash_it_next(&hi)) {
channel = hash_it_item(&hi);
nick = hash_get(&channel->nicks, s_nick);
if (!nick)
if (!hash_includes(&channel->ovmasks, s_nick))
continue;
hash_remove(&channel->nicks, s_nick);
nick_free(nick);
hash_remove(&channel->ovmasks, s_nick);
log_quit(LINK(server)->log, line->origin, channel->name,
irc_line_includes(line, 1) ? irc_line_elem(line, 1) : NULL);
irc_line_includes(line, 1) ?
irc_line_elem(line, 1) : NULL);
}
free(s_nick);
return OK_COPY;

View File

@ -15,7 +15,7 @@
#define IRC_H
#include "connection.h"
#include "line.h"
#include "log.h"
#define ERR_PROTOCOL (-1)
#define ERR_AUTH (-2)
@ -40,11 +40,6 @@ struct server {
#define NICKHALFOP (1<<1)
#define NICKVOICED (1<<2)
struct nick {
char *name;
int ovmask;
};
struct channel {
char *name;
char *mode;
@ -54,7 +49,7 @@ struct channel {
char type;
char *creator;
char *create_ts;
hash_t nicks;
hash_t ovmasks;
int running_names;
};

View File

@ -415,6 +415,9 @@ void log_quit(log_t *logdata, const char *ircmask, const char *channel,
void log_nick(log_t *logdata, const char *ircmask, const char *channel,
const char *newnick)
{
char *oldnick = nick_from_ircmask(ircmask);
if (hash_includes(&logdata->logfgs, oldnick))
hash_rename_key(&logdata->logfgs, oldnick, newnick);
snprintf(logdata->buffer, LOGLINE_MAXLEN,
"%s -!- %s is now known as %s",
timestamp(), ircmask, newnick);
@ -559,16 +562,17 @@ void log_mode(log_t *logdata, const char *ircmask, const char *channel,
snprintf(tmpbuf, LOGLINE_MAXLEN, "%s -!- mode/%s [%s", timestamp(),
channel, modes);
for (i = 0; i < array_count(mode_args); i++) {
snprintf(tmpbuf2, LOGLINE_MAXLEN, "%s %s", tmpbuf,
(char *)array_get(mode_args, i));
tmp = tmpbuf;
tmpbuf = tmpbuf2;
tmpbuf2 = tmp;
if (mode_args) {
for (i = 0; i < array_count(mode_args); i++) {
snprintf(tmpbuf2, LOGLINE_MAXLEN, "%s %s", tmpbuf,
(char *)array_get(mode_args, i));
tmp = tmpbuf;
tmpbuf = tmpbuf2;
tmpbuf2 = tmp;
}
}
snprintf(logdata->buffer, LOGLINE_MAXLEN, "%s] by %s", tmpbuf,
ircmask);
snprintf(logdata->buffer, LOGLINE_MAXLEN, "%s] by %s", tmpbuf, ircmask);
log_write(logdata, channel, logdata->buffer);
free(tmpbuf);

View File

@ -550,6 +550,14 @@ void hash_insert(hash_t *hash, const char *key, void *ptr)
list_add_first(&hash->lists[hash_func(key)], it);
}
int hash_includes(hash_t *hash, const char *key)
{
struct hash_item *hi;
list_t *list = &hash->lists[hash_func(key)];
hi = list_get(list, key);
return hi != NULL;
}
void *hash_get(hash_t *hash, const char *key)
{
struct hash_item *hi;
@ -667,6 +675,11 @@ list_t *hash_keys(hash_t *hash)
return ret;
}
void hash_rename_key(hash_t *h, const char *oldk, const char *newk)
{
hash_insert(h, newk, hash_remove(h, oldk));
}
char *bip_strmaydup(char *s)
{
if (!s)

View File

@ -122,6 +122,7 @@ void hash_free(hash_t *h);
void hash_clean(hash_t *h);
hash_t *hash_new(int options);
void hash_insert(hash_t *hash, const char *key, void *ptr);
int hash_includes(hash_t *hash, const char *key);
void *hash_get(hash_t *, const char *key);
void *hash_remove(hash_t *hash, const char *key);
void *hash_remove_if_exists(hash_t *hash, const char *key);
@ -132,6 +133,7 @@ void *hash_it_item(hash_iterator_t *h);
const char *hash_it_key(hash_iterator_t *h);
void *hash_it_remove(hash_iterator_t *li);
list_t *hash_keys(hash_t *hash);
void hash_rename_key(hash_t *h, const char *oldk, const char *newk);
int is_valid_nick(char *str);
int is_valid_username(char *str);
@ -183,8 +185,10 @@ static inline void *array_get(array_t *a, int index)
static inline void array_push(array_t *a, void *ptr)
{
array_ensure(a, a->elemc + 1);
a->elemv[a->elemc - 1] = ptr;
int idx = a->elemc;
array_ensure(a, idx);
a->elemv[idx] = ptr;
}
static inline void *array_pop(array_t *a)