From 89cd47bf3a937c3077acdc95d98cc4b389e30608 Mon Sep 17 00:00:00 2001 From: Jilles Tjoelker Date: Fri, 28 Nov 2008 00:16:51 +0000 Subject: Allow storing multiple "other" prefixes such as +q and +a. Original patch by JasonX, somewhat changed by exg and me. git-svn-id: file:///var/www/svn.irssi.org/SVN/irssi/trunk@4922 dbcabf3a-b0e7-0310-adc4-f8d773084564 --- src/core/nick-rec.h | 2 +- src/core/nicklist.c | 50 ++++++++++++---------------------- src/core/nicklist.h | 2 ++ src/core/session.c | 5 +--- src/fe-common/core/fe-channels.c | 10 ++----- src/fe-common/core/fe-messages.c | 12 +++----- src/irc/core/irc-expandos.c | 18 ++++-------- src/irc/core/irc-nicklist.c | 14 +++++----- src/irc/core/irc-session.c | 6 ++-- src/irc/core/modes.c | 59 ++++++++++++++++++++++++++++++++++++++-- src/irc/core/modes.h | 3 ++ src/irc/core/netsplit.c | 2 +- src/irc/core/netsplit.h | 2 +- src/irc/proxy/dump.c | 10 ++----- src/perl/perl-common.c | 3 +- 15 files changed, 110 insertions(+), 88 deletions(-) diff --git a/src/core/nick-rec.h b/src/core/nick-rec.h index aaedded9..1463f9f3 100644 --- a/src/core/nick-rec.h +++ b/src/core/nick-rec.h @@ -19,7 +19,7 @@ unsigned int send_massjoin:1; /* Waiting to be sent in massjoin signal */ unsigned int op:1; unsigned int halfop:1; unsigned int voice:1; -char other; +char prefixes[MAX_USER_PREFIXES+1]; /*GHashTable *module_data;*/ diff --git a/src/core/nicklist.c b/src/core/nicklist.c index 28665ddd..9f67f20b 100644 --- a/src/core/nicklist.c +++ b/src/core/nicklist.c @@ -359,45 +359,31 @@ GSList *nicklist_get_same_unique(SERVER_REC *server, void *id) /* nick record comparision for sort functions */ int nicklist_compare(NICK_REC *p1, NICK_REC *p2, const char *nick_prefix) { - int status1, status2; + int i; if (p1 == NULL) return -1; if (p2 == NULL) return 1; - /* we assign each status (op, halfop, voice, normal) a number - * and compare them. this is easier than 100,000 if's and - * returns :-) - * -- yath */ - - if (p1->other) { - const char *other = (nick_prefix == NULL) ? NULL : strchr(nick_prefix, p1->other); - status1 = (other == NULL) ? 5 : 1000 - (other - nick_prefix); - } else if (p1->op) - status1 = 4; - else if (p1->halfop) - status1 = 3; - else if (p1->voice) - status1 = 2; - else - status1 = 1; - - if (p2->other) { - const char *other = (nick_prefix == NULL) ? NULL : strchr(nick_prefix, p2->other); - status2 = (other == NULL) ? 5 : 1000 - (other - nick_prefix); - } else if (p2->op) - status2 = 4; - else if (p2->halfop) - status2 = 3; - else if (p2->voice) - status2 = 2; - else - status2 = 1; - - if (status1 < status2) + if (p1->prefixes[0] == p2->prefixes[0]) + return g_strcasecmp(p1->nick, p2->nick); + + if (!p1->prefixes[0]) return 1; - else if (status1 > status2) + if (!p2->prefixes[0]) return -1; + /* They aren't equal. We've taken care of that already. + * The first one we encounter in this list is the greater. + */ + + for (i = 0; nick_prefix[i] != '\0'; i++) { + if (p1->prefixes[0] == nick_prefix[i]) + return -1; + if (p2->prefixes[0] == nick_prefix[i]) + return 1; + } + + /* we should never have gotten here... */ return g_strcasecmp(p1->nick, p2->nick); } diff --git a/src/core/nicklist.h b/src/core/nicklist.h index 7712af65..55dfd5ef 100644 --- a/src/core/nicklist.h +++ b/src/core/nicklist.h @@ -8,6 +8,8 @@ #define IS_NICK(server) \ (NICK(server) ? TRUE : FALSE) +#define MAX_USER_PREFIXES 7 /* Max prefixes kept for any user-in-chan. 7+1 is a memory unit */ + struct _NICK_REC { #include "nick-rec.h" }; diff --git a/src/core/session.c b/src/core/session.c index 75b44b3d..5eb5270b 100644 --- a/src/core/session.c +++ b/src/core/session.c @@ -91,7 +91,6 @@ static void cmd_upgrade(const char *data) static void session_save_nick(CHANNEL_REC *channel, NICK_REC *nick, CONFIG_REC *config, CONFIG_NODE *node) { - static char other[2]; node = config_node_section(node, NULL, NODE_TYPE_BLOCK); config_node_set_str(config, node, "nick", nick->nick); @@ -99,9 +98,7 @@ static void session_save_nick(CHANNEL_REC *channel, NICK_REC *nick, config_node_set_bool(config, node, "halfop", nick->halfop); config_node_set_bool(config, node, "voice", nick->voice); - other[0] = nick->other; - other[1] = '\0'; - config_node_set_str(config, node, "other", other); + config_node_set_str(config, node, "prefixes", nick->prefixes); signal_emit("session save nick", 4, channel, nick, config, node); } diff --git a/src/fe-common/core/fe-channels.c b/src/fe-common/core/fe-channels.c index a3325ef8..cc6f200f 100644 --- a/src/fe-common/core/fe-channels.c +++ b/src/fe-common/core/fe-channels.c @@ -413,14 +413,8 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist) for (tmp = nicklist; tmp != NULL; tmp = tmp->next) { NICK_REC *rec = tmp->data; - if (rec->other) - nickmode[0] = rec->other; - else if (rec->op) - nickmode[0] = '@'; - else if (rec->halfop) - nickmode[0] = '%'; - else if (rec->voice) - nickmode[0] = '+'; + if (rec->prefixes[0]) + nickmode[0] = rec->prefixes[0]; else nickmode[0] = ' '; diff --git a/src/fe-common/core/fe-messages.c b/src/fe-common/core/fe-messages.c index a5bcd2b0..1035c7bb 100644 --- a/src/fe-common/core/fe-messages.c +++ b/src/fe-common/core/fe-messages.c @@ -140,17 +140,13 @@ static char *channel_get_nickmode_rec(NICK_REC *nickrec) emptystr = settings_get_bool("show_nickmode_empty") ? " " : ""; - if (nickrec == NULL) + if (nickrec == NULL || nickrec->prefixes[0] == '\0') nickmode = g_strdup(emptystr); - else if (nickrec->other) { + else { nickmode = g_malloc(2); - nickmode[0] = nickrec->other; + nickmode[0] = nickrec->prefixes[0]; nickmode[1] = '\0'; - } else - nickmode = g_strdup(nickrec->op ? "@" : - nickrec->halfop ? "%" : - nickrec->voice ? "+" : - emptystr); + } return nickmode; } diff --git a/src/irc/core/irc-expandos.c b/src/irc/core/irc-expandos.c index 901edc6a..0c0da643 100644 --- a/src/irc/core/irc-expandos.c +++ b/src/irc/core/irc-expandos.c @@ -86,18 +86,12 @@ static char *expando_usermode(SERVER_REC *server, void *item, int *free_ret) static char *expando_cumode(SERVER_REC *server, void *item, int *free_ret) { if (IS_IRC_CHANNEL(item) && CHANNEL(item)->ownnick) { - char other = NICK(CHANNEL(item)->ownnick)->other; - if (other != '\0') { - char *cumode = g_malloc(2); - cumode[0] = other; - cumode[1] = '\0'; - *free_ret = TRUE; - return cumode; - } - - return NICK(CHANNEL(item)->ownnick)->op ? "@" : - NICK(CHANNEL(item)->ownnick)->halfop ? "%" : - NICK(CHANNEL(item)->ownnick)->voice ? "+" : ""; + char prefix = NICK(CHANNEL(item)->ownnick)->prefixes[0]; + char *cumode = g_malloc(2); + cumode[0] = prefix; + cumode[1] = '\0'; + *free_ret = TRUE; + return cumode; /* will be "\0\0" = "" if there is no prefix */ } return ""; } diff --git a/src/irc/core/irc-nicklist.c b/src/irc/core/irc-nicklist.c index 7d97196f..81bb6cfe 100644 --- a/src/irc/core/irc-nicklist.c +++ b/src/irc/core/irc-nicklist.c @@ -99,7 +99,8 @@ static void event_names_list(IRC_SERVER_REC *server, const char *data) IRC_CHANNEL_REC *chanrec; NICK_REC *rec; char *params, *type, *channel, *names, *ptr; - int op, halfop, voice, other; + int op, halfop, voice; + char prefixes[MAX_USER_PREFIXES+1]; g_return_if_fail(data != NULL); @@ -137,9 +138,11 @@ static void event_names_list(IRC_SERVER_REC *server, const char *data) /* some servers show ".@nick", there's also been talk about showing "@+nick" and since none of these chars are valid nick chars, just check them until a non-nickflag char is - found. FIXME: we just ignore owner char now. */ - op = halfop = voice = other = FALSE; + found. */ + op = halfop = voice = FALSE; + prefixes[0] = '\0'; while (isnickflag(server, *ptr)) { + prefix_add(prefixes, *ptr, (SERVER_REC *) server); switch (*ptr) { case '@': op = TRUE; @@ -150,8 +153,6 @@ static void event_names_list(IRC_SERVER_REC *server, const char *data) case '+': voice = TRUE; break; - default: - other = *ptr; } ptr++; } @@ -159,8 +160,7 @@ static void event_names_list(IRC_SERVER_REC *server, const char *data) if (nicklist_find((CHANNEL_REC *) chanrec, ptr) == NULL) { rec = irc_nicklist_insert(chanrec, ptr, op, halfop, voice, FALSE); - if (other) - rec->other = other; + memcpy(rec->prefixes, prefixes, sizeof(rec->prefixes)); } } diff --git a/src/irc/core/irc-session.c b/src/irc/core/irc-session.c index ac2b0a07..5cd5cc43 100644 --- a/src/irc/core/irc-session.c +++ b/src/irc/core/irc-session.c @@ -114,7 +114,6 @@ static void sig_session_restore_nick(IRC_CHANNEL_REC *channel, CONFIG_NODE *node) { const char *nick; - char *other; int op, halfop, voice; NICK_REC *nickrec; @@ -129,8 +128,9 @@ static void sig_session_restore_nick(IRC_CHANNEL_REC *channel, voice = config_node_get_bool(node, "voice", FALSE); halfop = config_node_get_bool(node, "halfop", FALSE); nickrec = irc_nicklist_insert(channel, nick, op, halfop, voice, FALSE); - other = config_node_get_str(node, "other", NULL); - nickrec->other = other == NULL ? '\0' : other[0]; + strocpy(nickrec->prefixes, + config_node_get_str(node, "prefixes", ""), + sizeof(nickrec->prefixes)); } static void session_restore_channel(IRC_CHANNEL_REC *channel) diff --git a/src/irc/core/modes.c b/src/irc/core/modes.c index 994a55f3..5c4a45da 100644 --- a/src/irc/core/modes.c +++ b/src/irc/core/modes.c @@ -46,8 +46,12 @@ static void nick_mode_change(IRC_CHANNEL_REC *channel, const char *nick, if (mode == '@') nickrec->op = type == '+'; else if (mode == '+') nickrec->voice = type == '+'; else if (mode == '%') nickrec->halfop = type == '+'; - else if (channel->server->prefix[(unsigned char) mode] != '\0') - nickrec->other = (type == '+' ? mode : '\0'); + if (channel->server->prefix[(unsigned char) mode] != '\0') { + if (type == '+') + prefix_add(nickrec->prefixes, mode, (SERVER_REC *) channel->server); + else + prefix_del(nickrec->prefixes, mode); + } modestr[0] = mode; modestr[1] = '\0'; typestr[0] = type; typestr[1] = '\0'; @@ -55,6 +59,57 @@ static void nick_mode_change(IRC_CHANNEL_REC *channel, const char *nick, channel, nickrec, setby, modestr, typestr); } +void prefix_add(char *prefixes, char newprefix, SERVER_REC *server) +{ + const char *prefixlst; + char newprefixes[MAX_USER_PREFIXES+1]; /* to hold the new prefixes */ + unsigned int newpos = 0; /* to hold our position in the new prefixes */ + unsigned int oldpos = 0; /* to hold our position in the old prefixes */ + + prefixlst = server->get_nick_flags(server); + + /* go through the possible prefixes, copy higher ones, and find this one's place + * always leave room for the current prefix to be added, though. + */ + while (*prefixlst != '\0' && prefixes[oldpos] != '\0' && + newpos < MAX_USER_PREFIXES - 1) { + if (prefixes[oldpos] == newprefix) + return; /* already inserted. why are we here? */ + + if (*prefixlst == newprefix) + break; /* insert the new prefix here */ + + if (*prefixlst == prefixes[oldpos]) { + /* this prefix is present. + * the one we are inserting goes after it. + * copy it over, and continue searching. + */ + newprefixes[newpos++] = prefixes[oldpos++]; + } + prefixlst++; + } + + /* newpos is now the position in which we wish to insert the prefix */ + newprefixes[newpos++] = newprefix; + + /* finish copying the remaining prefixes */ + while (prefixes[oldpos] != '\0' && newpos < MAX_USER_PREFIXES) + newprefixes[newpos++] = prefixes[oldpos++]; + + newprefixes[newpos] = '\0'; + + memcpy(prefixes, newprefixes, sizeof(prefixes)); +} + +void prefix_del(char *prefixes, char oldprefix) +{ + char *todel; + + todel = strchr(prefixes, oldprefix); + if (todel) + memmove(todel, todel+1, strlen(todel)); +} + static int mode_is_set(const char *str, char mode) { char *end, *pos; diff --git a/src/irc/core/modes.h b/src/irc/core/modes.h index 70b19042..e9326c7a 100644 --- a/src/irc/core/modes.h +++ b/src/irc/core/modes.h @@ -54,6 +54,9 @@ void channel_set_singlemode(IRC_CHANNEL_REC *channel, const char *nicks, void channel_set_mode(IRC_SERVER_REC *server, const char *channel, const char *mode); +void prefix_add(char *prefixes, char newprefix, SERVER_REC *server); +void prefix_del(char *prefixes, char oldprefix); + mode_func_t modes_type_a; mode_func_t modes_type_b; mode_func_t modes_type_c; diff --git a/src/irc/core/netsplit.c b/src/irc/core/netsplit.c index 51f3a630..269d2556 100644 --- a/src/irc/core/netsplit.c +++ b/src/irc/core/netsplit.c @@ -135,7 +135,7 @@ static NETSPLIT_REC *netsplit_add(IRC_SERVER_REC *server, const char *nick, splitchan->op = nickrec->op; splitchan->halfop = nickrec->halfop; splitchan->voice = nickrec->voice; - splitchan->other = nickrec->other; + memcpy(splitchan->prefixes, nickrec->prefixes, sizeof(splitchan->prefixes)); rec->channels = g_slist_append(rec->channels, splitchan); } diff --git a/src/irc/core/netsplit.h b/src/irc/core/netsplit.h index 23e6d636..cbe3f26f 100644 --- a/src/irc/core/netsplit.h +++ b/src/irc/core/netsplit.h @@ -28,7 +28,7 @@ typedef struct { unsigned int op:1; unsigned int halfop:1; unsigned int voice:1; - unsigned int other:7; + char prefixes[MAX_USER_PREFIXES+1]; } NETSPLIT_CHAN_REC; void netsplit_init(void); diff --git a/src/irc/proxy/dump.c b/src/irc/proxy/dump.c index a7a996d5..5829023d 100644 --- a/src/irc/proxy/dump.c +++ b/src/irc/proxy/dump.c @@ -180,14 +180,8 @@ static void dump_join(IRC_CHANNEL_REC *channel, CLIENT_REC *client) else g_string_append_c(str, ' '); - if (nick->other) - g_string_append_c(str, nick->other); - else if (nick->op) - g_string_append_c(str, '@'); - else if (nick->halfop) - g_string_append_c(str, '%'); - else if (nick->voice) - g_string_append_c(str, '+'); + if (nick->prefixes[0]) + g_string_append_c(str, nick->prefixes[0]); g_string_append(str, nick->nick); } g_slist_free(nicks); diff --git a/src/perl/perl-common.c b/src/perl/perl-common.c index 517e6102..e13c2cf3 100644 --- a/src/perl/perl-common.c +++ b/src/perl/perl-common.c @@ -432,7 +432,8 @@ void perl_nick_fill_hash(HV *hv, NICK_REC *nick) hv_store(hv, "op", 2, newSViv(nick->op), 0); hv_store(hv, "halfop", 6, newSViv(nick->halfop), 0); hv_store(hv, "voice", 5, newSViv(nick->voice), 0); - hv_store(hv, "other", 5, newSViv(nick->other), 0); + hv_store(hv, "other", 5, newSViv(nick->prefixes[0]), 0); + hv_store(hv, "prefixes", 8, new_pv(nick->prefixes), 0); hv_store(hv, "last_check", 10, newSViv(nick->last_check), 0); hv_store(hv, "send_massjoin", 13, newSViv(nick->send_massjoin), 0); -- cgit v1.2.3