summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/base.h6
-rw-r--r--include/inspircd.h2
-rw-r--r--include/modules.h74
-rw-r--r--src/InspIRCd.dev12
-rw-r--r--src/InspIRCd.layout101
-rw-r--r--src/base.cpp13
-rw-r--r--src/inspircd.cpp30
-rw-r--r--src/mode.cpp379
-rw-r--r--src/modules.cpp44
-rw-r--r--src/users.cpp4
10 files changed, 441 insertions, 224 deletions
diff --git a/include/base.h b/include/base.h
index e755fc951..9b9795229 100644
--- a/include/base.h
+++ b/include/base.h
@@ -39,7 +39,7 @@ class Extensible : public classbase
{
/** Private data store
*/
- std::map<std::string,VoidPointer> Extension_Items;
+ std::map<std::string,char*> Extension_Items;
public:
@@ -49,7 +49,7 @@ public:
* twice, Extensible::Extend will return false in this case.
* On successful extension, Extend returns true.
*/
- bool Extend(std::string key, VoidPointer p);
+ bool Extend(std::string key, char* p);
/** Shrink an Extensible class.
* You must provide a key name. The given key name will be removed from the classes data. If
@@ -62,7 +62,7 @@ public:
* You must provide a key name, which is case sensitive. If you provide a non-existent key name,
* the function returns NULL, otherwise a pointer to the item referenced by the key is returned.
*/
- VoidPointer GetExt(std::string key);
+ char* GetExt(std::string key);
};
#endif
diff --git a/include/inspircd.h b/include/inspircd.h
index d8967afb7..09e286cdc 100644
--- a/include/inspircd.h
+++ b/include/inspircd.h
@@ -110,6 +110,8 @@ bool ModeDefined(char c, int i);
bool ModeDefinedOper(char c, int i);
int ModeDefinedOn(char c, int i);
int ModeDefinedOff(char c, int i);
+void ModeMakeList(char modechar);
+bool ModeIsListMode(char modechar, int type);
chanrec* add_channel(userrec *user, const char* cn, const char* key, bool override);
chanrec* del_channel(userrec *user, const char* cname, const char* reason, bool local);
void force_nickchange(userrec* user,const char* newnick);
diff --git a/include/modules.h b/include/modules.h
index e6b4739d8..866bed269 100644
--- a/include/modules.h
+++ b/include/modules.h
@@ -8,16 +8,36 @@
#ifndef __PLUGIN_H
#define __PLUGIN_H
+// log levels
+
#define DEBUG 10
#define VERBOSE 20
#define DEFAULT 30
#define SPARSE 40
#define NONE 50
+// used with OnExtendedMode() method of modules
+
#define MT_CHANNEL 1
#define MT_CLIENT 2
#define MT_SERVER 3
+// used with OnAccessCheck() method of modules
+
+#define ACR_DEFAULT 0 // Do default action (act as if the module isnt even loaded)
+#define ACR_DENY 1 // deny the action
+#define ACR_ALLOW 2 // allow the action
+
+#define AC_KICK 0 // a user is being kicked
+#define AC_DEOP 1 // a user is being deopped
+#define AC_OP 2 // a user is being opped
+#define AC_VOICE 3 // a user is being voiced
+#define AC_DEVOICE 4 // a user is being devoiced
+#define AC_HALFOP 5 // a user is being halfopped
+#define AC_DEHALFOP 6 // a user is being dehalfopped
+#define AC_INVITE 7 // a user is being invited
+#define AC_GENERAL_MODE 8 // a user channel mode is being changed
+
#include "dynamic.h"
#include "base.h"
#include "ctables.h"
@@ -174,7 +194,7 @@ class Module : public classbase
* If the mode is a channel mode, target is a chanrec*, and if it is a user mode, target is a userrec*.
* You must cast this value yourself to make use of it.
*/
- virtual bool OnExtendedMode(userrec* user, void* target, char modechar, int type, bool mode_on, string_list &params);
+ virtual int OnExtendedMode(userrec* user, void* target, char modechar, int type, bool mode_on, string_list &params);
/** Called whenever a user is about to join a channel, before any processing is done.
* Returning any nonzero value from this function stops the process immediately, causing no
@@ -241,6 +261,29 @@ class Module : public classbase
* module to generate some meaninful output.
*/
virtual int OnUserPreNick(userrec* user, std::string newnick);
+
+ /** Called before an action which requires a channel privilage check.
+ * This function is called before many functions which check a users status on a channel, for example
+ * before opping a user, deopping a user, kicking a user, etc.
+ * There are several values for access_type which indicate for what reason access is being checked.
+ * These are:<br>
+ * AC_KICK (0) - A user is being kicked<br>
+ * AC_DEOP (1) - a user is being deopped<br>
+ * AC_OP (2) - a user is being opped<br>
+ * AC_VOICE (3) - a user is being voiced<br>
+ * AC_DEVOICE (4) - a user is being devoiced<br>
+ * AC_HALFOP (5) - a user is being halfopped<br>
+ * AC_DEHALFOP (6) - a user is being dehalfopped<br>
+ * AC_INVITE (7) - a user is being invited<br>
+ * AC_GENERAL_MODE (8) - a user channel mode is being changed<br>
+ * Upon returning from your function you must return either ACR_DEFAULT, to indicate the module wishes
+ * to do nothing, or ACR_DENY where approprate to deny the action, and ACR_ALLOW where appropriate to allow
+ * the action. Please note that in the case of some access checks (such as AC_GENERAL_MODE) access may be
+ * denied 'upstream' causing other checks such as AC_DEOP to not be reached. Be very careful with use of the
+ * AC_GENERAL_MODE type, as it may inadvertently override the behaviour of other modules. When the access_type
+ * is AC_GENERAL_MODE, the destination of the mode will be NULL (as it has not yet been determined).
+ */
+ virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type);
};
@@ -347,6 +390,10 @@ class Server : public classbase
* representing the user's privilages upon the channel you specify.
*/
virtual std::string ChanMode(userrec* User, chanrec* Chan);
+ /** Checks if a user is on a channel.
+ * This function will return true or false to indicate if user 'User' is on channel 'Chan'.
+ */
+ virtual bool IsOnChannel(userrec* User, chanrec* Chan);
/** Returns the server name of the server where the module is loaded.
*/
virtual std::string GetServerName();
@@ -359,7 +406,7 @@ class Server : public classbase
* server where the module is loaded.
*/
virtual Admin GetAdmin();
- /** Adds an extended mode letter which is parsed by a module
+ /** Adds an extended mode letter which is parsed by a module.
* This allows modules to add extra mode letters, e.g. +x for hostcloak.
* the "type" parameter is either MT_CHANNEL, MT_CLIENT, or MT_SERVER, to
* indicate wether the mode is a channel mode, a client mode, or a server mode.
@@ -379,6 +426,29 @@ class Server : public classbase
*/
virtual bool AddExtendedMode(char modechar, int type, bool requires_oper, int params_when_on, int params_when_off);
+ /** Adds an extended mode letter which is parsed by a module and handled in a list fashion.
+ * This call is used to implement modes like +q and +a. The characteristics of these modes are
+ * as follows:
+ *
+ * (1) They are ALWAYS on channels, not on users, therefore their type is MT_CHANNEL
+ *
+ * (2) They always take exactly one parameter when being added or removed
+ *
+ * (3) They can be set multiple times, usually on users in channels
+ *
+ * (4) The mode and its parameter are NOT stored in the channels modes structure
+ *
+ * It is down to the module handling the mode to maintain state and determine what 'items' (e.g. users,
+ * or a banlist) have the mode set on them, and process the modes at the correct times, e.g. during access
+ * checks on channels, etc. When the extended mode is triggered the OnExtendedMode method will be triggered
+ * as above. Note that the target you are given will be a channel, if for example your mode is set 'on a user'
+ * (in for example +a) you must use Server::Find to locate the user the mode is operating on.
+ * Your mode handler may return 1 to handle the mode AND tell the core to display the mode change, e.g.
+ * '+aaa one two three' in the case of the mode for 'two', or it may return -1 to 'eat' the mode change,
+ * so the above example would become '+aa one three' after processing.
+ */
+ virtual bool AddExtendedListMode(char modechar);
+
/** Adds a command to the command table.
* This allows modules to add extra commands into the command table. You must place a function within your
* module which is is of type handlerfunc:
diff --git a/src/InspIRCd.dev b/src/InspIRCd.dev
index f553ce649..2012957fc 100644
--- a/src/InspIRCd.dev
+++ b/src/InspIRCd.dev
@@ -1,7 +1,7 @@
[Project]
FileName=InspIRCd.dev
Name=InspIRCd - The Inspire Internet Relay Chat Daemon
-UnitCount=50
+UnitCount=51
Type=1
Ver=1
ObjFiles=
@@ -545,3 +545,13 @@ Priority=1000
OverrideBuildCmd=0
BuildCmd=
+[Unit51]
+FileName=modules\m_chanprotect.cpp
+CompileCpp=1
+Folder=Modules
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
diff --git a/src/InspIRCd.layout b/src/InspIRCd.layout
index 06ccc0a28..1e1e0138c 100644
--- a/src/InspIRCd.layout
+++ b/src/InspIRCd.layout
@@ -1,5 +1,5 @@
[Editors]
-Focused=6
+Focused=-1
Order=2,4,6,3,7,25,5,24,39,42,43,-1,1,46,0,49
[Editor_0]
@@ -13,9 +13,9 @@ LeftChar=1
[Editor_1]
Open=1
Top=0
-CursorCol=2
-CursorRow=211
-TopLine=180
+CursorCol=23
+CursorRow=1610
+TopLine=1575
LeftChar=1
[Editor_2]
@@ -37,9 +37,9 @@ LeftChar=1
[Editor_4]
Open=1
Top=0
-CursorCol=71
-CursorRow=120
-TopLine=92
+CursorCol=1
+CursorRow=330
+TopLine=298
LeftChar=1
[Editor_5]
@@ -52,9 +52,9 @@ LeftChar=1
[Editor_6]
Open=1
-Top=1
-CursorCol=24
-CursorRow=140
+Top=0
+CursorCol=1
+CursorRow=117
TopLine=94
LeftChar=1
@@ -77,17 +77,17 @@ LeftChar=1
[Editor_9]
Open=1
Top=0
-CursorCol=1
-CursorRow=113
+CursorCol=3
+CursorRow=66
TopLine=26
LeftChar=1
[Editor_10]
Open=1
Top=0
-CursorCol=1
-CursorRow=102
-TopLine=76
+CursorCol=13
+CursorRow=62
+TopLine=49
LeftChar=1
[Editor_11]
@@ -103,7 +103,7 @@ Open=1
Top=0
CursorCol=32
CursorRow=191
-TopLine=154
+TopLine=1
LeftChar=1
[Editor_13]
@@ -141,9 +141,9 @@ LeftChar=1
[Editor_17]
Open=1
Top=0
-CursorCol=1
-CursorRow=2
-TopLine=1
+CursorCol=46
+CursorRow=114
+TopLine=106
LeftChar=1
[Editor_18]
@@ -164,10 +164,10 @@ LeftChar=1
[Editor_20]
Open=1
-Top=0
-CursorCol=107
-CursorRow=164
-TopLine=140
+Top=1
+CursorCol=1
+CursorRow=40
+TopLine=1
LeftChar=1
[Editor_21]
@@ -189,9 +189,9 @@ LeftChar=1
[Editor_23]
Open=1
Top=0
-CursorCol=1
-CursorRow=69
-TopLine=14
+CursorCol=28
+CursorRow=42
+TopLine=2
LeftChar=1
[Editor_24]
@@ -206,21 +206,21 @@ Open=1
Top=0
CursorCol=1
CursorRow=23
-TopLine=1
+TopLine=46
LeftChar=1
[Editor_26]
Open=1
Top=0
-CursorCol=1
-CursorRow=13
-TopLine=23
+CursorCol=13
+CursorRow=49
+TopLine=32
LeftChar=1
[Editor_27]
Open=1
Top=0
-CursorCol=3
-CursorRow=67
-TopLine=34
+CursorCol=13
+CursorRow=50
+TopLine=6
LeftChar=1
[Editor_28]
Open=1
@@ -251,7 +251,7 @@ CursorRow=40
TopLine=8
LeftChar=1
[Editor_32]
-Open=0
+Open=1
Top=0
CursorCol=1
CursorRow=1
@@ -262,7 +262,7 @@ Open=1
Top=0
CursorCol=23
CursorRow=36
-TopLine=1
+TopLine=10
LeftChar=1
[Editor_34]
Open=1
@@ -288,9 +288,9 @@ LeftChar=1
[Editor_37]
Open=1
Top=0
-CursorCol=5
-CursorRow=90
-TopLine=63
+CursorCol=13
+CursorRow=160
+TopLine=1
LeftChar=1
[Editor_38]
Open=1
@@ -323,16 +323,16 @@ LeftChar=1
[Editor_42]
Open=1
Top=0
-CursorCol=10
-CursorRow=538
-TopLine=510
+CursorCol=128
+CursorRow=1210
+TopLine=1187
LeftChar=1
[Editor_43]
Open=1
Top=0
CursorCol=1
-CursorRow=86
-TopLine=49
+CursorRow=217
+TopLine=203
LeftChar=1
[Editor_44]
Open=1
@@ -358,8 +358,8 @@ LeftChar=1
[Editor_47]
Open=1
Top=0
-CursorCol=1
-CursorRow=52
+CursorCol=32
+CursorRow=46
TopLine=4
LeftChar=1
[Editor_48]
@@ -372,7 +372,14 @@ LeftChar=1
[Editor_49]
Open=1
Top=0
-CursorCol=1
-CursorRow=32
+CursorCol=31
+CursorRow=14
TopLine=1
LeftChar=1
+[Editor_50]
+Open=1
+Top=0
+CursorCol=1
+CursorRow=9
+TopLine=37
+LeftChar=1
diff --git a/src/base.cpp b/src/base.cpp
index 7e545694b..f1f66bd93 100644
--- a/src/base.cpp
+++ b/src/base.cpp
@@ -3,13 +3,16 @@
#include <time.h>
#include <map>
#include <string>
+#include "inspircd.h"
+#include "modules.h"
-bool Extensible::Extend(std::string key, VoidPointer p)
+bool Extensible::Extend(std::string key, char* p)
{
// only add an item if it doesnt already exist
if (this->Extension_Items.find(key) == this->Extension_Items.end())
{
- this->Extension_Items[key] == p;
+ this->Extension_Items[key] = p;
+ log(DEBUG,"Extending object with item %s",key.c_str());
return true;
}
// item already exists, return false
@@ -22,17 +25,21 @@ bool Extensible::Shrink(std::string key)
if (this->Extension_Items.find(key) != this->Extension_Items.end())
{
this->Extension_Items.erase(this->Extension_Items.find(key));
+ log(DEBUG,"Shrinking object with item %s",key.c_str());
return true;
}
return false;
}
-VoidPointer Extensible::GetExt(std::string key)
+char* Extensible::GetExt(std::string key)
{
+ log(DEBUG,"Checking extension items for %s",key.c_str());
if (this->Extension_Items.find(key) != this->Extension_Items.end())
{
+ log(DEBUG,"Found item %s %s",key.c_str(),(this->Extension_Items.find(key))->second);
return (this->Extension_Items.find(key))->second;
}
+ log(DEBUG,"Cant find item %s",key.c_str());
return NULL;
}
diff --git a/src/inspircd.cpp b/src/inspircd.cpp
index f313c64c7..310ef4043 100644
--- a/src/inspircd.cpp
+++ b/src/inspircd.cpp
@@ -1310,6 +1310,7 @@ chanrec* add_channel(userrec *user, const char* cn, const char* key, bool overri
if (!FindChan(cname))
{
+ int MOD_RESULT = 0;
FOREACH_RESULT(OnUserPreJoin(user,NULL,cname));
if (MOD_RESULT) {
return NULL;
@@ -1347,6 +1348,7 @@ chanrec* add_channel(userrec *user, const char* cn, const char* key, bool overri
// and bans (used by servers)
if (!override)
{
+ int MOD_RESULT = 0;
FOREACH_RESULT(OnUserPreJoin(user,Ptr,cname));
if (MOD_RESULT) {
return NULL;
@@ -1600,18 +1602,28 @@ void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason)
WriteServ(src->fd,"441 %s %s %s :They are not on that channel",src->nick, user->nick, Ptr->name);
return;
}
- if (((cstatus(src,Ptr) < STATUS_HOP) || (cstatus(src,Ptr) < cstatus(user,Ptr))) && (!is_uline(src->server)))
+
+ int MOD_RESULT = 0;
+ FOREACH_RESULT(OnAccessCheck(src,user,Ptr,AC_KICK));
+
+ if (MOD_RESULT == ACR_DENY)
+ return;
+
+ if (MOD_RESULT == ACR_DEFAULT)
{
- if (cstatus(src,Ptr) == STATUS_HOP)
- {
- WriteServ(src->fd,"482 %s %s :You must be a channel operator",src->nick, Ptr->name);
- }
- else
+ if (((cstatus(src,Ptr) < STATUS_HOP) || (cstatus(src,Ptr) < cstatus(user,Ptr))) && (!is_uline(src->server)))
{
- WriteServ(src->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",src->nick, Ptr->name);
+ if (cstatus(src,Ptr) == STATUS_HOP)
+ {
+ WriteServ(src->fd,"482 %s %s :You must be a channel operator",src->nick, Ptr->name);
+ }
+ else
+ {
+ WriteServ(src->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",src->nick, Ptr->name);
+ }
+
+ return;
}
-
- return;
}
for (int i =0; i != MAXCHANS; i++)
diff --git a/src/mode.cpp b/src/mode.cpp
index c5f179f24..4a7c56bd3 100644
--- a/src/mode.cpp
+++ b/src/mode.cpp
@@ -71,47 +71,56 @@ char* give_ops(userrec *user,char *dest,chanrec *chan,int status)
log(DEFAULT,"*** BUG *** give_ops was given an invalid parameter");
return NULL;
}
- if ((status < STATUS_OP) && (!is_uline(user->server)))
+
+ if (!isnick(dest))
+ {
+ log(DEFAULT,"the target nickname given to give_ops was invalid");
+ WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+ return NULL;
+ }
+ d = Find(dest);
+ if (!d)
{
- log(DEBUG,"%s cant give ops to %s because they nave status %d and needs %d",user->nick,dest,status,STATUS_OP);
- WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
+ log(DEFAULT,"the target nickname given to give_ops couldnt be found");
+ WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
return NULL;
}
else
{
- if (!isnick(dest))
- {
- log(DEFAULT,"the target nickname given to give_ops was invalid");
- WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+
+ int MOD_RESULT = 0;
+ FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_OP));
+
+ if (MOD_RESULT == ACR_DENY)
return NULL;
- }
- d = Find(dest);
- if (!d)
+ if (MOD_RESULT == ACR_DEFAULT)
{
- log(DEFAULT,"the target nickname given to give_ops couldnt be found");
- WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
- return NULL;
+ if ((status < STATUS_OP) && (!is_uline(user->server)))
+ {
+ log(DEBUG,"%s cant give ops to %s because they nave status %d and needs %d",user->nick,dest,status,STATUS_OP);
+ WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
+ return NULL;
+ }
}
- else
+
+
+ for (int i = 0; i != MAXCHANS; i++)
{
- for (int i = 0; i != MAXCHANS; i++)
+ if ((d->chans[i].channel != NULL) && (chan != NULL))
+ if (!strcasecmp(d->chans[i].channel->name,chan->name))
{
- if ((d->chans[i].channel != NULL) && (chan != NULL))
- if (!strcasecmp(d->chans[i].channel->name,chan->name))
+ if (d->chans[i].uc_modes & UCMODE_OP)
{
- if (d->chans[i].uc_modes & UCMODE_OP)
- {
- /* mode already set on user, dont allow multiple */
- log(DEFAULT,"The target user given to give_ops was already opped on the channel");
- return NULL;
- }
- d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_OP;
- log(DEBUG,"gave ops: %s %s",d->chans[i].channel->name,d->nick);
- return d->nick;
+ /* mode already set on user, dont allow multiple */
+ log(DEFAULT,"The target user given to give_ops was already opped on the channel");
+ return NULL;
}
+ d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_OP;
+ log(DEBUG,"gave ops: %s %s",d->chans[i].channel->name,d->nick);
+ return d->nick;
}
- log(DEFAULT,"The target channel given to give_ops was not in the users mode list");
}
+ log(DEFAULT,"The target channel given to give_ops was not in the users mode list");
}
return NULL;
}
@@ -126,40 +135,47 @@ char* give_hops(userrec *user,char *dest,chanrec *chan,int status)
log(DEFAULT,"*** BUG *** give_hops was given an invalid parameter");
return NULL;
}
- if ((status < STATUS_OP) && (!is_uline(user->server)))
+
+ d = Find(dest);
+ if (!isnick(dest))
+ {
+ WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+ return NULL;
+ }
+ if (!d)
{
- WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
+ WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
return NULL;
}
else
{
- d = Find(dest);
- if (!isnick(dest))
- {
- WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+ int MOD_RESULT = 0;
+ FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_HALFOP));
+
+ if (MOD_RESULT == ACR_DENY)
return NULL;
- }
- if (!d)
+ if (MOD_RESULT == ACR_DEFAULT)
{
- WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
- return NULL;
+ if ((status < STATUS_OP) && (!is_uline(user->server)))
+ {
+ WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
+ return NULL;
+ }
}
- else
+
+ for (int i = 0; i != MAXCHANS; i++)
{
- for (int i = 0; i != MAXCHANS; i++)
+ if ((d->chans[i].channel != NULL) && (chan != NULL))
+ if (!strcasecmp(d->chans[i].channel->name,chan->name))
{
- if ((d->chans[i].channel != NULL) && (chan != NULL))
- if (!strcasecmp(d->chans[i].channel->name,chan->name))
+ if (d->chans[i].uc_modes & UCMODE_HOP)
{
- if (d->chans[i].uc_modes & UCMODE_HOP)
- {
- /* mode already set on user, dont allow multiple */
- return NULL;
- }
- d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_HOP;
- log(DEBUG,"gave h-ops: %s %s",d->chans[i].channel->name,d->nick);
- return d->nick;
+ /* mode already set on user, dont allow multiple */
+ return NULL;
}
+ d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_HOP;
+ log(DEBUG,"gave h-ops: %s %s",d->chans[i].channel->name,d->nick);
+ return d->nick;
}
}
}
@@ -176,40 +192,47 @@ char* give_voice(userrec *user,char *dest,chanrec *chan,int status)
log(DEFAULT,"*** BUG *** give_voice was given an invalid parameter");
return NULL;
}
- if ((status < STATUS_HOP) && (!is_uline(user->server)))
+
+ d = Find(dest);
+ if (!isnick(dest))
+ {
+ WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+ return NULL;
+ }
+ if (!d)
{
- WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, chan->name);
+ WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
return NULL;
}
else
{
- d = Find(dest);
- if (!isnick(dest))
- {
- WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+ int MOD_RESULT = 0;
+ FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_VOICE));
+
+ if (MOD_RESULT == ACR_DENY)
return NULL;
- }
- if (!d)
+ if (MOD_RESULT == ACR_DEFAULT)
{
- WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
- return NULL;
+ if ((status < STATUS_HOP) && (!is_uline(user->server)))
+ {
+ WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, chan->name);
+ return NULL;
+ }
}
- else
+
+ for (int i = 0; i != MAXCHANS; i++)
{
- for (int i = 0; i != MAXCHANS; i++)
+ if ((d->chans[i].channel != NULL) && (chan != NULL))
+ if (!strcasecmp(d->chans[i].channel->name,chan->name))
{
- if ((d->chans[i].channel != NULL) && (chan != NULL))
- if (!strcasecmp(d->chans[i].channel->name,chan->name))
+ if (d->chans[i].uc_modes & UCMODE_VOICE)
{
- if (d->chans[i].uc_modes & UCMODE_VOICE)
- {
- /* mode already set on user, dont allow multiple */
- return NULL;
- }
- d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_VOICE;
- log(DEBUG,"gave voice: %s %s",d->chans[i].channel->name,d->nick);
- return d->nick;
+ /* mode already set on user, dont allow multiple */
+ return NULL;
}
+ d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_VOICE;
+ log(DEBUG,"gave voice: %s %s",d->chans[i].channel->name,d->nick);
+ return d->nick;
}
}
}
@@ -226,46 +249,52 @@ char* take_ops(userrec *user,char *dest,chanrec *chan,int status)
log(DEFAULT,"*** BUG *** take_ops was given an invalid parameter");
return NULL;
}
- if ((status < STATUS_OP) && (!is_uline(user->server)))
+
+ d = Find(dest);
+ if (!isnick(dest))
+ {
+ log(DEBUG,"take_ops was given an invalid target nickname of %s",dest);
+ WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+ return NULL;
+ }
+ if (!d)
{
- log(DEBUG,"%s cant give ops to %s because they have status %d and needs %d",user->nick,dest,status,STATUS_OP);
- WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
+ log(DEBUG,"take_ops couldnt resolve the target nickname: %s",dest);
+ WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
return NULL;
}
else
{
- d = Find(dest);
- if (!isnick(dest))
- {
- log(DEBUG,"take_ops was given an invalid target nickname of %s",dest);
- WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+ int MOD_RESULT = 0;
+ FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_DEOP));
+
+ if (MOD_RESULT == ACR_DENY)
return NULL;
- }
- if (!d)
+ if (MOD_RESULT == ACR_DEFAULT)
{
- log(DEBUG,"take_ops couldnt resolve the target nickname: %s",dest);
- WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
- return NULL;
+ if ((status < STATUS_OP) && (!is_uline(user->server)))
+ {
+ WriteServ(user->fd,"482 %s %s :You are not a channel operator",user->nick, chan->name);
+ return NULL;
+ }
}
- else
+
+ for (int i = 0; i != MAXCHANS; i++)
{
- for (int i = 0; i != MAXCHANS; i++)
+ if ((d->chans[i].channel != NULL) && (chan != NULL))
+ if (!strcasecmp(d->chans[i].channel->name,chan->name))
{
- if ((d->chans[i].channel != NULL) && (chan != NULL))
- if (!strcasecmp(d->chans[i].channel->name,chan->name))
+ if ((d->chans[i].uc_modes & UCMODE_OP) == 0)
{
- if ((d->chans[i].uc_modes & UCMODE_OP) == 0)
- {
- /* mode already set on user, dont allow multiple */
- return NULL;
- }
- d->chans[i].uc_modes ^= UCMODE_OP;
- log(DEBUG,"took ops: %s %s",d->chans[i].channel->name,d->nick);
- return d->nick;
+ /* mode already set on user, dont allow multiple */
+ return NULL;
}
+ d->chans[i].uc_modes ^= UCMODE_OP;
+ log(DEBUG,"took ops: %s %s",d->chans[i].channel->name,d->nick);
+ return d->nick;
}
- log(DEBUG,"take_ops couldnt locate the target channel in the target users list");
}
+ log(DEBUG,"take_ops couldnt locate the target channel in the target users list");
}
return NULL;
}
@@ -280,40 +309,47 @@ char* take_hops(userrec *user,char *dest,chanrec *chan,int status)
log(DEFAULT,"*** BUG *** take_hops was given an invalid parameter");
return NULL;
}
- if ((status < STATUS_OP) && (!is_uline(user->server)))
+
+ d = Find(dest);
+ if (!isnick(dest))
+ {
+ WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+ return NULL;
+ }
+ if (!d)
{
- WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
+ WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
return NULL;
}
else
{
- d = Find(dest);
- if (!isnick(dest))
- {
- WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+ int MOD_RESULT = 0;
+ FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_DEHALFOP));
+
+ if (MOD_RESULT == ACR_DENY)
return NULL;
- }
- if (!d)
+ if (MOD_RESULT == ACR_DEFAULT)
{
- WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
- return NULL;
+ if ((status < STATUS_OP) && (!is_uline(user->server)))
+ {
+ WriteServ(user->fd,"482 %s %s :You are not a channel operator",user->nick, chan->name);
+ return NULL;
+ }
}
- else
+
+ for (int i = 0; i != MAXCHANS; i++)
{
- for (int i = 0; i != MAXCHANS; i++)
+ if ((d->chans[i].channel != NULL) && (chan != NULL))
+ if (!strcasecmp(d->chans[i].channel->name,chan->name))
{
- if ((d->chans[i].channel != NULL) && (chan != NULL))
- if (!strcasecmp(d->chans[i].channel->name,chan->name))
+ if ((d->chans[i].uc_modes & UCMODE_HOP) == 0)
{
- if ((d->chans[i].uc_modes & UCMODE_HOP) == 0)
- {
- /* mode already set on user, dont allow multiple */
- return NULL;
- }
- d->chans[i].uc_modes ^= UCMODE_HOP;
- log(DEBUG,"took h-ops: %s %s",d->chans[i].channel->name,d->nick);
- return d->nick;
+ /* mode already set on user, dont allow multiple */
+ return NULL;
}
+ d->chans[i].uc_modes ^= UCMODE_HOP;
+ log(DEBUG,"took h-ops: %s %s",d->chans[i].channel->name,d->nick);
+ return d->nick;
}
}
}
@@ -330,40 +366,47 @@ char* take_voice(userrec *user,char *dest,chanrec *chan,int status)
log(DEFAULT,"*** BUG *** take_voice was given an invalid parameter");
return NULL;
}
- if ((status < STATUS_HOP) && (!is_uline(user->server)))
+
+ d = Find(dest);
+ if (!isnick(dest))
+ {
+ WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+ return NULL;
+ }
+ if (!d)
{
- WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, chan->name);
+ WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
return NULL;
}
else
{
- d = Find(dest);
- if (!isnick(dest))
- {
- WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
+ int MOD_RESULT = 0;
+ FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_DEVOICE));
+
+ if (MOD_RESULT == ACR_DENY)
return NULL;
- }
- if (!d)
+ if (MOD_RESULT == ACR_DEFAULT)
{
- WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
- return NULL;
+ if ((status < STATUS_HOP) && (!is_uline(user->server)))
+ {
+ WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, chan->name);
+ return NULL;
+ }
}
- else
+
+ for (int i = 0; i != MAXCHANS; i++)
{
- for (int i = 0; i != MAXCHANS; i++)
+ if ((d->chans[i].channel != NULL) && (chan != NULL))
+ if (!strcasecmp(d->chans[i].channel->name,chan->name))
{
- if ((d->chans[i].channel != NULL) && (chan != NULL))
- if (!strcasecmp(d->chans[i].channel->name,chan->name))
+ if ((d->chans[i].uc_modes & UCMODE_VOICE) == 0)
{
- if ((d->chans[i].uc_modes & UCMODE_VOICE) == 0)
- {
- /* mode already set on user, dont allow multiple */
- return NULL;
- }
- d->chans[i].uc_modes ^= UCMODE_VOICE;
- log(DEBUG,"took voice: %s %s",d->chans[i].channel->name,d->nick);
- return d->nick;
+ /* mode already set on user, dont allow multiple */
+ return NULL;
}
+ d->chans[i].uc_modes ^= UCMODE_VOICE;
+ log(DEBUG,"took voice: %s %s",d->chans[i].channel->name,d->nick);
+ return d->nick;
}
}
}
@@ -463,6 +506,12 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
return;
}
+ int MOD_RESULT = 0;
+ FOREACH_RESULT(OnAccessCheck(user,NULL,chan,AC_GENERAL_MODE));
+
+ if (MOD_RESULT == ACR_DENY)
+ return;
+
log(DEBUG,"process_modes: start: parameters=%d",pcnt);
strcpy(modelist,parameters[1]); /* mode list, e.g. +oo-o */
@@ -753,8 +802,11 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
p.clear();
if (((!strchr(chan->custom_modes,modechar)) && (!mdir)) || ((strchr(chan->custom_modes,modechar)) && (mdir)))
{
- log(DEBUG,"Mode %c isnt set on %s but trying to remove!",modechar,chan->name);
- break;
+ if (!ModeIsListMode(modechar,MT_CHANNEL))
+ {
+ log(DEBUG,"Mode %c isnt set on %s but trying to remove!",modechar,chan->name);
+ break;
+ }
}
if (ModeDefined(modechar,MT_CHANNEL))
{
@@ -785,27 +837,46 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
{
if (!handled)
{
- if (modules[i]->OnExtendedMode(user,chan,modechar,MT_CHANNEL,mdir,p))
+ int t = modules[i]->OnExtendedMode(user,chan,modechar,MT_CHANNEL,mdir,p);
+ if (t != 0)
{
log(DEBUG,"OnExtendedMode returned nonzero for a module");
char app[] = {modechar, 0};
- if (ptr>0)
+ if (ModeIsListMode(modechar,MT_CHANNEL))
{
- if ((modelist[ptr-1] == '+') || (modelist[ptr-1] == '-'))
+ if (t == -1)
{
- strcat(outlist, app);
+ pc++;
}
- else if (!strchr(outlist,modechar))
+ else
{
- strcat(outlist, app);
+ if (ptr>0)
+ {
+ strcat(outlist, app);
+ }
+ strcpy(outpars[pc++],parameters[param++]);
}
}
- chan->SetCustomMode(modechar,mdir);
- // include parameters in output if mode has them
- if ((ModeDefinedOn(modechar,MT_CHANNEL)>0) && (mdir))
+ else
{
- chan->SetCustomModeParam(modelist[ptr],parameters[param],mdir);
- strcpy(outpars[pc++],parameters[param++]);
+ if (ptr>0)
+ {
+ if ((modelist[ptr-1] == '+') || (modelist[ptr-1] == '-'))
+ {
+ strcat(outlist, app);
+ }
+ else if (!strchr(outlist,modechar))
+ {
+ strcat(outlist, app);
+ }
+ }
+ chan->SetCustomMode(modechar,mdir);
+ // include parameters in output if mode has them
+ if ((ModeDefinedOn(modechar,MT_CHANNEL)>0) && (mdir))
+ {
+ chan->SetCustomModeParam(modelist[ptr],parameters[param],mdir);
+ strcpy(outpars[pc++],parameters[param++]);
+ }
}
// break, because only one module can handle the mode.
handled = true;
diff --git a/src/modules.cpp b/src/modules.cpp
index d2f012977..d4d647d7e 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -26,6 +26,7 @@ public:
int params_when_on;
int params_when_off;
bool needsoper;
+ bool list;
ExtMode(char mc, int ty, bool oper, int p_on, int p_off) : modechar(mc), type(ty), needsoper(oper), params_when_on(p_on), params_when_off(p_off) { };
};
@@ -49,6 +50,20 @@ bool ModeDefined(char modechar, int type)
return false;
}
+bool ModeIsListMode(char modechar, int type)
+{
+ log(DEBUG,"Size of extmodes vector is %d",EMode.size());
+ for (ExtModeListIter i = EMode.begin(); i < EMode.end(); i++)
+ {
+ log(DEBUG,"i->modechar==%c, modechar=%c, i->type=%d, type=%d",i->modechar,modechar,i->type,type);
+ if ((i->modechar == modechar) && (i->type == type) && (i->list == true))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
bool ModeDefinedOper(char modechar, int type)
{
log(DEBUG,"Size of extmodes vector is %d",EMode.size());
@@ -99,6 +114,19 @@ bool DoAddExtendedMode(char modechar, int type, bool requires_oper, int params_o
return true;
}
+// turns a mode into a listmode
+void ModeMakeList(char modechar)
+{
+ for (ExtModeListIter i = EMode.begin(); i < EMode.end(); i++)
+ {
+ if ((i->modechar == modechar) && (i->type == MT_CHANNEL))
+ {
+ i->list = true;
+ return;
+ }
+ }
+ return;
+}
// version is a simple class for holding a modules version number
@@ -119,7 +147,7 @@ void Module::OnPacketReceive(char *p) { }
void Module::OnRehash() { }
void Module::OnServerRaw(std::string &raw, bool inbound, userrec* user) { }
int Module::OnUserPreJoin(userrec* user, chanrec* chan, const char* cname) { return 0; }
-bool Module::OnExtendedMode(userrec* user, void* target, char modechar, int type, bool mode_on, string_list &params) { return false; }
+int Module::OnExtendedMode(userrec* user, void* target, char modechar, int type, bool mode_on, string_list &params) { return false; }
Version Module::GetVersion() { return Version(1,0,0,0); }
void Module::OnOper(userrec* user) { };
void Module::OnInfo(userrec* user) { };
@@ -127,6 +155,7 @@ void Module::OnWhois(userrec* source, userrec* dest) { };
int Module::OnUserPreMessage(userrec* user,void* dest,int target_type, std::string text) { return 0; };
int Module::OnUserPreNotice(userrec* user,void* dest,int target_type, std::string text) { return 0; };
int Module::OnUserPreNick(userrec* user, std::string newnick) { return 0; };
+int Module::OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type) { return ACR_DEFAULT; };
// server is a wrapper class that provides methods to all of the C-style
// exports in the core
@@ -297,6 +326,11 @@ std::string Server::ChanMode(userrec* User, chanrec* Chan)
return cmode(User,Chan);
}
+bool Server::IsOnChannel(userrec* User, chanrec* Chan)
+{
+ return has_channel(User,Chan);
+}
+
std::string Server::GetServerName()
{
return getservername();
@@ -334,6 +368,14 @@ bool Server::AddExtendedMode(char modechar, int type, bool requires_oper, int pa
return DoAddExtendedMode(modechar,type,requires_oper,params_when_on,params_when_off);
}
+bool Server::AddExtendedListMode(char modechar)
+{
+ bool res = DoAddExtendedMode(modechar,MT_CHANNEL,false,1,1);
+ if (res)
+ ModeMakeList(modechar);
+ return res;
+}
+
int Server::CountUsers(chanrec* c)
{
return usercount(c);
diff --git a/src/users.cpp b/src/users.cpp
index b523033ba..cdb93a40f 100644
--- a/src/users.cpp
+++ b/src/users.cpp
@@ -114,7 +114,6 @@ bool userrec::HasPermission(char* command)
log(DEBUG,"*** HasPermission: %s is an oper of type '%s'",this->nick,this->oper);
ConfValue("type","classes",j,Classes,&config_f);
char* myclass = strtok_r(Classes," ",&savept);
- //myclass = savept;
while (myclass)
{
log(DEBUG,"*** HasPermission: checking classtype '%s'",myclass);
@@ -128,7 +127,6 @@ bool userrec::HasPermission(char* command)
mycmd = strtok_r(CommandList," ",&savept2);
- //mycmd = savept2;
while (mycmd)
{
if (!strcasecmp(mycmd,command))
@@ -137,12 +135,10 @@ bool userrec::HasPermission(char* command)
return true;
}
mycmd = strtok_r(NULL," ",&savept2);
- //mycmd = savept2;
}
}
}
myclass = strtok_r(NULL," ",&savept);
- //myclass = savept;
}
}
}