diff options
-rw-r--r-- | src/core/server.c | 6 | ||||
-rw-r--r-- | src/fe-common/irc/fe-channels.c | 5 | ||||
-rw-r--r-- | src/fe-common/irc/fe-netjoin.c | 2 | ||||
-rw-r--r-- | src/fe-text/statusbar-items.c | 13 | ||||
-rw-r--r-- | src/irc/core/channels.c | 29 | ||||
-rw-r--r-- | src/irc/core/channels.h | 16 | ||||
-rw-r--r-- | src/irc/core/irc-special-vars.c | 5 | ||||
-rw-r--r-- | src/irc/core/irc.h | 16 | ||||
-rw-r--r-- | src/irc/core/masks.c | 19 | ||||
-rw-r--r-- | src/irc/core/mode-lists.c | 68 | ||||
-rw-r--r-- | src/irc/core/modes.c | 320 | ||||
-rw-r--r-- | src/irc/core/modes.h | 28 | ||||
-rw-r--r-- | src/irc/core/nicklist.c | 50 | ||||
-rw-r--r-- | src/irc/core/nicklist.h | 1 | ||||
-rw-r--r-- | src/perl/xs/Irssi-channel.xs | 5 |
15 files changed, 351 insertions, 232 deletions
diff --git a/src/core/server.c b/src/core/server.c index c4d22d6c..029433c5 100644 --- a/src/core/server.c +++ b/src/core/server.c @@ -204,7 +204,8 @@ int server_connect(SERVER_REC *server) server->connect_pipe[1]); server->connect_tag = g_input_add(server->connect_pipe[0], G_INPUT_READ, - (GInputFunction) server_connect_callback_readpipe, server); + (GInputFunction) server_connect_callback_readpipe, + server); lookup_servers = g_slist_append(lookup_servers, server); @@ -278,7 +279,8 @@ SERVER_REC *server_find_ircnet(const char *ircnet) SERVER_REC *server = tmp->data; if (server->connrec->ircnet != NULL && - g_strcasecmp(server->connrec->ircnet, ircnet) == 0) return server; + g_strcasecmp(server->connrec->ircnet, ircnet) == 0) + return server; } return NULL; diff --git a/src/fe-common/irc/fe-channels.c b/src/fe-common/irc/fe-channels.c index 4c1a7011..1d41c70f 100644 --- a/src/fe-common/irc/fe-channels.c +++ b/src/fe-common/irc/fe-channels.c @@ -149,7 +149,6 @@ static void cmd_channel_list_joined(void) CHANNEL_REC *channel; GString *nicks; GSList *nicklist, *tmp, *ntmp; - char *mode; if (channels == NULL) { printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOT_IN_CHANNELS); @@ -167,7 +166,6 @@ static void cmd_channel_list_joined(void) channel = tmp->data; nicklist = nicklist_getnicks(channel); - mode = channel_get_mode(channel); nicks = g_string_new(NULL); for (ntmp = nicklist; ntmp != NULL; ntmp = ntmp->next) { NICK_REC *rec = ntmp->data; @@ -177,9 +175,8 @@ static void cmd_channel_list_joined(void) if (nicks->len > 1) g_string_truncate(nicks, nicks->len-1); printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_CHANLIST_LINE, - channel->name, mode, channel->server->tag, nicks->str); + channel->name, channel->mode, channel->server->tag, nicks->str); - g_free(mode); g_slist_free(nicklist); g_string_free(nicks, TRUE); } diff --git a/src/fe-common/irc/fe-netjoin.c b/src/fe-common/irc/fe-netjoin.c index 9cb77ed2..e6c50c1e 100644 --- a/src/fe-common/irc/fe-netjoin.c +++ b/src/fe-common/irc/fe-netjoin.c @@ -359,7 +359,7 @@ static void event_mode(const char *data, IRC_SERVER_REC *server, show = TRUE; nick++; } else { - if (HAS_MODE_ARG(*mode) && *nick != NULL) + if (HAS_MODE_ARG(type, *mode) && *nick != NULL) nick++; show = TRUE; } diff --git a/src/fe-text/statusbar-items.c b/src/fe-text/statusbar-items.c index 08f46eb2..d4759401 100644 --- a/src/fe-text/statusbar-items.c +++ b/src/fe-text/statusbar-items.c @@ -214,7 +214,7 @@ static void statusbar_channel(SBAR_ITEM_REC *item, int ypos) WI_ITEM_REC *witem; CHANNEL_REC *channel; SERVER_REC *server; - gchar channame[21], winnum[MAX_INT_STRLEN], *mode, *tmpname; + gchar channame[21], winnum[MAX_INT_STRLEN], *tmpname; int size_needed; int mode_size; @@ -230,8 +230,8 @@ static void statusbar_channel(SBAR_ITEM_REC *item, int ypos) { /* display server tag */ channame[0] = '\0'; - mode = NULL; mode_size = 0; + channel = NULL; size_needed = 3 + strlen(winnum) + (server == NULL ? 0 : (17+strlen(server->tag))); } @@ -245,10 +245,8 @@ static void statusbar_channel(SBAR_ITEM_REC *item, int ypos) channel = irc_item_channel(witem); if (channel == NULL) { mode_size = 0; - mode = NULL; } else { - mode = channel_get_mode(channel); - mode_size = strlen(mode); + mode_size = strlen(channel->mode); if (mode_size > 0) mode_size += 3; /* (+) */ } @@ -259,7 +257,6 @@ static void statusbar_channel(SBAR_ITEM_REC *item, int ypos) { /* we need more (or less..) space! */ statusbar_item_resize(item, size_needed); - if (mode != NULL) g_free(mode); return; } @@ -284,14 +281,12 @@ static void statusbar_channel(SBAR_ITEM_REC *item, int ypos) { set_color(stdscr, sbar_color_bold); addch('('); set_color(stdscr, sbar_color_dim); addch('+'); - set_color(stdscr, sbar_color_normal); addstr(mode); + set_color(stdscr, sbar_color_normal); addstr(channel->mode); set_color(stdscr, sbar_color_bold); addch(')'); } } set_color(stdscr, sbar_color_dim); addch(']'); screen_refresh(NULL); - - if (mode != NULL) g_free(mode); } static void sig_statusbar_channel_redraw(void) diff --git a/src/irc/core/channels.c b/src/irc/core/channels.c index 445bc1e4..158abede 100644 --- a/src/irc/core/channels.c +++ b/src/irc/core/channels.c @@ -62,6 +62,7 @@ CHANNEL_REC *channel_create(IRC_SERVER_REC *server, const char *channel, int aut rec->name = g_strdup(channel); rec->server = server; rec->createtime = time(NULL); + rec->mode = g_strdup(""); if (*channel == '+') rec->no_modes = TRUE; @@ -126,34 +127,6 @@ CHANNEL_REC *channel_find(IRC_SERVER_REC *server, const char *channel) } -char *channel_get_mode(CHANNEL_REC *channel) -{ - GString *mode; - char *ret; - - g_return_val_if_fail(channel != NULL, NULL); - - mode = g_string_new(NULL); - - if (channel->mode_secret) g_string_append_c(mode, 's'); - if (channel->mode_private) g_string_append_c(mode, 'p'); - if (channel->mode_moderate) g_string_append_c(mode, 'm'); - if (channel->mode_invite) g_string_append_c(mode, 'i'); - if (channel->mode_nomsgs) g_string_append_c(mode, 'n'); - if (channel->mode_optopic) g_string_append_c(mode, 't'); - if (channel->mode_anonymous) g_string_append_c(mode, 'a'); - if (channel->mode_reop) g_string_append_c(mode, 'r'); - if (channel->mode_key) g_string_append_c(mode, 'k'); - if (channel->limit > 0) g_string_append_c(mode, 'l'); - - if (channel->mode_key) g_string_sprintfa(mode, " %s", channel->key); - if (channel->limit > 0) g_string_sprintfa(mode, " %d", channel->limit); - - ret = mode->str; - g_string_free(mode, FALSE); - return ret; -} - #define get_join_key(key) \ (((key) == NULL || *(key) == '\0') ? "x" : (key)) diff --git a/src/irc/core/channels.h b/src/irc/core/channels.h index 9873c303..bda4db1d 100644 --- a/src/irc/core/channels.h +++ b/src/irc/core/channels.h @@ -21,20 +21,12 @@ typedef struct { GSList *invitelist; /* invite list */ char *topic; - int limit; /* user limit */ - char *key; /* password key */ /* channel mode */ int no_modes:1; /* channel doesn't support modes */ - int mode_invite:1; - int mode_secret:1; - int mode_private:1; - int mode_moderate:1; - int mode_nomsgs:1; - int mode_optopic:1; - int mode_key:1; - int mode_anonymous:1; - int mode_reop:1; + char *mode; + int limit; /* user limit */ + char *key; /* password key */ int chanop:1; /* You're a channel operator */ @@ -64,8 +56,6 @@ void channel_destroy(CHANNEL_REC *channel); /* find channel by name, if `server' is NULL, search from all servers */ CHANNEL_REC *channel_find(IRC_SERVER_REC *server, const char *channel); -char *channel_get_mode(CHANNEL_REC *channel); - /* Join to channels. `data' contains channels and channel keys */ void channels_join(IRC_SERVER_REC *server, const char *data, int automatic); diff --git a/src/irc/core/irc-special-vars.c b/src/irc/core/irc-special-vars.c index 92acd246..03335114 100644 --- a/src/irc/core/irc-special-vars.c +++ b/src/irc/core/irc-special-vars.c @@ -101,10 +101,7 @@ static char *expando_chanmode(void *server, void *item, int *free_ret) CHANNEL_REC *channel; channel = irc_item_channel(item); - if (channel == NULL) return NULL; - - *free_ret = TRUE; - return channel_get_mode(channel); + return channel == NULL ? NULL : channel->mode; } /* current nickname */ diff --git a/src/irc/core/irc.h b/src/irc/core/irc.h index 5c549157..baa692df 100644 --- a/src/irc/core/irc.h +++ b/src/irc/core/irc.h @@ -12,9 +12,19 @@ = i line with OTHER type ident - i line, no ident */ -#define ishostflag(a) ((a) == '^' || (a) == '~' || (a) == '+' || (a) == '=' || (a) == '-') -#define isnickflag(a) ((a) == '@' || (a) == '+' || (a) == '-' || (a) == '~') -#define ischannel(a) ((a) == '#' || (a) == '&' || (a) == '!' || (a) == '+') +#define ishostflag(a) \ + ((a) == '^' || (a) == '~' || \ + (a) == '+' || (a) == '=' || (a) == '-') + +#define isnickflag(a) \ + ((a) == '@' || (a) == '+' || (a) == '%' || /* op / voice / half-op */ \ + (a) == '-' || (a) == '~') /* no idea, just copied from somewhere.. */ + +#define ischannel(a) \ + ((a) == '#' || /* normal */ \ + (a) == '&' || /* local */ \ + (a) == '!' || /* secure */ \ + (a) == '+') /* modeless */ /* values returned by module_category() */ enum { diff --git a/src/irc/core/masks.c b/src/irc/core/masks.c index 17e3048a..e2942140 100644 --- a/src/irc/core/masks.c +++ b/src/irc/core/masks.c @@ -39,11 +39,17 @@ static int check_mask(const char *mask, int *wildcards) return FALSE; } -int irc_mask_match(const char *mask, const char *nick, const char *user, const char *host) +int irc_mask_match(const char *mask, const char *nick, + const char *user, const char *host) { char *str; int ret, wildcards; + g_return_val_if_fail(mask != NULL, FALSE); + g_return_val_if_fail(nick != NULL, FALSE); + g_return_val_if_fail(user != NULL, FALSE); + g_return_val_if_fail(host != NULL, FALSE); + if (!check_mask(mask, &wildcards)) { return wildcards ? match_wildcards(mask, nick) : @@ -57,12 +63,14 @@ int irc_mask_match(const char *mask, const char *nick, const char *user, const c return ret; } -int irc_mask_match_address(const char *mask, const char *nick, const char *address) +int irc_mask_match_address(const char *mask, const char *nick, + const char *address) { char *str; int ret, wildcards; - g_return_val_if_fail(address != NULL, FALSE); + g_return_val_if_fail(mask != NULL, FALSE); + g_return_val_if_fail(nick != NULL, FALSE); if (!check_mask(mask, &wildcards)) { return wildcards ? @@ -70,7 +78,7 @@ int irc_mask_match_address(const char *mask, const char *nick, const char *addre g_strcasecmp(mask, nick) == 0; } - str = g_strdup_printf("%s!%s", nick, address); + str = g_strdup_printf("%s!%s", nick, address != NULL ? address : ""); ret = match_wildcards(mask, str); g_free(str); @@ -136,7 +144,8 @@ char *irc_get_mask(const char *nick, const char *address, int flags) char *ret, *user, *host; /* strip -, ^ or ~ from start.. */ - user = g_strconcat("*", ishostflag(*address) ? address+1 : address, NULL); + user = g_strconcat("*", ishostflag(*address) ? + address+1 : address, NULL); /* split user and host */ host = strchr(user, '@'); diff --git a/src/irc/core/mode-lists.c b/src/irc/core/mode-lists.c index 21e7b563..44df5189 100644 --- a/src/irc/core/mode-lists.c +++ b/src/irc/core/mode-lists.c @@ -43,17 +43,18 @@ void banlist_free(GSList *banlist) ban_free(&banlist, banlist->data); } -BAN_REC *banlist_add(CHANNEL_REC *channel, const char *ban, const char *nick, time_t time) +BAN_REC *banlist_add(CHANNEL_REC *channel, const char *ban, + const char *nick, time_t time) { BAN_REC *rec; g_return_val_if_fail(channel != NULL, NULL); g_return_val_if_fail(ban != NULL, NULL); - g_return_val_if_fail(nick != NULL, NULL); rec = g_new(BAN_REC, 1); rec->ban = g_strdup(ban); - rec->setby = g_strdup(nick); + rec->setby = nick == NULL || *nick == '\0' ? NULL : + g_strdup(nick); rec->time = time; channel->banlist = g_slist_append(channel->banlist, rec); @@ -62,36 +63,48 @@ BAN_REC *banlist_add(CHANNEL_REC *channel, const char *ban, const char *nick, ti return rec; } -void banlist_remove(CHANNEL_REC *channel, const char *ban) +static BAN_REC *banlist_find(GSList *list, const char *ban) { GSList *tmp; - g_return_if_fail(ban != NULL); + g_return_val_if_fail(ban != NULL, NULL); - for (tmp = channel->banlist; tmp != NULL; tmp = tmp->next) - { + for (tmp = list; tmp != NULL; tmp = tmp->next) { BAN_REC *rec = tmp->data; if (g_strcasecmp(rec->ban, ban) == 0) - { - signal_emit("ban remove", 1, rec); - ban_free(&channel->banlist, rec); - break; - } + return rec; + } + + return NULL; +} + +void banlist_remove(CHANNEL_REC *channel, const char *ban) +{ + BAN_REC *rec; + + g_return_if_fail(channel != NULL); + g_return_if_fail(ban != NULL); + + rec = banlist_find(channel->banlist, ban); + if (rec != NULL) { + signal_emit("ban remove", 1, rec); + ban_free(&channel->banlist, rec); } } -BAN_REC *banlist_exception_add(CHANNEL_REC *channel, const char *ban, const char *nick, time_t time) +BAN_REC *banlist_exception_add(CHANNEL_REC *channel, const char *ban, + const char *nick, time_t time) { BAN_REC *rec; g_return_val_if_fail(channel != NULL, NULL); g_return_val_if_fail(ban != NULL, NULL); - g_return_val_if_fail(nick != NULL, NULL); rec = g_new(BAN_REC, 1); rec->ban = g_strdup(ban); - rec->setby = g_strdup(nick); + rec->setby = nick == NULL || *nick == '\0' ? NULL : + g_strdup(nick); rec->time = time; channel->ebanlist = g_slist_append(channel->ebanlist, rec); @@ -102,20 +115,15 @@ BAN_REC *banlist_exception_add(CHANNEL_REC *channel, const char *ban, const char void banlist_exception_remove(CHANNEL_REC *channel, const char *ban) { - GSList *tmp; + BAN_REC *rec; + g_return_if_fail(channel != NULL); g_return_if_fail(ban != NULL); - for (tmp = channel->ebanlist; tmp != NULL; tmp = tmp->next) - { - BAN_REC *rec = tmp->data; - - if (g_strcasecmp(rec->ban, ban) == 0) - { - signal_emit("ban exception remove", 1, rec); - ban_free(&channel->ebanlist, rec); - break; - } + rec = banlist_find(channel->ebanlist, ban); + if (rec != NULL) { + signal_emit("ban exception remove", 1, rec); + ban_free(&channel->ebanlist, rec); } } @@ -172,9 +180,7 @@ static void event_banlist(const char *data, IRC_SERVER_REC *server) params = event_get_params(data, 5, NULL, &channel, &ban, &setby, &tims); chanrec = channel_find(server, channel); if (chanrec != NULL) { - if (sscanf(tims, "%ld", (long *) &tim) != 1) - tim = time(NULL); - + tim = (time_t) atol(tims); banlist_add(chanrec, ban, setby, tim); } g_free(params); @@ -191,9 +197,7 @@ static void event_ebanlist(const char *data, IRC_SERVER_REC *server) params = event_get_params(data, 5, NULL, &channel, &ban, &setby, &tims); chanrec = channel_find(server, channel); if (chanrec != NULL) { - if (sscanf(tims, "%ld", (long *) &tim) != 1) - tim = time(NULL); - + tim = (time_t) atol(tims); banlist_exception_add(chanrec, ban, setby, tim); } g_free(params); diff --git a/src/irc/core/modes.c b/src/irc/core/modes.c index 199aa5fe..c3331dfe 100644 --- a/src/irc/core/modes.c +++ b/src/irc/core/modes.c @@ -28,7 +28,8 @@ #include "nicklist.h" /* Change nick's mode in channel */ -static void nick_mode_change(CHANNEL_REC *channel, const char *nick, const char mode, gboolean set) +static void nick_mode_change(CHANNEL_REC *channel, const char *nick, + const char mode, int type) { NICK_REC *nickrec; @@ -38,26 +39,173 @@ static void nick_mode_change(CHANNEL_REC *channel, const char *nick, const char nickrec = nicklist_find(channel, nick); if (nickrec == NULL) return; /* No /names list got yet */ - if (mode == '@') nickrec->op = set; - if (mode == '+') nickrec->voice = set; + if (mode == '@') nickrec->op = type == '+'; + if (mode == '+') nickrec->voice = type == '+'; + if (mode == '%') nickrec->halfop = type == '+'; signal_emit("nick mode changed", 2, channel, nickrec); } +static int mode_is_set(const char *str, char mode) +{ + char *end, *pos; + + g_return_val_if_fail(str != NULL, FALSE); + + end = strchr(str, ' '); + pos = strchr(str, mode); + return pos != NULL && (end == NULL || pos < end); +} + +/* add argument to specified position */ +static void mode_add_arg(GString *str, int pos, const char *arg) +{ + char *p; + + for (p = str->str; *p != '\0'; p++) { + if (*p != ' ') + continue; + + if (pos == 0) + break; + pos--; + } + + /* .. GLib shouldn't fail when inserting at the end of the string */ + if (*p == '\0') { + g_string_append_c(str, ' '); + g_string_append(str, arg); + } else { + pos = (int) (p-str->str); + g_string_insert_c(str, pos, ' '); + g_string_insert(str, pos+1, arg); + } +} + +/* Add mode character to list sorted alphabetically */ +static void mode_add_sorted(GString *str, char mode, const char *arg) +{ + char *p; + int argpos = 0; + + /* check that mode isn't already set */ + if (mode_is_set(str->str, mode)) + return; + + for (p = str->str; *p != '\0' && *p != ' '; p++) { + if (mode < *p) + break; + if (HAS_MODE_ARG_SET(*p)) + argpos++; + } + + /* .. GLib shouldn't fail when inserting at the end of the string */ + if (*p == '\0') + g_string_append_c(str, mode); + else + g_string_insert_c(str, (int) (p-str->str), mode); + if (arg != NULL) + mode_add_arg(str, argpos+1, arg); +} + +/* remove the n'th argument */ +static void node_remove_arg(GString *str, int pos) +{ + char *p; + int startpos; + + startpos = -1; + for (p = str->str; *p != '\0'; p++) { + if (*p != ' ') + continue; + + if (pos < 0) + break; + if (pos == 0) + startpos = (int) (p-str->str); + pos--; + } + + if (startpos == -1) + return; /* not found */ + + g_string_erase(str, startpos, (int) (p-str->str)-startpos); +} + +/* remove mode (and it's argument) from string */ +static void mode_remove(GString *str, char mode) +{ + char *p; + int argpos = 0; + + for (p = str->str; *p != '\0' && *p != ' '; p++) { + if (mode == *p) { + g_string_erase(str, (int) (p-str->str), 1); + if (HAS_MODE_ARG_SET(mode)) + node_remove_arg(str, argpos); + break; + } + if (HAS_MODE_ARG_SET(*p)) + argpos++; + } +} + +static void mode_set(GString *str, char type, char mode) +{ + g_return_if_fail(str != NULL); + + if (type == '-') + mode_remove(str, mode); + else + mode_add_sorted(str, mode, NULL); +} + +static void mode_set_arg(GString *str, char type, char mode, const char *arg) +{ + g_return_if_fail(str != NULL); + g_return_if_fail(type == '-' || arg != NULL); + + if (type == '-') + mode_remove(str, mode); + else + mode_add_sorted(str, mode, arg); +} + +int channel_mode_is_set(CHANNEL_REC *channel, char mode) +{ + g_return_val_if_fail(channel != NULL, FALSE); + + return channel->mode == NULL ? FALSE : + mode_is_set(channel->mode, mode); +} + /* Parse channel mode string */ -void parse_channel_modes(CHANNEL_REC *channel, const char *setby, const char *mode) +void parse_channel_modes(CHANNEL_REC *channel, const char *setby, + const char *mode) { - char *dup, *modestr, *ptr, *curmode, type; + GString *newmode; + char *dup, *modestr, *arg, *curmode, type; g_return_if_fail(channel != NULL); - g_return_if_fail(setby != NULL); g_return_if_fail(mode != NULL); type = '+'; + newmode = g_string_new(channel->mode); dup = modestr = g_strdup(mode); curmode = cmd_get_param(&modestr); while (*curmode != '\0') { + if (HAS_MODE_ARG(type, *curmode)) { + /* get the argument for the mode. since we're + expecting argument, ignore the mode if there's + no argument (shouldn't happen). */ + arg = cmd_get_param(&modestr); + if (*arg == '\0') + continue; + } else { + arg = NULL; + } + switch (*curmode) { case '+': case '-': @@ -65,98 +213,50 @@ void parse_channel_modes(CHANNEL_REC *channel, const char *setby, const char *mo break; case 'b': - ptr = cmd_get_param(&modestr); - if (*ptr == '\0') break; - if (type == '+') - banlist_add(channel, ptr, setby, time(NULL)); + banlist_add(channel, arg, setby, time(NULL)); else - banlist_remove(channel, ptr); + banlist_remove(channel, arg); break; - case 'e': - ptr = cmd_get_param(&modestr); - if (*ptr == '\0') break; - if (type == '+') - banlist_exception_add(channel, ptr, setby, time(NULL)); + banlist_exception_add(channel, arg, setby, + time(NULL)); else - banlist_exception_remove(channel, ptr); + banlist_exception_remove(channel, arg); break; - case 'I': - ptr = cmd_get_param(&modestr); - if (*ptr == '\0') break; - if (type == '+') - invitelist_add(channel, ptr); + invitelist_add(channel, arg); else - invitelist_remove(channel, ptr); - break; - - case 'v': - ptr = cmd_get_param(&modestr); - if (*ptr != '\0') - nick_mode_change(channel, ptr, '+', type == '+'); + invitelist_remove(channel, arg); break; case 'o': - ptr = cmd_get_param(&modestr); - if (*ptr == '\0') break; - - if (g_strcasecmp(channel->server->nick, ptr) == 0) - channel->chanop = type == '+' ? TRUE : FALSE; - nick_mode_change(channel, ptr, '@', type == '+'); + if (g_strcasecmp(channel->server->nick, arg) == 0) + channel->chanop = type == '+'; + nick_mode_change(channel, arg, '@', type); + break; + case 'h': + nick_mode_change(channel, arg, '%', type); + break; + case 'v': + nick_mode_change(channel, arg, '+', type); break; case 'l': - if (type == '-') - channel->limit = 0; - else { - ptr = cmd_get_param(&modestr); - sscanf(ptr, "%d", &channel->limit); - } - signal_emit("channel mode changed", 1, channel); + mode_set_arg(newmode, type, 'l', arg); + channel->limit = type == '-' ? 0 : atoi(arg); break; case 'k': - ptr = cmd_get_param(&modestr); - if (*ptr != '\0' || type == '-') { - g_free_and_null(channel->key); - channel->mode_key = type == '+'; - if (type == '+') - channel->key = g_strdup(ptr); - } - signal_emit("channel mode changed", 1, channel); + mode_set_arg(newmode, type, 'k', arg); + g_free_and_null(channel->key); + if (type == '+') + channel->key = g_strdup(arg); break; default: - switch (*curmode) { - case 'i': - channel->mode_invite = type == '+'; - break; - case 'm': - channel->mode_moderate = type == '+'; - break; - case 's': - channel->mode_secret = type == '+'; - break; - case 'p': - channel->mode_private = type == '+'; - break; - case 'n': - channel->mode_nomsgs = type == '+'; - break; - case 't': - channel->mode_optopic = type == '+'; - break; - case 'a': - channel->mode_anonymous = type == '+'; - break; - case 'r': - channel->mode_reop = type == '+'; - break; - } - signal_emit("channel mode changed", 1, channel); + mode_set(newmode, type, *curmode); break; } @@ -164,52 +264,57 @@ void parse_channel_modes(CHANNEL_REC *channel, const char *setby, const char *mo } g_free(dup); - if (!channel->mode_key && channel->key != NULL) { + if (strchr(channel->mode, 'k') == NULL && channel->key != NULL) { /* join was used with key but there's no key set in channel modes.. */ g_free(channel->key); channel->key = NULL; } -} -static int compare_char(const void *p1, const void *p2) -{ - const char *c1 = p1, *c2 = p2; + if (strcmp(newmode->str, channel->mode) != 0) { + g_free(channel->mode); + channel->mode = g_strdup(newmode->str); - return *c1 < *c2 ? -1 : - (*c1 > *c2 ? 1 : 0); + signal_emit("channel mode changed", 1, channel); + } + + g_string_free(newmode, TRUE); } /* add `mode' to `old' - return newly allocated mode. */ char *modes_join(const char *old, const char *mode) { GString *newmode; - char type, *p; + char *dup, *modestr, *curmode, type; g_return_val_if_fail(mode != NULL, NULL); type = '+'; newmode = g_string_new(old); - while (*mode != '\0' && *mode != ' ') { - if (*mode == '+' || *mode == '-') { - type = *mode; - } else { - p = strchr(newmode->str, *mode); - if (type == '+' && p == NULL) - g_string_append_c(newmode, *mode); - else if (type == '-' && p != NULL) - g_string_erase(newmode, (int) (p-newmode->str), 1); + dup = modestr = g_strdup(mode); + curmode = cmd_get_param(&modestr); + while (*curmode != '\0' && *curmode != ' ') { + if (*curmode == '+' || *curmode == '-') { + type = *curmode; + curmode++; + continue; } - mode++; - } + if (!HAS_MODE_ARG(type, *curmode)) + mode_set(newmode, type, *curmode); + else { + mode_set_arg(newmode, type, *curmode, + cmd_get_param(&modestr)); + } - qsort(newmode->str, sizeof(char), newmode->len, compare_char); + curmode++; + } + g_free(dup); - p = newmode->str; + modestr = newmode->str; g_string_free(newmode, FALSE); - return p; + return modestr; } /* Parse user mode string */ @@ -280,7 +385,8 @@ static void event_unaway(const char *data, IRC_SERVER_REC *server) signal_emit("away mode changed", 1, server); } -void channel_set_singlemode(IRC_SERVER_REC *server, const char *channel, const char *nicks, const char *mode) +void channel_set_singlemode(IRC_SERVER_REC *server, const char *channel, + const char *nicks, const char *mode) { GString *str; int num, modepos; @@ -323,9 +429,10 @@ void channel_set_singlemode(IRC_SERVER_REC *server, const char *channel, const c g_string_free(str, TRUE); } -void channel_set_mode(IRC_SERVER_REC *server, const char *channel, const char *mode) +void channel_set_mode(IRC_SERVER_REC *server, const char *channel, + const char *mode) { - char *modestr, *curmode, *orig; + char *modestr, *curmode, *orig, type; GString *tmode, *targs; int count; @@ -339,9 +446,14 @@ void channel_set_mode(IRC_SERVER_REC *server, const char *channel, const char *m orig = modestr = g_strdup(mode); + type = '+'; curmode = cmd_get_param(&modestr); for (; *curmode != '\0'; curmode++) { - if (count == server->max_modes_in_cmd && HAS_MODE_ARG(*curmode)) { + if (*curmode == '+' || *curmode == '-') + type = *curmode; + + if (count == server->max_modes_in_cmd && + HAS_MODE_ARG(type, *curmode)) { irc_send_cmdv(server, "MODE %s %s%s", channel, tmode->str, targs->str); count = 0; @@ -351,7 +463,7 @@ void channel_set_mode(IRC_SERVER_REC *server, const char *channel, const char *m g_string_append_c(tmode, *curmode); - if (HAS_MODE_ARG(*curmode)) { + if (HAS_MODE_ARG(type, *curmode)) { char *arg; count++; diff --git a/src/irc/core/modes.h b/src/irc/core/modes.h index d72e6a3c..d175c083 100644 --- a/src/irc/core/modes.h +++ b/src/irc/core/modes.h @@ -4,8 +4,21 @@ #include "server.h" #include "channels.h" -#define HAS_MODE_ARG(c) ((c) == 'b' || (c) == 'e' || (c) == 'I' || \ - (c) == 'v' || (c) == 'o' || (c) == 'l' || (c) == 'k') +/* modes that have argument always */ +#define HAS_MODE_ARG_ALWAYS(mode) \ + ((mode) == 'b' || (mode) == 'e' || (mode) == 'I' || \ + (mode) == 'o' || (mode) == 'h' || (mode) == 'v' || (mode) == 'k') + +/* modes that have argument when being set (+) */ +#define HAS_MODE_ARG_SET(mode) \ + (HAS_MODE_ARG_ALWAYS(mode) || (mode) == 'l') + +/* modes that have argument when being unset (-) */ +#define HAS_MODE_ARG_UNSET(mode) \ + HAS_MODE_ARG_ALWAYS(mode) + +#define HAS_MODE_ARG(type, mode) \ + ((type) == '+' ? HAS_MODE_ARG_SET(mode) : HAS_MODE_ARG_UNSET(mode)) void modes_init(void); void modes_deinit(void); @@ -13,9 +26,14 @@ void modes_deinit(void); /* add `mode' to `old' - return newly allocated mode. */ char *modes_join(const char *old, const char *mode); -void parse_channel_modes(CHANNEL_REC *channel, const char *setby, const char *modestr); +int channel_mode_is_set(CHANNEL_REC *channel, char mode); + +void parse_channel_modes(CHANNEL_REC *channel, const char *setby, + const char *modestr); -void channel_set_singlemode(IRC_SERVER_REC *server, const char *channel, const char *nicks, const char *mode); -void channel_set_mode(IRC_SERVER_REC *server, const char *channel, const char *mode); +void channel_set_singlemode(IRC_SERVER_REC *server, const char *channel, + const char *nicks, const char *mode); +void channel_set_mode(IRC_SERVER_REC *server, const char *channel, + const char *mode); #endif diff --git a/src/irc/core/nicklist.c b/src/irc/core/nicklist.c index ec9dc1ab..0143ca6d 100644 --- a/src/irc/core/nicklist.c +++ b/src/irc/core/nicklist.c @@ -25,11 +25,13 @@ #include "channels.h" #include "irc.h" #include "masks.h" +#include "modes.h" #include "nicklist.h" #include "irc-server.h" /* Add new nick to list */ -NICK_REC *nicklist_insert(CHANNEL_REC *channel, const char *nick, int op, int voice, int send_massjoin) +NICK_REC *nicklist_insert(CHANNEL_REC *channel, const char *nick, + int op, int voice, int send_massjoin) { NICK_REC *rec; @@ -70,7 +72,8 @@ void nicklist_remove(CHANNEL_REC *channel, NICK_REC *nick) nicklist_destroy(channel, nick); } -static NICK_REC *nicklist_find_wildcards(CHANNEL_REC *channel, const char *mask) +static NICK_REC *nicklist_find_wildcards(CHANNEL_REC *channel, + const char *mask) { GSList *nicks, *tmp; NICK_REC *nick; @@ -80,7 +83,7 @@ static NICK_REC *nicklist_find_wildcards(CHANNEL_REC *channel, const char *mask) for (tmp = nicks; tmp != NULL; tmp = tmp->next) { nick = tmp->data; - if (irc_mask_match_address(mask, nick->nick, nick->host == NULL ? "" : nick->host)) + if (irc_mask_match_address(mask, nick->nick, nick->host)) break; } g_slist_free(nicks); @@ -96,7 +99,7 @@ GSList *nicklist_find_multiple(CHANNEL_REC *channel, const char *mask) NICK_REC *nick = tmp->data; next = tmp->next; - if (!irc_mask_match_address(mask, nick->nick, nick->host == NULL ? "" : nick->host)) + if (!irc_mask_match_address(mask, nick->nick, nick->host)) nicks = g_slist_remove(nicks, tmp->data); } @@ -170,7 +173,8 @@ GSList *nicklist_get_same(IRC_SERVER_REC *server, const char *nick) rec.list = NULL; for (tmp = server->channels; tmp != NULL; tmp = tmp->next) { rec.channel = tmp->data; - g_hash_table_foreach(rec.channel->nicks, (GHFunc) get_nicks_same_hash, &rec); + g_hash_table_foreach(rec.channel->nicks, + (GHFunc) get_nicks_same_hash, &rec); } return rec.list; } @@ -224,8 +228,9 @@ int irc_nick_match(const char *nick, const char *msg) g_return_val_if_fail(nick != NULL, FALSE); g_return_val_if_fail(msg != NULL, FALSE); - if (g_strncasecmp(msg, nick, strlen(nick)) == 0 && - !isalnum((int) msg[strlen(nick)])) return TRUE; + len = strlen(nick); + if (g_strncasecmp(msg, nick, len) == 0 && !isalnum((int) msg[len])) + return TRUE; stripnick = nick_strip(nick); stripmsg = nick_strip(msg); @@ -262,9 +267,9 @@ static void event_names_list(const char *data, IRC_SERVER_REC *server) get to know if the channel is +p or +s a few seconds before we receive the MODE reply... */ if (*type == '*') - chanrec->mode_private = TRUE; + parse_channel_modes(chanrec, NULL, "+p"); else if (*type == '@') - chanrec->mode_secret = TRUE; + parse_channel_modes(chanrec, NULL, "+s"); while (*names != '\0') { while (*names == ' ') names++; @@ -275,7 +280,8 @@ static void event_names_list(const char *data, IRC_SERVER_REC *server) if (*ptr == '@' && g_strcasecmp(server->nick, ptr+1) == 0) chanrec->chanop = TRUE; - nicklist_insert(chanrec, ptr+isnickflag(*ptr), *ptr == '@', *ptr == '+', FALSE); + nicklist_insert(chanrec, ptr+isnickflag(*ptr), + *ptr == '@', *ptr == '+', FALSE); } g_free(params); @@ -299,7 +305,8 @@ static void event_end_of_names(const char *data, IRC_SERVER_REC *server) g_free(params); } -static void nicklist_update_flags(IRC_SERVER_REC *server, const char *nick, int gone, int ircop) +static void nicklist_update_flags(IRC_SERVER_REC *server, const char *nick, + int gone, int ircop) { GSList *nicks, *tmp; CHANNEL_REC *channel; @@ -336,7 +343,8 @@ static void event_who(const char *data, IRC_SERVER_REC *server) g_return_if_fail(data != NULL); - params = event_get_params(data, 8, NULL, &channel, &user, &host, NULL, &nick, &stat, &realname); + params = event_get_params(data, 8, NULL, &channel, &user, &host, + NULL, &nick, &stat, &realname); /* get hop count */ hops = realname; @@ -372,8 +380,10 @@ static void event_whois(const char *data, IRC_SERVER_REC *server) server->whois_coming = TRUE; - /* first remove the gone-flag, if user is gone it will be set later.. */ - params = event_get_params(data, 6, NULL, &nick, NULL, NULL, NULL, &realname); + /* first remove the gone-flag, if user is gone + it will be set later.. */ + params = event_get_params(data, 6, NULL, &nick, NULL, + NULL, NULL, &realname); nicks = nicklist_get_same(server, nick); for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) { @@ -477,7 +487,8 @@ static void event_target_unavailable(const char *data, IRC_SERVER_REC *server) g_free(params); } -static void event_nick(const char *data, IRC_SERVER_REC *server, const char *orignick) +static void event_nick(const char *data, IRC_SERVER_REC *server, + const char *orignick) { CHANNEL_REC *channel; NICK_REC *nickrec; @@ -550,10 +561,12 @@ static void sig_channel_created(CHANNEL_REC *channel) { g_return_if_fail(channel != NULL); - channel->nicks = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal); + channel->nicks = g_hash_table_new((GHashFunc) g_istr_hash, + (GCompareFunc) g_istr_equal); } -static void nicklist_remove_hash(gpointer key, NICK_REC *nick, CHANNEL_REC *channel) +static void nicklist_remove_hash(gpointer key, NICK_REC *nick, + CHANNEL_REC *channel) { nicklist_destroy(channel, nick); } @@ -562,7 +575,8 @@ static void sig_channel_destroyed(CHANNEL_REC *channel) { g_return_if_fail(channel != NULL); - g_hash_table_foreach(channel->nicks, (GHFunc) nicklist_remove_hash, channel); + g_hash_table_foreach(channel->nicks, + (GHFunc) nicklist_remove_hash, channel); g_hash_table_destroy(channel->nicks); } diff --git a/src/irc/core/nicklist.h b/src/irc/core/nicklist.h index b986be5d..c40ec8cb 100644 --- a/src/irc/core/nicklist.h +++ b/src/irc/core/nicklist.h @@ -15,6 +15,7 @@ typedef struct { int hops; int op:1; + int halfop:1; int voice:1; int gone:1; int ircop:1; diff --git a/src/perl/xs/Irssi-channel.xs b/src/perl/xs/Irssi-channel.xs index 62d5892e..8f14ebc9 100644 --- a/src/perl/xs/Irssi-channel.xs +++ b/src/perl/xs/Irssi-channel.xs @@ -76,6 +76,7 @@ PPCODE: hv_store(hv, "createtime", 10, newSViv(channel->createtime), 0); hv_store(hv, "topic", 5, new_pv(channel->topic), 0); + hv_store(hv, "mode", 4, new_pv(channel->mode), 0); hv_store(hv, "limit", 5, newSViv(channel->limit), 0); hv_store(hv, "key", 3, new_pv(channel->key), 0); @@ -109,10 +110,6 @@ command(channel, cmd) CODE: signal_emit("send command", 3, cmd, channel->server, channel); -char * -channel_get_mode(channel) - Irssi::Channel channel - Irssi::Nick nicklist_insert(channel, nick, op, voice, send_massjoin) Irssi::Channel channel |