From: Michael Poole Date: Thu, 7 Jan 2010 02:33:21 +0000 (-0500) Subject: Send oplevels correctly during a burst. X-Git-Url: http://git.pk910.de/?p=srvx.git;a=commitdiff_plain;h=2167d030c80b34f9f9cc0e2235edf47d64ce2500 Send oplevels correctly during a burst. src/hash.c (AddChannelUser): Initialize oplevel to the maximum, not -1. src/proto-p10.c (parse_oplevel): Move up for easier inlining. (modeNode_sort): New function. (irc_burst): Use it to sort the membership list for channels so the members' oplevels can be sent correctly. (cmd_burst): Simplify the handling of oplevels. (mod_chanmode_parse): Only change the member's oplevel when opping or deopping -- otherwise +v would set it to MAXOPLEVEL! --- diff --git a/src/hash.c b/src/hash.c index a4dd6fb..75769fa 100644 --- a/src/hash.c +++ b/src/hash.c @@ -485,7 +485,7 @@ AddChannelUser(struct userNode *user, struct chanNode* channel) mNode->channel = channel; mNode->user = user; mNode->modes = 0; - mNode->oplevel = -1; + mNode->oplevel = MAXOPLEVEL; mNode->idle_since = now; /* Add modeNode to channel and to user. diff --git a/src/proto-p10.c b/src/proto-p10.c index bd86885..86cd335 100644 --- a/src/proto-p10.c +++ b/src/proto-p10.c @@ -299,7 +299,17 @@ static struct userNode *AddUser(struct server* uplink, const char *nick, const c extern int off_channel; -static int parse_oplevel(char *str); +/* + * Oplevel parsing + */ +static int +parse_oplevel(char *str) +{ + int oplevel = 0; + while (isdigit(*str)) + oplevel = oplevel * 10 + *str++ - '0'; + return oplevel; +} /* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the * server and Y's indentifying the client on that server. */ @@ -666,6 +676,32 @@ irc_ungline(const char *mask) putsock("%s " P10_GLINE " * -%s", self->numeric, mask); } +/* Return negative if *(struct modeNode**)pa is "less than" pb, + * positive if pa is "larger than" pb. Comparison is based on sorting + * so that non-voiced/non-opped users are first, voiced-only users are + * next, and the "strongest" oplevels are before "weaker" oplevels. + * Within those sets, ordering is arbitrary. + */ +static int +modeNode_sort(const void *pa, const void *pb) +{ + struct modeNode *a = *(struct modeNode**)pa; + struct modeNode *b = *(struct modeNode**)pb; + + if (a->modes & MODE_CHANOP) { + if (!(b->modes & MODE_CHANOP)) + return 1; + else if ((a->modes & MODE_VOICE) != (b->modes & MODE_VOICE)) + return (a->modes & MODE_VOICE) - (b->modes & MODE_VOICE); + else if (a->oplevel != b->oplevel) + return a->oplevel - b->oplevel; + } else if (b->modes & MODE_CHANOP) + return -1; + else if ((a->modes & MODE_VOICE) != (b->modes & MODE_VOICE)) + return (a->modes & MODE_VOICE) - (b->modes & MODE_VOICE); + return (a < b) ? -1 : 1; +} + static void irc_burst(struct chanNode *chan) { @@ -673,7 +709,9 @@ irc_burst(struct chanNode *chan) int pos, base_len, len; struct modeNode *mn; struct banNode *bn; - long last_mode=-1; + int last_oplevel = 0; + int last_mode = 0; + int new_modes; unsigned int first_ban; unsigned int n; @@ -685,6 +723,9 @@ irc_burst(struct chanNode *chan) if (len > 0 && chan->members.used > 0) burst_line[pos++] = ' '; + /* sort the users for oplevel-sending purposes */ + qsort(chan->members.list, chan->members.used, sizeof(chan->members.list[0]), modeNode_sort); + /* dump the users */ for (n=0; nmembers.used; n++) { mn = chan->members.list[n]; @@ -692,17 +733,32 @@ irc_burst(struct chanNode *chan) burst_line[pos-1] = 0; /* -1 to back up over the space or comma */ putsock("%s", burst_line); pos = base_len; - last_mode = -1; + last_mode = 0; + last_oplevel = 0; } memcpy(burst_line+pos, mn->user->numeric, strlen(mn->user->numeric)); pos += strlen(mn->user->numeric); - if (mn->modes && (mn->modes != last_mode)) { - last_mode = mn->modes; + new_modes = mn->modes & (MODE_CHANOP | MODE_VOICE); + if (new_modes != last_mode) { + last_mode = new_modes; burst_line[pos++] = ':'; - if (last_mode & MODE_CHANOP) - burst_line[pos++] = 'o'; - if (last_mode & MODE_VOICE) + if (new_modes & MODE_VOICE) burst_line[pos++] = 'v'; + /* Note: :vNNN (oplevel NNN with voice) resets the + * implicit oplevel back to zero, so we always use the raw + * oplevel value here. Read ircu's m_burst.c for more + * examples. + */ + if (new_modes & MODE_CHANOP) { + last_oplevel = mn->oplevel; + if (mn->oplevel < MAXOPLEVEL) + pos += sprintf(burst_line + pos, "%u", mn->oplevel); + else + burst_line[pos++] = 'o'; + } + } else if ((last_mode & MODE_CHANOP) && (mn->oplevel != last_oplevel)) { + pos += sprintf(burst_line + pos, ":%u", mn->oplevel - last_oplevel); + last_oplevel = mn->oplevel; } if ((n+1)members.used) burst_line[pos++] = ','; @@ -1204,7 +1260,7 @@ static CMD_FUNC(cmd_burst) struct userNode *un; struct modeNode *mNode; long mode; - int oplevel = -1; + int oplevel = 0; char *user, *end, sep; unsigned long in_timestamp; @@ -1248,16 +1304,13 @@ static CMD_FUNC(cmd_burst) while ((sep = *end++)) { if (sep == 'o') { mode |= MODE_CHANOP; - oplevel = -1; + oplevel = MAXOPLEVEL; } else if (sep == 'v') { mode |= MODE_VOICE; - oplevel = -1; + oplevel = 0; } else if (isdigit(sep)) { mode |= MODE_CHANOP; - if (oplevel >= 0) - oplevel += parse_oplevel(end); - else - oplevel = parse_oplevel(end); + oplevel += parse_oplevel(end - 1); while (isdigit(*end)) end++; } else break; @@ -2409,7 +2462,7 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un else if (channel->modes & MODE_UPASS) oplevel = base_oplevel + 1; else - oplevel = -1; + oplevel = MAXOPLEVEL; /* Check that oplevel is within bounds. */ if (oplevel > MAXOPLEVEL) @@ -2430,8 +2483,9 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un continue; if ((change->args[ch_arg].u.member = GetUserMode(channel, victim))) { - /* Apply the oplevel change */ - change->args[ch_arg].u.member->oplevel = oplevel; + /* Apply the oplevel change if the user is being (de-)opped */ + if (modes[0][ii] == 'o') + change->args[ch_arg].u.member->oplevel = oplevel; ch_arg++; } break; @@ -2848,15 +2902,3 @@ send_burst(void) for (it = dict_first(channels); it; it = iter_next(it)) dict_insert(unbursted_channels, iter_key(it), iter_data(it)); } - -/* - * Oplevel parsing - */ -static int -parse_oplevel(char *str) -{ - int oplevel = 0; - while (isdigit(*str)) - oplevel = oplevel * 10 + *str++ - '0'; - return oplevel; -}