summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/channels.h1
-rw-r--r--include/modules.h2
-rw-r--r--src/channels.cpp51
-rw-r--r--src/modules.cpp12
-rw-r--r--src/modules/m_messageflood.cpp73
-rw-r--r--src/modules/m_spanningtree.cpp19
6 files changed, 151 insertions, 7 deletions
diff --git a/include/channels.h b/include/channels.h
index c00ab0541..dd6d3b585 100644
--- a/include/channels.h
+++ b/include/channels.h
@@ -261,6 +261,7 @@ class ucrec : public classbase
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 kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason);
+void server_kick_channel(userrec* user, chanrec* Ptr, char* reason, bool triggerevents);
#endif
diff --git a/include/modules.h b/include/modules.h
index d920736a9..6afb0e181 100644
--- a/include/modules.h
+++ b/include/modules.h
@@ -1410,6 +1410,8 @@ class Server : public classbase
* action after calling this method is to immediately bail from your handler.
*/
virtual void QuitUser(userrec* user, std::string reason);
+
+ virtual void KickUser(userrec* source, userrec* target, chanrec* chan, std::string reason);
/** Matches text against a glob pattern.
* Uses the ircd's internal matching function to match string against a globbing pattern, e.g. *!*@*.com
diff --git a/src/channels.cpp b/src/channels.cpp
index 2b1fac5f2..9179c8002 100644
--- a/src/channels.cpp
+++ b/src/channels.cpp
@@ -451,6 +451,52 @@ chanrec* del_channel(userrec *user, const char* cname, const char* reason, bool
return NULL;
}
+void server_kick_channel(userrec* user, chanrec* Ptr, char* reason, bool triggerevents)
+{
+ if ((!user) || (!Ptr) || (!reason))
+ {
+ return;
+ }
+
+ if (!has_channel(user,Ptr))
+ {
+ /* Not on channel */
+ return;
+ }
+
+ if (triggerevents)
+ {
+ FOREACH_MOD(I_OnUserKick,OnUserKick(NULL,user,Ptr,reason));
+ }
+
+ for (unsigned int i =0; i < user->chans.size(); i++)
+ {
+ if (user->chans[i].channel)
+ if (!strcasecmp(user->chans[i].channel->name,Ptr->name))
+ {
+ WriteChannelWithServ(Ptr,"KICK %s %s :%s",Ptr->name, user->nick, reason);
+ user->chans[i].uc_modes = 0;
+ user->chans[i].channel = NULL;
+ break;
+ }
+ }
+
+ Ptr->DelUser((char*)user);
+
+ if (!usercount(Ptr))
+ {
+ chan_hash::iterator iter = chanlist.find(Ptr->name);
+ log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
+ /* kill the record */
+ if (iter != chanlist.end())
+ {
+ log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
+ FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(Ptr));
+ delete Ptr;
+ chanlist.erase(iter);
+ }
+ }
+}
void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason)
{
@@ -460,11 +506,6 @@ void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason)
return;
}
- if ((!Ptr) || (!user) || (!src))
- {
- return;
- }
-
log(DEBUG,"kick_channel: removing: %s %s %s",user->nick,Ptr->name,src->nick);
if (!has_channel(user,Ptr))
diff --git a/src/modules.cpp b/src/modules.cpp
index 390efe5bf..5ac49e75a 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -408,6 +408,18 @@ void Server::ChangeUserNick(userrec* user, std::string nickname)
force_nickchange(user,nickname.c_str());
}
+virtual void KickUser(userrec* source, userrec* target, chanrec* chan, std::string reason)
+{
+ if (source)
+ {
+ kick_channel(source,target,chan,reason);
+ }
+ else
+ {
+ server_kick_channel(target,chan,reason,true);
+ }
+}
+
void Server::QuitUser(userrec* user, std::string reason)
{
kill_link(user,reason.c_str());
diff --git a/src/modules/m_messageflood.cpp b/src/modules/m_messageflood.cpp
index 738857f29..0f0878646 100644
--- a/src/modules/m_messageflood.cpp
+++ b/src/modules/m_messageflood.cpp
@@ -17,6 +17,7 @@
using namespace std;
#include <stdio.h>
+#include <map>
#include "users.h"
#include "channels.h"
#include "modules.h"
@@ -30,9 +31,45 @@ class floodsettings
bool ban;
int secs;
int lines;
+ time_t reset;
+ std::map<userrec*,int> counters;
floodsettings() : ban(0), secs(0), lines(0) {};
- floodsettings(bool a, int b, int c) : ban(a), secs(b), lines(c) {};
+ floodsettings(bool a, int b, int c) : ban(a), secs(b), lines(c) { reset = time(NULL) + secs };
+
+ void addmessage(userrec* who)
+ {
+ std::map<userrec*,int>::iterator iter = counters.find(who);
+ if (iter != counters.end())
+ {
+ iter->second++;
+ log(DEBUG,"Count for %s is now %d",who->nick,iter->second);
+ }
+ if (reset > time(NULL))
+ {
+ counters.clear();
+ reset = time(NULL) + secs;
+ }
+ }
+
+ bool shouldkick(userrec* who)
+ {
+ std::map<userrec*,int>::iterator iter = counters.find(who);
+ if (iter != counters.end())
+ {
+ return (iter->second >= this->lines);
+ }
+ else return false;
+ }
+
+ void clear(userrec* who)
+ {
+ std::map<userrec*,int>::iterator iter = counters.find(who);
+ if (iter != counters.end())
+ {
+ counters.erase(iter);
+ }
+ }
};
class ModuleMsgFlood : public Module
@@ -124,6 +161,40 @@ class ModuleMsgFlood : public Module
return 0;
}
+ int ProcessMessages(userrec* user,chanrec* dest,std::string &text)
+ {
+ floodsettings *f = (floodsettings*)c->GetExt("flood");
+ if (f)
+ {
+ f->addmessage(user);
+ if (f->shouldkick(user))
+ {
+ /* Youre outttta here! */
+ f->clear(user);
+ Srv->KickUser(NULL, user, dest, "Channel flood triggered (mode +f)");
+ return 1;
+ }
+ }
+ }
+
+ virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text)
+ {
+ if (target_type == TYPE_CHANNEL)
+ {
+ return ProcessMessages(user,(chanrec*)dest,text);
+ }
+ else return 0;
+ }
+
+ virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text)
+ {
+ if (target_type == TYPE_CHANNEL)
+ {
+ return ProcessMessages(user,(chanrec*)dest,text);
+ }
+ else return 0;
+ }
+
void OnChannelDelete(chanrec* chan)
{
if (chan->GetExt("flood"))
diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp
index 124583ff1..7204c2435 100644
--- a/src/modules/m_spanningtree.cpp
+++ b/src/modules/m_spanningtree.cpp
@@ -2029,6 +2029,14 @@ class TreeSocket : public InspSocket
{
return this->ForceTopic(prefix,params);
}
+ else if ((command == "KICK") && (!Srv->FindNick(prefix)))
+ {
+ /* Server kick */
+ userrec* who = Srv->FindNick(params[1]);
+ chanrec* where = Srv->FindChannel(params[0]);
+ server_kick_channel(who, where, (char*)params[2].c_str(), false);
+ return true;
+ }
else if (command == "REHASH")
{
return this->RemoteRehash(prefix,params);
@@ -3054,7 +3062,16 @@ class ModuleSpanningTree : public Module
virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, std::string reason)
{
- if (source->fd > -1)
+ if (!source)
+ {
+ /* Server kick (ugh) */
+ std::deque<std::string> params;
+ params.push_back(chan->name);
+ params.push_back(user->nick);
+ params.push_back(":"+reason);
+ DoOneToMany(Srv->GetServerName(),"KICK",params);
+ }
+ else if (source->fd > -1)
{
std::deque<std::string> params;
params.push_back(chan->name);