1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-03 22:03:13 +02:00

Get rid of Usermode_Table[] and use a linked list called usermodes.

Just like already done for Channelmode_Table[] -> channelmodes.
This commit is contained in:
Bram Matthys
2021-09-26 12:45:45 +02:00
parent 05f2694685
commit ee8cc0e8e2
11 changed files with 273 additions and 276 deletions
+1
View File
@@ -94,6 +94,7 @@ extern long set_usermode(const char *umode);
extern const char *get_usermode_string(Client *acptr);
extern const char *get_usermode_string_r(Client *client, char *buf, size_t buflen);
extern const char *get_usermode_string_raw(long umodes);
extern const char *get_usermode_string_raw_r(long umodes, char *buf, size_t buflen);
extern ConfigFile *config_parse(const char *filename, char *confdata);
extern ConfigFile *config_parse_with_offset(const char *filename, char *confdata, unsigned int line_offset);
extern void config_error(FORMAT_STRING(const char *format), ...) __attribute__((format(printf,1,2)));
+10 -8
View File
@@ -109,14 +109,16 @@ typedef enum ModuleObjectType {
MOBJ_HISTORY_BACKEND = 18,
} ModuleObjectType;
typedef struct {
long mode; /**< Mode mask */
char letter; /**< Mode character */
int unset_on_deoper; /**< When set to 1 then this user mode will be unset on de-oper */
int (*allowed)(Client *client, int what); /**< The 'is this user allowed to set this mode?' routine */
char unloaded; /**< Internal flag to indicate module is being unloaded */
Module *owner; /**< Module that owns this user mode */
} Umode;
typedef struct Umode Umode;
struct Umode {
Umode *prev, *next;
long mode; /**< Mode mask */
char letter; /**< Mode character */
int unset_on_deoper; /**< When set to 1 then this user mode will be unset on de-oper */
int (*allowed)(Client *client, int what); /**< The 'is this user allowed to set this mode?' routine */
char unloaded; /**< Internal flag to indicate module is being unloaded */
Module *owner; /**< Module that owns this user mode */
};
typedef enum ModDataType {
MODDATATYPE_LOCAL_VARIABLE = 1,
+1 -2
View File
@@ -1191,8 +1191,7 @@ struct CommandOverride {
OverrideCmdFunc func;
};
extern MODVAR Umode *Usermode_Table;
extern MODVAR int Usermode_highest;
extern MODVAR Umode *usermodes;
extern MODVAR Cmode *channelmodes;
extern Umode *UmodeAdd(Module *module, char ch, int options, int unset_on_deoper, int (*allowed)(Client *client, int what), long *mode);
+155 -128
View File
@@ -24,10 +24,9 @@
char umodestring[UMODETABLESZ+1];
Umode *Usermode_Table = NULL;
int Usermode_highest = 0;
/** User modes and their handlers */
Umode *usermodes = NULL;
/* client->umodes (32 bits): 26 used, 6 free */
long UMODE_INVISIBLE = 0L; /* makes user invisible */
long UMODE_OPER = 0L; /* Operator */
long UMODE_REGNICK = 0L; /* Nick set by services as registered */
@@ -59,20 +58,11 @@ long SendUmodes; /* All umodes which are sent to other servers (global umodes) *
/* Forward declarations */
int umode_hidle_allow(Client *client, int what);
static void unload_usermode_commit(Umode *m);
void umode_init(void)
void umode_init(void)
{
long val = 1;
int i;
Usermode_Table = safe_alloc(sizeof(Umode) * UMODETABLESZ);
for (i = 0; i < UMODETABLESZ; i++)
{
Usermode_Table[i].mode = val;
val *= 2;
}
Usermode_highest = 0;
/* Set up modes */
/* Some built-in modes */
UmodeAdd(NULL, 'i', UMODE_GLOBAL, 0, umode_allow_all, &UMODE_INVISIBLE);
UmodeAdd(NULL, 'o', UMODE_GLOBAL, 1, umode_allow_opers, &UMODE_OPER);
UmodeAdd(NULL, 'r', UMODE_GLOBAL, 0, umode_allow_none, &UMODE_REGNICK);
@@ -87,16 +77,13 @@ void umode_init(void)
void make_umodestr(void)
{
int i;
char *m;
Umode *um;
char *p = umodestring;
m = umodestring;
for (i = 0; i <= Usermode_highest; i++)
{
if (Usermode_Table[i].letter)
*m++ = Usermode_Table[i].letter;
}
*m = '\0';
for (um=usermodes; um; um = um->next)
if (um->letter)
*p++ = um->letter;
*p = '\0';
}
static char previous_umodestring[256];
@@ -125,101 +112,134 @@ void umodes_check_for_changes(void)
strlcpy(previous_umodestring, umodestring, sizeof(previous_umodestring));
}
void usermode_add_sorted(Umode *n)
{
Umode *m;
if (usermodes == NULL)
{
usermodes = n;
return;
}
for (m = usermodes; m; m = m->next)
{
if (m->letter == '\0')
abort();
if (sort_character_lowercase_before_uppercase(n->letter, m->letter))
{
/* Insert us before */
if (m->prev)
m->prev->next = n;
else
usermodes = n; /* new head */
n->prev = m->prev;
n->next = m;
m->prev = n;
return;
}
if (!m->next)
{
/* Append us at end */
m->next = n;
n->prev = m;
return;
}
}
}
/* UmodeAdd:
* Add a usermode with character 'ch', if global is set to 1 the usermode is global
* (sent to other servers) otherwise it's a local usermode
*/
Umode *UmodeAdd(Module *module, char ch, int global, int unset_on_deoper, int (*allowed)(Client *client, int what), long *mode)
{
short i = 0;
short j = 0;
short save = -1;
while (i < UMODETABLESZ)
Umode *um;
int existing = 0;
for (um=usermodes; um; um = um->next)
{
if (!Usermode_Table[i].letter && save == -1)
save = i;
else if (Usermode_Table[i].letter == ch)
if (um->letter == ch)
{
if (Usermode_Table[i].unloaded)
if (um->unloaded)
{
save = i;
Usermode_Table[i].unloaded = 0;
um->unloaded = 0;
existing = 1;
break;
}
else
{
} else {
if (module)
module->errorcode = MODERR_EXISTS;
return NULL;
}
}
i++;
}
i = save;
if (i != UMODETABLESZ)
if (!um)
{
Usermode_Table[i].letter = ch;
Usermode_Table[i].allowed = allowed;
Usermode_Table[i].unset_on_deoper = unset_on_deoper;
/* Update usermode table highest */
for (j = 0; j < UMODETABLESZ; j++)
if (Usermode_Table[i].letter)
if (i > Usermode_highest)
Usermode_highest = i;
make_umodestr();
AllUmodes |= Usermode_Table[i].mode;
if (global)
SendUmodes |= Usermode_Table[i].mode;
*mode = Usermode_Table[i].mode;
Usermode_Table[i].owner = module;
if (module)
/* Not found, create */
long l, found = 0;
for (l = 1; l < INT_MAX/2; l *= 2)
{
ModuleObject *umodeobj = safe_alloc(sizeof(ModuleObject));
umodeobj->object.umode = &(Usermode_Table[i]);
umodeobj->type = MOBJ_UMODE;
AddListItem(umodeobj, module->objects);
module->errorcode = MODERR_NOERROR;
found = 0;
for (um=usermodes; um; um = um->next)
{
if (um->mode == l)
{
found = 1;
break;
}
}
if (!found)
break;
}
return &(Usermode_Table[i]);
/* If 'found' is still true, then we are out of space */
if (found)
{
unreal_log(ULOG_ERROR, "module", "USER_MODE_OUT_OF_SPACE", NULL,
"UmodeAdd: out of space!!!");
if (module)
module->errorcode = MODERR_NOSPACE;
return NULL;
}
um = safe_alloc(sizeof(Umode));
um->letter = ch;
um->mode = l;
usermode_add_sorted(um);
}
else
um->letter = ch;
um->allowed = allowed;
um->unset_on_deoper = unset_on_deoper;
make_umodestr();
AllUmodes |= um->mode;
if (global)
SendUmodes |= um->mode;
*mode = um->mode;
um->owner = module;
if (module)
{
unreal_log(ULOG_ERROR, "module", "USER_MODE_OUT_OF_SPACE", NULL,
"UmodeAdd: out of space!!!");
if (module)
module->errorcode = MODERR_NOSPACE;
return NULL;
ModuleObject *umodeobj = safe_alloc(sizeof(ModuleObject));
umodeobj->object.umode = um;
umodeobj->type = MOBJ_UMODE;
AddListItem(umodeobj, module->objects);
module->errorcode = MODERR_NOERROR;
}
return um;
}
void UmodeDel(Umode *umode)
{
if (loop.rehashing)
umode->unloaded = 1;
else
/* Always free the module object */
if (umode->owner)
{
Client *client;
list_for_each_entry(client, &client_list, client_node)
{
long oldumode = 0;
if (!IsUser(client))
continue;
oldumode = client->umodes;
client->umodes &= ~umode->mode;
if (MyUser(client))
send_umode_out(client, 1, oldumode);
}
umode->letter = '\0';
AllUmodes &= ~(umode->mode);
SendUmodes &= ~(umode->mode);
make_umodestr();
}
if (umode->owner) {
ModuleObject *umodeobj;
for (umodeobj = umode->owner->objects; umodeobj; umodeobj = umodeobj->next) {
if (umodeobj->type == MOBJ_UMODE && umodeobj->object.umode == umode) {
for (umodeobj = umode->owner->objects; umodeobj; umodeobj = umodeobj->next)
{
if (umodeobj->type == MOBJ_UMODE && umodeobj->object.umode == umode)
{
DelListItem(umodeobj, umode->owner->objects);
safe_free(umodeobj);
break;
@@ -227,7 +247,13 @@ void UmodeDel(Umode *umode)
}
umode->owner = NULL;
}
return;
/* Whether we can actually (already) free the Umode depends... */
if (loop.rehashing)
umode->unloaded = 1;
else
unload_usermode_commit(umode);
}
int umode_allow_all(Client *client, int what)
@@ -270,41 +296,45 @@ int umode_hidle_allow(Client *client, int what)
return 0; /* if set::hide-idle-time is 'never' or 'always' then +I makes no sense */
}
void unload_all_unused_umodes(void)
static void unload_usermode_commit(Umode *um)
{
long removed_umode = 0;
int i;
Client *client;
for (i = 0; i < UMODETABLESZ; i++)
{
if (Usermode_Table[i].unloaded)
removed_umode |= Usermode_Table[i].mode;
}
if (!removed_umode) /* Nothing was unloaded */
long removed_umode;
if (!um)
return;
removed_umode = um->mode;
/* First send the -mode regarding all users */
list_for_each_entry(client, &lclient_list, lclient_node)
{
long oldumode = 0;
if (!IsUser(client))
continue;
oldumode = client->umodes;
client->umodes &= ~(removed_umode);
if (MyUser(client))
send_umode_out(client, 1, oldumode);
}
for (i = 0; i < UMODETABLESZ; i++)
{
if (Usermode_Table[i].unloaded)
if (MyUser(client) && (client->umodes & removed_umode))
{
AllUmodes &= ~(Usermode_Table[i].mode);
SendUmodes &= ~(Usermode_Table[i].mode);
Usermode_Table[i].letter = '\0';
Usermode_Table[i].unloaded = 0;
long oldumode = client->umodes;
client->umodes &= ~(removed_umode);
send_umode_out(client, 1, oldumode);
}
}
/* Then unload the mode */
DelListItem(um, usermodes);
safe_free(um);
make_umodestr();
}
void unload_all_unused_umodes(void)
{
Umode *um, *um_next;
for (um=usermodes; um; um = um_next)
{
um_next = um->next;
if (um->letter && um->unloaded)
unload_usermode_commit(um);
}
}
/**
* This function removes any oper-only snomasks when the user is no
* longer an IRC Operator.
@@ -323,14 +353,12 @@ void remove_all_snomasks(Client *client)
*/
void remove_oper_modes(Client *client)
{
int i;
Umode *um;
for (i = 0; i <= Usermode_highest; i++)
for (um = usermodes; um; um = um->next)
{
if (!Usermode_Table[i].letter)
continue;
if (Usermode_Table[i].unset_on_deoper)
client->umodes &= ~Usermode_Table[i].mode;
if (um->unset_on_deoper)
client->umodes &= ~um->mode;
}
/* Bit of a hack, since this is a dynamic permission umode */
@@ -350,15 +378,14 @@ void remove_oper_privileges(Client *client, int broadcast_mode_change)
}
/** Return long integer mode for a user mode character (eg: 'x' -> 0x10) */
long find_user_mode(char flag)
long find_user_mode(char letter)
{
int i;
Umode *um;
for (um = usermodes; um; um = um->next)
if ((um->letter == letter) && !um->unloaded)
return um->mode;
for (i = 0; i < UMODETABLESZ; i++)
{
if ((Usermode_Table[i].letter == flag) && !(Usermode_Table[i].unloaded))
return Usermode_Table[i].mode;
}
return 0;
}
+16 -23
View File
@@ -1079,7 +1079,7 @@ void _set_mode(Channel *channel, Client *client, int parc, const char *parv[], u
*/
CMD_FUNC(_cmd_umode)
{
int i;
Umode *um;
const char *m;
Client *acptr;
int what;
@@ -1120,10 +1120,7 @@ CMD_FUNC(_cmd_umode)
userhost_save_current(client); /* save host, in case we do any +x/-x or similar */
/* find flags already set for user */
for (i = 0; i <= Usermode_highest; i++)
if ((client->umodes & Usermode_Table[i].mode))
oldumodes |= Usermode_Table[i].mode;
oldumodes = client->umodes;
if (RESTRICT_USERMODES && MyUser(client) && !ValidatePermissionsForPath("immune:restrict-usermodes",client,NULL,NULL,NULL))
chk_restrict = 1;
@@ -1238,24 +1235,23 @@ CMD_FUNC(_cmd_umode)
break;
default:
def:
for (i = 0; i <= Usermode_highest; i++)
for (um = usermodes; um; um = um->next)
{
if (*m == Usermode_Table[i].letter)
if (um->letter == *m)
{
if (Usermode_Table[i].allowed)
if (!Usermode_Table[i].allowed(client,what))
if (um->allowed && !um->allowed(client,what))
break;
if (what == MODE_ADD)
client->umodes |= Usermode_Table[i].mode;
client->umodes |= um->mode;
else
client->umodes &= ~Usermode_Table[i].mode;
client->umodes &= ~um->mode;
break;
}
else if (i == Usermode_highest && MyConnect(client) && !rpterror)
{
sendnumeric(client, ERR_UMODEUNKNOWNFLAG);
rpterror = 1;
}
}
if (!um && MyConnect(client) && !rpterror)
{
sendnumeric(client, ERR_UMODEUNKNOWNFLAG);
rpterror = 1;
}
break;
} /* switch */
@@ -1273,19 +1269,16 @@ CMD_FUNC(_cmd_umode)
int i;
/* MODES */
for (i = 0; i <= Usermode_highest; i++)
for (um = usermodes; um; um = um->next)
{
if (!Usermode_Table[i].letter)
continue;
if (Usermode_Table[i].unset_on_deoper)
if (um->unset_on_deoper)
{
/* This is an oper mode. Is it set now and wasn't earlier?
* then it needs to be stripped, as setting it is not
* permitted.
*/
long m = Usermode_Table[i].mode;
if ((client->umodes & m) && !(oldumodes & m))
client->umodes &= ~Usermode_Table[i].mode; /* remove */
if ((client->umodes & um->mode) && !(oldumodes & um->mode))
client->umodes &= ~um->mode; /* remove */
}
}
+1 -13
View File
@@ -83,19 +83,7 @@ CMD_FUNC(cmd_sendumode)
sendto_server(client, 0, 0, mtags, ":%s SENDUMODE %s :%s", client->id, parv[1], message);
for (p = parv[1]; *p; p++)
{
for(i = 0; i <= Usermode_highest; i++)
{
if (!Usermode_Table[i].letter)
continue;
if (Usermode_Table[i].letter == *p)
{
umode_s |= Usermode_Table[i].mode;
break;
}
}
}
umode_s = set_usermode(parv[1]);
list_for_each_entry(acptr, &oper_list, special_node)
{
+11 -16
View File
@@ -317,11 +317,11 @@ void channel_svsmode(Client *client, int parc, const char *parv[])
*/
void do_svsmode(Client *client, MessageTag *recv_mtags, int parc, const char *parv[], int show_change)
{
int i;
Umode *um;
const char *m;
Client *target;
int what;
long setflags = 0;
long oldumodes = 0;
if (!IsULine(client))
return;
@@ -342,10 +342,7 @@ void do_svsmode(Client *client, MessageTag *recv_mtags, int parc, const char *pa
userhost_save_current(target);
/* initialize setflag to be the user's pre-SVSMODE flags */
for (i = 0; i <= Usermode_highest; i++)
if (Usermode_Table[i].letter && (target->umodes & Usermode_Table[i].mode))
setflags |= Usermode_Table[i].mode;
oldumodes = target->umodes;
/* parse mode change string(s) */
for (m = parv[2]; *m; m++)
@@ -505,16 +502,14 @@ void do_svsmode(Client *client, MessageTag *recv_mtags, int parc, const char *pa
break;
default:
setmodex:
for (i = 0; i <= Usermode_highest; i++)
for (um = usermodes; um; um = um->next)
{
if (!Usermode_Table[i].letter)
continue;
if (*m == Usermode_Table[i].letter)
if (um->letter == *m)
{
if (what == MODE_ADD)
target->umodes |= Usermode_Table[i].mode;
target->umodes |= um->mode;
else
target->umodes &= ~Usermode_Table[i].mode;
target->umodes &= ~um->mode;
break;
}
}
@@ -531,15 +526,15 @@ void do_svsmode(Client *client, MessageTag *recv_mtags, int parc, const char *pa
parv[1], parv[2]);
/* Here we trigger the same hooks that cmd_mode does and, likewise,
only if the old flags (setflags) are different than the newly-
only if the old flags (oldumodes) are different than the newly-
set ones */
if (setflags != target->umodes)
RunHook(HOOKTYPE_UMODE_CHANGE, target, setflags, target->umodes);
if (oldumodes != target->umodes)
RunHook(HOOKTYPE_UMODE_CHANGE, target, oldumodes, target->umodes);
if (show_change)
{
char buf[BUFSIZE];
build_umode_string(target, setflags, ALL_UMODES, buf);
build_umode_string(target, oldumodes, ALL_UMODES, buf);
if (MyUser(target) && *buf)
sendto_one(target, NULL, ":%s MODE %s :%s", client->name, target->name, buf);
}
+1 -11
View File
@@ -330,17 +330,7 @@ static int parse_who_options(Client *client, int argc, const char **argv)
else
umodes = &wfl.umodes_dontwant;
while (*s)
{
int i;
for (i = 0; i <= Usermode_highest; i++)
if (*s == Usermode_Table[i].letter)
{
*umodes |= Usermode_Table[i].mode;
break;
}
s++;
}
*umodes = set_usermode(s);
if (!IsOper(client))
*umodes = *umodes & UMODE_OPER; /* these are usermodes regular users may search for. just oper now. */
+4 -4
View File
@@ -295,7 +295,7 @@ CMD_FUNC(cmd_whox)
while (*s)
{
int i;
Umode *um;
switch (*s)
{
@@ -317,11 +317,11 @@ CMD_FUNC(cmd_whox)
else
umodes = &fmt.noumodes;
for (i = 0; i <= Usermode_highest; i++)
for (um = usermodes; um; um = um->next)
{
if (*s == Usermode_Table[i].letter)
if (um->letter == *s)
{
*umodes |= Usermode_Table[i].mode;
*umodes |= um->mode;
break;
}
}
+2 -11
View File
@@ -736,22 +736,13 @@ void sendto_umode_global(int umodes, FORMAT_STRING(const char *pattern), ...)
{
va_list vl;
Client *acptr;
Umode *um;
char nbuf[1024];
int i;
char modestr[128];
char *p;
/* Convert 'umodes' (int) to 'modestr' (string) */
*modestr = '\0';
p = modestr;
for(i = 0; i <= Usermode_highest; i++)
{
if (!Usermode_Table[i].letter)
continue;
if (umodes & Usermode_Table[i].mode)
*p++ = Usermode_Table[i].letter;
}
*p = '\0';
get_usermode_string_raw_r(umodes, modestr, sizeof(modestr));
list_for_each_entry(acptr, &lclient_list, lclient_node)
{
+71 -60
View File
@@ -82,43 +82,43 @@ void iNAH_host(Client *client, const char *host)
*/
long set_usermode(const char *umode)
{
int newumode;
int what;
Umode *um;
int newumode;
int what;
const char *m;
int i;
newumode = 0;
what = MODE_ADD;
for (m = umode; *m; m++)
{
switch (*m)
{
case '+':
what = MODE_ADD;
break;
case '-':
what = MODE_DEL;
break;
case ' ':
case '\n':
case '\r':
case '\t':
break;
default:
for (i = 0; i <= Usermode_highest; i++)
{
if (!Usermode_Table[i].letter)
continue;
if (*m == Usermode_Table[i].letter)
{
if (what == MODE_ADD)
newumode |= Usermode_Table[i].mode;
else
newumode &= ~Usermode_Table[i].mode;
}
}
case '+':
what = MODE_ADD;
break;
case '-':
what = MODE_DEL;
break;
case ' ':
case '\n':
case '\r':
case '\t':
break;
default:
for (um = usermodes; um; um = um->next)
{
if (um->letter == *m)
{
if (what == MODE_ADD)
newumode |= um->mode;
else
newumode &= ~um->mode;
}
}
}
}
return (newumode);
return newumode;
}
/** Convert a target pointer to an 8 bit hash, used for target limiting. */
@@ -257,15 +257,13 @@ char *canonize(const char *buffer)
const char *get_usermode_string(Client *client)
{
static char buf[128];
int i;
char *m;
Umode *um;
strlcpy(buf, "+", sizeof(buf));
for (um = usermodes; um; um = um->next)
if (client->umodes & um->mode)
strlcat_letter(buf, um->letter, sizeof(buf));
m = buf;
*m++ = '+';
for (i = 0; (i <= Usermode_highest) && (m - buf < sizeof(buf) - 4); i++)
if (Usermode_Table[i].letter && (client->umodes & Usermode_Table[i].mode))
*m++ = Usermode_Table[i].letter;
*m = '\0';
return buf;
}
@@ -273,21 +271,20 @@ const char *get_usermode_string(Client *client)
* @param client The client
* @param buf The buffer to write to
* @param buflen The size of the buffer
* @returns string of user modes (temporary storage)
* @returns string of user modes (buf)
*/
const char *get_usermode_string_r(Client *client, char *buf, size_t buflen)
{
int i;
Umode *um;
strlcpy(buf, "+", buflen);
for (i = 0; i <= Usermode_highest; i++)
if (Usermode_Table[i].letter && (client->umodes & Usermode_Table[i].mode))
strlcat_letter(buf, Usermode_Table[i].letter, buflen);
for (um = usermodes; um; um = um->next)
if (client->umodes & um->mode)
strlcat_letter(buf, um->letter, buflen);
return buf;
}
/** Get user modes as a string - this one does not work on 'client' but directly on 'umodes'.
* @param umodes The user modes that are set
* @returns string of user modes (temporary storage)
@@ -295,19 +292,35 @@ const char *get_usermode_string_r(Client *client, char *buf, size_t buflen)
const char *get_usermode_string_raw(long umodes)
{
static char buf[128];
int i;
char *m;
Umode *um;
strlcpy(buf, "+", sizeof(buf));
for (um = usermodes; um; um = um->next)
if (umodes & um->mode)
strlcat_letter(buf, um->letter, sizeof(buf));
m = buf;
*m++ = '+';
for (i = 0; (i <= Usermode_highest) && (m - buf < sizeof(buf) - 4); i++)
if (Usermode_Table[i].letter && (umodes & Usermode_Table[i].mode))
*m++ = Usermode_Table[i].letter;
*m = '\0';
return buf;
}
/** Get user modes as a string - this one does not work on 'client' but directly on 'umodes'.
* @param umodes The user modes that are set
* @param buf The buffer to write to
* @param buflen The size of the buffer
* @returns string of user modes (buf)
*/
const char *get_usermode_string_raw_r(long umodes, char *buf, size_t buflen)
{
Umode *um;
strlcpy(buf, "+", buflen);
for (um = usermodes; um; um = um->next)
if (umodes & um->mode)
strlcat_letter(buf, um->letter, buflen);
return buf;
}
/** Set a new snomask on the user.
* The user is not informed of the change by this function.
* @param client The client
@@ -355,7 +368,7 @@ void set_snomask(Client *client, const char *snomask)
*/
void build_umode_string(Client *client, long old, long sendmask, char *umode_buf)
{
int i;
Umode *um;
long flag;
char *m;
int what = MODE_NULL;
@@ -366,33 +379,31 @@ void build_umode_string(Client *client, long old, long sendmask, char *umode_buf
*/
m = umode_buf;
*m = '\0';
for (i = 0; i <= Usermode_highest; i++)
for (um = usermodes; um; um = um->next)
{
if (!Usermode_Table[i].letter)
continue;
flag = Usermode_Table[i].mode;
flag = um->mode;
if (MyUser(client) && !(flag & sendmask))
continue;
if ((flag & old) && !(client->umodes & flag))
{
if (what == MODE_DEL)
*m++ = Usermode_Table[i].letter;
*m++ = um->letter;
else
{
what = MODE_DEL;
*m++ = '-';
*m++ = Usermode_Table[i].letter;
*m++ = um->letter;
}
}
else if (!(flag & old) && (client->umodes & flag))
{
if (what == MODE_ADD)
*m++ = Usermode_Table[i].letter;
*m++ = um->letter;
else
{
what = MODE_ADD;
*m++ = '+';
*m++ = Usermode_Table[i].letter;
*m++ = um->letter;
}
}
}