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

Replace manual array for ChannelInfo's access list to use an std::vector instead, cleans up the code by a huge portion and fixes bug #1024 in the process.

git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@2184 5417fbe8-f217-4b02-8779-1006273d7864
This commit is contained in:
cyberbotx
2009-03-23 00:06:40 +00:00
parent 5d56ed0158
commit 3ff8e96e14
8 changed files with 303 additions and 322 deletions
-1
View File
@@ -185,7 +185,6 @@ E ChannelInfo *cs_findchan(const char *chan);
E int check_access(User * user, ChannelInfo * ci, int what);
E int is_founder(User * user, ChannelInfo * ci);
E int get_access(User * user, ChannelInfo * ci);
E ChanAccess *get_access_entry(NickCore * nc, ChannelInfo * ci);
E void update_cs_lastseen(User * user, ChannelInfo * ci);
E int get_idealban(ChannelInfo * ci, User * u, char *ret, int retlen);
E AutoKick *is_stuck(ChannelInfo * ci, const char *mask);
+93 -8
View File
@@ -8,8 +8,8 @@
* $Id$
*
*/
class ChannelInfo : public Extensible
class CoreExport ChannelInfo : public Extensible
{
public:
ChannelInfo()
@@ -20,9 +20,8 @@ class ChannelInfo : public Extensible
desc = url = email = last_topic = forbidby = forbidreason = NULL;
time_registered = last_used = last_topic_time = 0;
flags = 0;
bantype = accesscount = akickcount = 0;
bantype = akickcount = 0;
levels = NULL;
access = NULL;
akick = NULL;
mlock_on = mlock_off = mlock_limit = 0;
mlock_key = mlock_flood = mlock_redirect = entry_message = NULL;
@@ -36,7 +35,7 @@ class ChannelInfo : public Extensible
floodlines = floodsecs = 0;
repeattimes = 0;
}
ChannelInfo *next, *prev;
char name[CHANMAX];
NickCore *founder;
@@ -60,8 +59,7 @@ class ChannelInfo : public Extensible
int16 bantype;
int16 *levels; /* Access levels for commands */
uint16 accesscount;
ChanAccess *access; /* List of authorized users */
std::vector<ChanAccess *> access; /* List of authorized users */
uint16 akickcount;
AutoKick *akick; /* List of users to kickban */
@@ -89,5 +87,92 @@ class ChannelInfo : public Extensible
int16 capsmin, capspercent; /* For CAPS kicker */
int16 floodlines, floodsecs; /* For FLOOD kicker */
int16 repeattimes; /* For REPEAT kicker */
};
/** Add an entry to the channel access list
*
* @param nc The NickCore of the user that the access entry should be tied to
* @param level The channel access level the user has on the channel
* @param last_seen When the user was last seen within the channel
*
* Creates a new access list entry and inserts it into the access list.
*/
void AddAccess(NickCore *nc, int16 level, int32 last_seen = 0)
{
ChanAccess *new_access = new ChanAccess;
new_access->in_use = 1;
new_access->nc = nc;
new_access->level = level;
new_access->last_seen = last_seen;
access.push_back(new_access);
}
/** Get an entry from the channel access list by index
*
* @param index The index in the access list vector
* @return A ChanAccess struct corresponding to the index given, or NULL if outside the bounds
*
* Retrieves an entry from the access list that matches the given index.
*/
ChanAccess *GetAccess(unsigned index)
{
if (access.empty() || index >= access.size())
return NULL;
return access[index];
}
/** Get an entry from the channel access list by NickCore
*
* @param nc The NickCore to find within the access list vector
* @param level Optional channel access level to compare the access entries to
* @return A ChanAccess struct corresponding to the NickCore, or NULL if not found
*
* Retrieves an entry from the access list that matches the given NickCore, optionally also matching a certain level.
*/
ChanAccess *GetAccess(NickCore *nc, int16 level = 0)
{
if (access.empty())
return NULL;
for (unsigned i = 0; i < access.size(); i++)
if (access[i]->in_use && access[i]->nc == nc && (level ? access[i]->level == level : true))
return access[i];
return NULL;
}
/** Erase an entry from the channel access list
*
* @param index The index in the access list vector
*
* Clears the memory used by the given access entry and removes it from the vector.
*/
void EraseAccess(unsigned index)
{
if (access.empty() || index >= access.size())
return;
delete access[index];
access.erase(access.begin() + index);
}
/** Cleans the channel access list
*
* Cleans up the access list so it no longer contains entries no longer in use.
*/
void CleanAccess()
{
for (unsigned j = access.size(); j > 0; --j)
if (!access[j - 1]->in_use)
EraseAccess(j - 1);
}
/** Clear the entire channel access list
*
* Clears the entire access list by deleting every item and then clearing the vector.
*/
void ClearAccess()
{
while (access.begin() != access.end())
EraseAccess(0);
}
};
+23 -22
View File
@@ -597,38 +597,39 @@ typedef struct {
/*************************************************************************/
enum AccessLevel
{
/* Note that these two levels also serve as exclusive boundaries for valid
* access levels. ACCESS_FOUNDER may be assumed to be strictly greater
* than any valid access level, and ACCESS_INVALID may be assumed to be
* strictly less than any valid access level. Also read below.
*/
ACCESS_FOUNDER = 10000, /* Numeric level indicating founder access */
ACCESS_INVALID = -10000, /* Used in levels[] for disabled settings */
/* There is one exception to the above access levels: SuperAdmins will have
* access level 10001. This level is never stored, however; it is only used
* in comparison and to let SuperAdmins win from founders where needed
*/
ACCESS_SUPERADMIN = 10001,
/* Levels for xOP */
ACCESS_VOP = 3,
ACCESS_HOP = 4,
ACCESS_AOP = 5,
ACCESS_SOP = 10
};
/* Channel info structures. Stored similarly to the nicks, except that
* the second character of the channel name, not the first, is used to
* determine the list. (Hashing based on the first character of the name
* wouldn't get very far. ;) ) */
/* Access levels for users. */
typedef struct {
struct ChanAccess {
uint16 in_use; /* 1 if this entry is in use, else 0 */
int16 level;
NickCore *nc; /* Guaranteed to be non-NULL if in use, NULL if not */
time_t last_seen;
} ChanAccess;
/* Note that these two levels also serve as exclusive boundaries for valid
* access levels. ACCESS_FOUNDER may be assumed to be strictly greater
* than any valid access level, and ACCESS_INVALID may be assumed to be
* strictly less than any valid access level. Also read below.
*/
#define ACCESS_FOUNDER 10000 /* Numeric level indicating founder access */
#define ACCESS_INVALID -10000 /* Used in levels[] for disabled settings */
/* There is one exception to the above access levels: SuperAdmins will have
* access level 10001. This level is never stored, however; it is only used
* in comparison and to let SuperAdmins win from founders where needed
*/
#define ACCESS_SUPERADMIN 10001
/* Levels for xOP */
#define ACCESS_VOP 3
#define ACCESS_HOP 4
#define ACCESS_AOP 5
#define ACCESS_SOP 10
};
/* AutoKick data. */
typedef struct {
+43 -69
View File
@@ -205,7 +205,8 @@ void get_chanserv_stats(long *nrec, long *memuse)
mem += strlen(ci->url) + 1;
if (ci->email)
mem += strlen(ci->email) + 1;
mem += ci->accesscount * sizeof(ChanAccess);
if (!ci->access.empty())
mem += ci->access.size() * sizeof(ChanAccess);
mem += ci->akickcount * sizeof(AutoKick);
for (j = 0; j < ci->akickcount; j++) {
if (!(ci->akick[j].flags & AK_ISNICK)
@@ -393,27 +394,29 @@ void load_cs_dbase()
ci->levels[j] = static_cast<int16>(tmp16);
}
SAFE(read_int16(&ci->accesscount, f));
if (ci->accesscount) {
ci->access = static_cast<ChanAccess *>(scalloc(ci->accesscount, sizeof(ChanAccess)));
for (j = 0; j < ci->accesscount; j++) {
SAFE(read_int16(&ci->access[j].in_use, f));
if (ci->access[j].in_use) {
SAFE(read_int16(&tmp16, f));
ci->access[j].level = static_cast<int16>(tmp16);
uint16 accesscount = 0;
SAFE(read_int16(&accesscount, f));
if (accesscount) {
for (j = 0; j < accesscount; j++) {
uint16 in_use = 0;
SAFE(read_int16(&in_use, f));
if (in_use) {
uint16 level;
SAFE(read_int16(&level, f));
NickCore *nc;
SAFE(read_string(&s, f));
if (s) {
ci->access[j].nc = findcore(s);
nc = findcore(s);
delete [] s;
}
if (ci->access[j].nc == NULL)
ci->access[j].in_use = 0;
SAFE(read_int32(&tmp32, f));
ci->access[j].last_seen = tmp32;
else
nc = NULL;
uint32 last_seen;
SAFE(read_int32(&last_seen, f));
if (nc)
ci->AddAccess(nc, level, last_seen);
}
}
} else {
ci->access = NULL;
}
SAFE(read_int16(&ci->akickcount, f));
@@ -610,14 +613,15 @@ void save_cs_dbase()
for (j = 0; j < CA_SIZE; j++)
SAFE(write_int16(ci->levels[j], f));
SAFE(write_int16(ci->accesscount, f));
for (j = 0; j < ci->accesscount; j++) {
SAFE(write_int16(ci->access[j].in_use, f));
if (ci->access[j].in_use) {
SAFE(write_int16(ci->access[j].level, f));
SAFE(write_string(ci->access[j].nc->display, f));
SAFE(write_int32(ci->access[j].last_seen, f));
}
SAFE(write_int16(ci->access.empty() ? 0 : ci->access.size(), f));
for (j = 0; j < ci->access.size(); j++) {
ChanAccess *access = ci->GetAccess(j);
if (!access->in_use)
continue;
SAFE(write_int16(access->in_use, f));
SAFE(write_int16(access->level, f));
SAFE(write_string(access->nc->display, f));
SAFE(write_int32(access->last_seen, f));
}
SAFE(write_int16(ci->akickcount, f));
@@ -1441,11 +1445,12 @@ void cs_remove_nick(const NickCore * nc)
if (ci->successor == nc)
ci->successor = NULL;
for (ca = ci->access, j = ci->accesscount; j > 0; ca++, j--) {
if (ca->in_use && ca->nc == nc) {
ca->in_use = 0;
ca->nc = NULL;
}
for (j = ci->access.size(); j > 0; --j)
{
ca = ci->GetAccess(j - 1);
if (ca->in_use && ca->nc == nc)
ci->EraseAccess(j - 1);
}
for (akick = ci->akick, j = 0; j < ci->akickcount; akick++, j++) {
@@ -1730,8 +1735,6 @@ int delchan(ChannelInfo * ci)
delete [] ci->forbidby;
if (ci->forbidreason)
delete [] ci->forbidreason;
if (ci->access)
free(ci->access);
if (debug >= 2) {
alog("debug: delchan() top of the akick list");
}
@@ -1874,26 +1877,6 @@ int is_identified(User * user, ChannelInfo * ci)
/*************************************************************************/
/* Returns the ChanAccess entry for an user */
ChanAccess *get_access_entry(NickCore * nc, ChannelInfo * ci)
{
ChanAccess *access;
int i;
if (!ci || !nc) {
return NULL;
}
for (access = ci->access, i = 0; i < ci->accesscount; access++, i++)
if (access->in_use && access->nc == nc)
return access;
return NULL;
}
/*************************************************************************/
/* Return the access level the given user has on the channel. If the
* channel doesn't exist, the user isn't on the access list, or the channel
* is CS_SECURE and the user hasn't IDENTIFY'd with NickServ, return 0. */
@@ -1917,7 +1900,7 @@ int get_access(User * user, ChannelInfo * ci)
if (nick_identified(user)
|| (nick_recognized(user) && !(ci->flags & CI_SECURE)))
if ((access = get_access_entry(user->nc, ci)))
if ((access = ci->GetAccess(user->nc)))
return access->level;
if (nick_identified(user))
@@ -1937,7 +1920,7 @@ void update_cs_lastseen(User * user, ChannelInfo * ci)
if (is_founder(user, ci) || nick_identified(user)
|| (nick_recognized(user) && !(ci->flags & CI_SECURE)))
if ((access = get_access_entry(user->nc, ci)))
if ((access = ci->GetAccess(user->nc)))
access->last_seen = time(NULL);
}
@@ -2117,28 +2100,19 @@ void cs_set_redirect(ChannelInfo * ci, const char *value)
int get_access_level(ChannelInfo * ci, NickAlias * na)
{
ChanAccess *access;
int num;
if (!ci || !na) {
if (!ci || !na)
return 0;
}
if (na->nc == ci->founder) {
if (na->nc == ci->founder)
return ACCESS_FOUNDER;
}
for (num = 0; num < ci->accesscount; num++) {
access = &ci->access[num];
if (access->nc && access->nc == na->nc && access->in_use) {
return access->level;
}
}
return 0;
access = ci->GetAccess(na->nc);
if (!access)
return 0;
else
return access->level;
}
const char *get_xop_level(int level)
+99 -133
View File
@@ -52,35 +52,34 @@ static int access_del_callback(User * u, int num, va_list args)
int *last = va_arg(args, int *);
int *perm = va_arg(args, int *);
int uacc = va_arg(args, int);
if (num < 1 || num > ci->accesscount)
if (num < 1 || num > ci->access.size())
return 0;
*last = num;
return access_del(u, ci, &ci->access[num - 1], perm, uacc);
return access_del(u, ci, ci->GetAccess(num - 1), perm, uacc);
}
static int access_list(User * u, int index, ChannelInfo * ci,
int *sent_header)
static int access_list(User * u, int index, ChannelInfo * ci, int *sent_header)
{
ChanAccess *access = &ci->access[index];
ChanAccess *access = ci->GetAccess(index);
const char *xop;
if (!access->in_use)
return 0;
if (!*sent_header) {
if (!*sent_header)
{
notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_HEADER, ci->name);
*sent_header = 1;
}
if (ci->flags & CI_XOP) {
if (ci->flags & CI_XOP)
{
xop = get_xop_level(access->level);
notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_XOP_FORMAT, index + 1,
xop, access->nc->display);
} else {
notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_AXS_FORMAT, index + 1,
access->level, access->nc->display);
notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_XOP_FORMAT, index + 1, xop, access->nc->display);
}
else
notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_AXS_FORMAT, index + 1, access->level, access->nc->display);
return 1;
}
@@ -88,7 +87,7 @@ static int access_list_callback(User * u, int num, va_list args)
{
ChannelInfo *ci = va_arg(args, ChannelInfo *);
int *sent_header = va_arg(args, int *);
if (num < 1 || num > ci->accesscount)
if (num < 1 || num > ci->access.size())
return 0;
return access_list(u, num - 1, ci, sent_header);
}
@@ -116,34 +115,35 @@ class CommandCSAccess : public Command
unsigned i;
int level = 0, ulev;
int is_list = (cmd && stricmp(cmd, "LIST") == 0);
int is_list = (cmd && !stricmp(cmd, "LIST"));
/* If LIST, we don't *require* any parameters, but we can take any.
* If DEL, we require a nick and no level.
* Else (ADD), we require a level (which implies a nick). */
if (!cmd || ((is_list || !stricmp(cmd, "CLEAR")) ? 0 :
(stricmp(cmd, "DEL") == 0) ? (!nick || s) : !s)) {
if (!cmd || ((is_list || !stricmp(cmd, "CLEAR")) ? 0 : (!stricmp(cmd, "DEL")) ? (!nick || s) : !s))
this->OnSyntaxError(u);
} else if (!(ci = cs_findchan(chan))) {
else if (!(ci = cs_findchan(chan)))
notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
} else if (ci->flags & CI_FORBIDDEN) {
else if (ci->flags & CI_FORBIDDEN)
notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
/* We still allow LIST in xOP mode, but not others */
} else if ((ci->flags & CI_XOP) && !is_list) {
/* We still allow LIST in xOP mode, but not others */
else if ((ci->flags & CI_XOP) && !is_list)
{
if (ircd->halfop)
notice_lang(s_ChanServ, u, CHAN_ACCESS_XOP_HOP, s_ChanServ);
else
notice_lang(s_ChanServ, u, CHAN_ACCESS_XOP, s_ChanServ);
} else if (
(
}
else if ((
(is_list && !check_access(u, ci, CA_ACCESS_LIST) && !u->nc->HasCommand("chanserv/access/list"))
||
(!is_list && !check_access(u, ci, CA_ACCESS_CHANGE) && !u->nc->HasPriv("chanserv/access/modify"))
))
{
notice_lang(s_ChanServ, u, ACCESS_DENIED);
} else if (stricmp(cmd, "ADD") == 0) {
if (readonly) {
else if (!stricmp(cmd, "ADD"))
{
if (readonly)
{
notice_lang(s_ChanServ, u, CHAN_ACCESS_DISABLED);
return MOD_CONT;
}
@@ -157,82 +157,76 @@ class CommandCSAccess : public Command
return MOD_CONT;
}
if (level == 0) {
if (!level)
{
notice_lang(s_ChanServ, u, CHAN_ACCESS_LEVEL_NONZERO);
return MOD_CONT;
} else if (level <= ACCESS_INVALID || level >= ACCESS_FOUNDER) {
notice_lang(s_ChanServ, u, CHAN_ACCESS_LEVEL_RANGE,
ACCESS_INVALID + 1, ACCESS_FOUNDER - 1);
}
else if (level <= ACCESS_INVALID || level >= ACCESS_FOUNDER)
{
notice_lang(s_ChanServ, u, CHAN_ACCESS_LEVEL_RANGE, ACCESS_INVALID + 1, ACCESS_FOUNDER - 1);
return MOD_CONT;
}
na = findnick(nick);
if (!na) {
if (!na)
{
notice_lang(s_ChanServ, u, CHAN_ACCESS_NICKS_ONLY);
return MOD_CONT;
}
if (na->status & NS_FORBIDDEN) {
if (na->status & NS_FORBIDDEN)
{
notice_lang(s_ChanServ, u, NICK_X_FORBIDDEN, nick);
return MOD_CONT;
}
nc = na->nc;
for (access = ci->access, i = 0; i < ci->accesscount;
access++, i++) {
if (access->nc == nc) {
/* Don't allow lowering from a level >= ulev */
if (access->level >= ulev && !u->nc->HasPriv("chanserv/access/change"))
{
notice_lang(s_ChanServ, u, PERMISSION_DENIED);
return MOD_CONT;
}
if (access->level == level) {
notice_lang(s_ChanServ, u, CHAN_ACCESS_LEVEL_UNCHANGED,
access->nc->display, chan, level);
return MOD_CONT;
}
access->level = level;
snprintf(event_access, BUFSIZE, "%d", access->level);
send_event(EVENT_ACCESS_CHANGE, 4, ci->name, u->nick,
na->nick, event_access);
alog("%s: %s!%s@%s (level %d) set access level %d to %s (group %s) on channel %s", s_ChanServ, u->nick, u->GetIdent().c_str(), u->host, ulev, access->level, na->nick, nc->display, ci->name);
notice_lang(s_ChanServ, u, CHAN_ACCESS_LEVEL_CHANGED,
access->nc->display, chan, level);
access = ci->GetAccess(nc);
if (access)
{
/* Don't allow lowering from a level >= ulev */
if (access->level >= ulev && !u->nc->HasPriv("chanserv/access/change"))
{
notice_lang(s_ChanServ, u, PERMISSION_DENIED);
return MOD_CONT;
}
}
if (i < CSAccessMax) {
ci->accesscount++;
ci->access =
static_cast<ChanAccess *>(srealloc(ci->access,
sizeof(ChanAccess) * ci->accesscount));
} else {
notice_lang(s_ChanServ, u, CHAN_ACCESS_REACHED_LIMIT,
CSAccessMax);
if (access->level == level)
{
notice_lang(s_ChanServ, u, CHAN_ACCESS_LEVEL_UNCHANGED, access->nc->display, chan, level);
return MOD_CONT;
}
access->level = level;
snprintf(event_access, BUFSIZE, "%d", access->level);
send_event(EVENT_ACCESS_CHANGE, 4, ci->name, u->nick, na->nick, event_access);
alog("%s: %s!%s@%s (level %d) set access level %d to %s (group %s) on channel %s", s_ChanServ, u->nick, u->GetIdent().c_str(), u->host, ulev, access->level, na->nick, nc->display, ci->name);
notice_lang(s_ChanServ, u, CHAN_ACCESS_LEVEL_CHANGED, access->nc->display, chan, level);
return MOD_CONT;
}
access = &ci->access[i];
access->nc = nc;
access->in_use = 1;
access->level = level;
access->last_seen = 0;
if (ci->access.size() >= CSAccessMax)
{
notice_lang(s_ChanServ, u, CHAN_ACCESS_REACHED_LIMIT, CSAccessMax);
return MOD_CONT;
}
ci->AddAccess(nc, level);
snprintf(event_access, BUFSIZE, "%d", access->level);
send_event(EVENT_ACCESS_ADD, 4, ci->name, u->nick, na->nick,
event_access);
send_event(EVENT_ACCESS_ADD, 4, ci->name, u->nick, na->nick, event_access);
alog("%s: %s!%s@%s (level %d) set access level %d to %s (group %s) on channel %s", s_ChanServ, u->nick, u->GetIdent().c_str(), u->host, ulev, access->level, na->nick, nc->display, ci->name);
notice_lang(s_ChanServ, u, CHAN_ACCESS_ADDED, nc->display,
ci->name, access->level);
} else if (stricmp(cmd, "DEL") == 0) {
int deleted, a, b;
if (readonly) {
notice_lang(s_ChanServ, u, CHAN_ACCESS_ADDED, nc->display, ci->name, access->level);
}
else if (!stricmp(cmd, "DEL"))
{
int deleted;
if (readonly)
{
notice_lang(s_ChanServ, u, CHAN_ACCESS_DISABLED);
return MOD_CONT;
}
if (ci->accesscount == 0) {
if (ci->access.empty())
{
notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_EMPTY, chan);
return MOD_CONT;
}
@@ -241,8 +235,7 @@ class CommandCSAccess : public Command
if (isdigit(*nick) && strspn(nick, "1234567890,-") == strlen(nick))
{
int count, last = -1, perm = 0;
deleted = process_numlist(nick, &count, access_del_callback, u,
ci, &last, &perm, get_access(u, ci));
deleted = process_numlist(nick, &count, access_del_callback, u, ci, &last, &perm, get_access(u, ci));
if (!deleted)
{
if (perm)
@@ -273,15 +266,12 @@ class CommandCSAccess : public Command
return MOD_CONT;
}
nc = na->nc;
for (i = 0; i < ci->accesscount; i++)
if (ci->access[i].nc == nc)
break;
if (i == ci->accesscount)
access = ci->GetAccess(nc);
if (!access)
{
notice_lang(s_ChanServ, u, CHAN_ACCESS_NOT_FOUND, nick, chan);
return MOD_CONT;
}
access = &ci->access[i];
if (get_access(u, ci) <= access->level && !u->nc->HasPriv("chanserv/access/change"))
{
deleted = 0;
@@ -297,37 +287,10 @@ class CommandCSAccess : public Command
}
}
if (deleted) {
/* Reordering - DrStein */
for (b = 0; b < ci->accesscount; b++) {
if (ci->access[b].in_use) {
for (a = 0; a < ci->accesscount; a++) {
if (a > b)
break;
if (!ci->access[a].in_use) {
ci->access[a].in_use = 1;
ci->access[a].level = ci->access[b].level;
ci->access[a].nc = ci->access[b].nc;
ci->access[a].last_seen =
ci->access[b].last_seen;
ci->access[b].nc = NULL;
ci->access[b].in_use = 0;
break;
}
}
}
}
/* After reordering only the entries at the end could still be empty.
* We ll free the places no longer in use... */
for (int j = ci->accesscount - 1; j >= 0; j--) {
if (ci->access[j].in_use == 1)
break;
ci->accesscount--;
}
ci->access =
static_cast<ChanAccess *>(srealloc(ci->access,sizeof(ChanAccess) * ci->accesscount));
if (deleted)
{
/* We'll free the access entries no longer in use... */
ci->CleanAccess();
/* We don't know the nick if someone used numbers, so we trigger the event without
* nick param. We just do this once, even if someone enters a range. -Certus */
@@ -336,32 +299,37 @@ class CommandCSAccess : public Command
else
send_event(EVENT_ACCESS_DEL, 2, ci->name, u->nick);
}
} else if (stricmp(cmd, "LIST") == 0) {
}
else if (!stricmp(cmd, "LIST"))
{
int sent_header = 0;
if (ci->accesscount == 0) {
if (ci->access.empty())
{
notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_EMPTY, chan);
return MOD_CONT;
}
if (nick && strspn(nick, "1234567890,-") == strlen(nick)) {
process_numlist(nick, NULL, access_list_callback, u, ci,
&sent_header);
} else {
for (i = 0; i < ci->accesscount; i++) {
if (nick && ci->access[i].nc
&& !Anope::Match(ci->access[i].nc->display, nick, false))
if (nick && strspn(nick, "1234567890,-") == strlen(nick))
process_numlist(nick, NULL, access_list_callback, u, ci, &sent_header);
else
{
for (i = 0; i < ci->access.size(); i++)
{
access = ci->GetAccess(i);
if (nick && access->nc && !Anope::Match(access->nc->display, nick, false))
continue;
access_list(u, i, ci, &sent_header);
}
}
if (!sent_header) {
if (!sent_header)
notice_lang(s_ChanServ, u, CHAN_ACCESS_NO_MATCH, chan);
} else {
else
notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_FOOTER, ci->name);
}
} else if (stricmp(cmd, "CLEAR") == 0) {
if (readonly) {
}
else if (!stricmp(cmd, "CLEAR"))
{
if (readonly)
{
notice_lang(s_ChanServ, u, CHAN_ACCESS_DISABLED);
return MOD_CONT;
}
@@ -372,9 +340,7 @@ class CommandCSAccess : public Command
return MOD_CONT;
}
free(ci->access);
ci->access = NULL;
ci->accesscount = 0;
ci->ClearAccess();
send_event(EVENT_ACCESS_CLEAR, 2, ci->name, u->nick);
@@ -383,9 +349,9 @@ class CommandCSAccess : public Command
s_ChanServ, u->nick, u->GetIdent().c_str(), u->host,
get_access(u, ci), chan);
} else {
this->OnSyntaxError(u);
}
else
this->OnSyntaxError(u);
return MOD_CONT;
}
+1 -1
View File
@@ -176,7 +176,7 @@ int get_access_nc(NickCore *nc, ChannelInfo *ci)
if (!ci || !nc)
return 0;
if ((access = get_access_entry(nc, ci)))
if ((access = ci->GetAccess(nc)))
return access->level;
return 0;
}
+5 -2
View File
@@ -464,8 +464,8 @@ class CommandCSSet : public Command
int i;
ChanAccess *access;
for (access = ci->access, i = 0; i < ci->accesscount;
access++, i++) {
for (i = 0; i < ci->access.size(); i++) {
access = ci->GetAccess(i);
if (!access->in_use)
continue;
/* This will probably cause wrong levels to be set, but hey,
@@ -490,6 +490,9 @@ class CommandCSSet : public Command
}
}
/* The above may have set an access entry to not be in use, this will clean that up. */
ci->CleanAccess();
reset_levels(ci);
ci->flags |= CI_XOP;
}
+39 -86
View File
@@ -109,7 +109,7 @@ class XOPBase : public Command
{
const char *nick = params.size() > 2 ? params[2].c_str() : NULL;
ChanAccess *access;
int change = 0, i;
int change = 0;
char event_access[BUFSIZE];
if (!nick)
@@ -145,44 +145,34 @@ class XOPBase : public Command
}
NickCore *nc = na->nc;
for (access = ci->access, i = 0; i < ci->accesscount; ++access, ++i)
access = ci->GetAccess(nc);
if (access)
{
if (access->nc == nc)
/**
* Patch provided by PopCorn to prevert AOP's reducing SOP's levels
**/
if (access->level >= ulev && !u->nc->HasPriv("chanserv/access/modify"))
{
/**
* Patch provided by PopCorn to prevert AOP's reducing SOP's levels
**/
if (access->level >= ulev && !u->nc->HasPriv("chanserv/access/modify"))
{
notice_lang(s_ChanServ, u, PERMISSION_DENIED);
return MOD_CONT;
}
++change;
break;
notice_lang(s_ChanServ, u, PERMISSION_DENIED);
return MOD_CONT;
}
++change;
}
if (!change && ci->access.size() >= CSAccessMax)
{
notice_lang(s_ChanServ, u, CHAN_XOP_REACHED_LIMIT, CSAccessMax);
return MOD_CONT;
}
if (!change)
ci->AddAccess(nc, level);
else
{
if (i < CSAccessMax)
{
++ci->accesscount;
ci->access = static_cast<ChanAccess *>(srealloc(ci->access, sizeof(ChanAccess) * ci->accesscount));
}
else
{
notice_lang(s_ChanServ, u, CHAN_XOP_REACHED_LIMIT, CSAccessMax);
return MOD_CONT;
}
access = &ci->access[i];
access->nc = nc;
access->level = level;
access->last_seen = 0;
}
access->in_use = 1;
access->level = level;
access->last_seen = 0;
alog("%s: %s!%s@%s (level %d) %s access level %d to %s (group %s) on channel %s", s_ChanServ, u->nick, u->GetIdent().c_str(), u->host, ulev, change ? "changed" : "set", access->level, na->nick, nc->display, ci->name);
snprintf(event_access, BUFSIZE, "%d", access->level);
@@ -205,9 +195,8 @@ class XOPBase : public Command
{
const char *nick = params.size() > 2 ? params[2].c_str() : NULL;
ChanAccess *access;
int i;
int deleted, a, b;
int deleted;
if (!nick)
{
@@ -221,7 +210,7 @@ class XOPBase : public Command
return MOD_CONT;
}
if (!ci->accesscount)
if (ci->access.empty())
{
notice_lang(s_ChanServ, u, messages[XOP_LIST_EMPTY], ci->name);
return MOD_CONT;
@@ -266,18 +255,14 @@ class XOPBase : public Command
return MOD_CONT;
}
NickCore *nc = na->nc;
access = ci->GetAccess(nc, level);
for (i = 0; i < ci->accesscount; ++i)
if (ci->access[i].nc == nc && ci->access[i].level == level)
break;
if (i == ci->accesscount)
if (!access)
{
notice_lang(s_ChanServ, u, messages[XOP_NOT_FOUND], nick, ci->name);
return MOD_CONT;
}
access = &ci->access[i];
if (ulev <= access->level && !u->nc->HasPriv("chanserv/access/change"))
{
deleted = 0;
@@ -294,41 +279,10 @@ class XOPBase : public Command
}
if (deleted)
{
/* Reordering - DrStein */
for (b = 0; b < ci->accesscount; ++b)
{
if (ci->access[b].in_use)
{
for (a = 0; a < ci->accesscount; ++a)
{
if (a > b)
break;
if (!ci->access[a].in_use)
{
ci->access[a].in_use = 1;
ci->access[a].level = ci->access[b].level;
ci->access[a].nc = ci->access[b].nc;
ci->access[a].last_seen = ci->access[b].last_seen;
ci->access[b].nc = NULL;
ci->access[b].in_use = 0;
break;
}
}
}
}
/* If the patch provided in bug #706 is applied, this should be placed
* before sending the events! */
/* After reordering only the entries at the end could still be empty.
* We ll free the places no longer in use... */
for (i = ci->accesscount - 1; i >= 0; --i)
{
if (ci->access[i].in_use == 1)
break;
--ci->accesscount;
}
ci->access = static_cast<ChanAccess *>(srealloc(ci->access, sizeof(ChanAccess) * ci->accesscount));
/* We'll free the access entries no longer in use... */
ci->CleanAccess();
}
return MOD_CONT;
@@ -345,7 +299,7 @@ class XOPBase : public Command
return MOD_CONT;
}
if (!ci->accesscount)
if (ci->access.empty())
{
notice_lang(s_ChanServ, u, messages[XOP_LIST_EMPTY], ci->name);
return MOD_CONT;
@@ -355,9 +309,10 @@ class XOPBase : public Command
process_numlist(nick, NULL, xop_list_callback, u, ci, &sent_header, level, messages[XOP_LIST_HEADER]);
else
{
for (int i = 0; i < ci->accesscount; ++i)
for (int i = 0; i < ci->access.size(); ++i)
{
if (nick && ci->access[i].nc && !Anope::Match(ci->access[i].nc->display, nick, false))
ChanAccess *access = ci->GetAccess(i);
if (nick && access->nc && !Anope::Match(access->nc->display, nick, false))
continue;
xop_list(u, i, ci, &sent_header, level, messages[XOP_LIST_HEADER]);
}
@@ -376,7 +331,7 @@ class XOPBase : public Command
return MOD_CONT;
}
if (!ci->accesscount)
if (ci->access.empty())
{
notice_lang(s_ChanServ, u, messages[XOP_LIST_EMPTY], ci->name);
return MOD_CONT;
@@ -388,13 +343,11 @@ class XOPBase : public Command
return MOD_CONT;
}
for (int i = 0; i < ci->accesscount; ++i)
for (unsigned i = ci->access.size(); i > 0; --i)
{
if (ci->access[i].in_use && ci->access[i].level == level)
{
ci->access[i].nc = NULL;
ci->access[i].in_use = 0;
}
ChanAccess *access = ci->GetAccess(i - 1);
if (access->in_use && access->level == level)
ci->EraseAccess(i - 1);
}
send_event(EVENT_ACCESS_CLEAR, 2, ci->name, u->nick);
@@ -600,17 +553,17 @@ int xop_del_callback(User *u, int num, va_list args)
int uacc = va_arg(args, int);
int xlev = va_arg(args, int);
if (num < 1 || num > ci->accesscount)
if (num < 1 || num > ci->access.size())
return 0;
*last = num;
return xop_del(u, ci, &ci->access[num - 1], perm, uacc, xlev);
return xop_del(u, ci, ci->GetAccess(num - 1), perm, uacc, xlev);
}
int xop_list(User *u, int index, ChannelInfo *ci, int *sent_header, int xlev, int xmsg)
{
ChanAccess *access = &ci->access[index];
ChanAccess *access = ci->GetAccess(index);
if (!access->in_use || access->level != xlev)
return 0;
@@ -632,7 +585,7 @@ int xop_list_callback(User *u, int num, va_list args)
int xlev = va_arg(args, int);
int xmsg = va_arg(args, int);
if (num < 1 || num > ci->accesscount)
if (num < 1 || num > ci->access.size())
return 0;
return xop_list(u, num - 1, ci, sent_header, xlev, xmsg);