summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mode.cpp4
-rw-r--r--src/modes/cmode_k.cpp5
-rw-r--r--src/modes/cmode_l.cpp6
-rw-r--r--src/modules/m_spanningtree.cpp186
4 files changed, 191 insertions, 10 deletions
diff --git a/src/mode.cpp b/src/mode.cpp
index d5ee5acdd..5b32c707a 100644
--- a/src/mode.cpp
+++ b/src/mode.cpp
@@ -292,13 +292,13 @@ void ModeParser::Process(const char** parameters, int pcnt, userrec *user, bool
* (e.g. are they a (half)op?
*/
- if (cstatus(user, targetchannel) < STATUS_HOP)
+ if ((IS_LOCAL(user)) && (cstatus(user, targetchannel) < STATUS_HOP))
{
/* We don't have halfop */
log(DEBUG,"The user is not a halfop or above, checking other reasons for being able to set the modes");
/* Are we a uline or is it a servermode? */
- if ((!is_uline(user->server)) && (!servermode) && (IS_LOCAL(user)))
+ if ((!is_uline(user->server)) && (!servermode))
{
/* Not enough permission:
* NOT a uline and NOT a servermode,
diff --git a/src/modes/cmode_k.cpp b/src/modes/cmode_k.cpp
index 5e55ce972..e54aa688a 100644
--- a/src/modes/cmode_k.cpp
+++ b/src/modes/cmode_k.cpp
@@ -20,6 +20,11 @@ std::pair<bool,std::string> ModeChannelKey::ModeSet(userrec* source, userrec* de
}
}
+bool ModeChannelKey::CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
+{
+ /* When TS is equal, the alphabetically later channel key wins */
+ return (their_param < our_param);
+}
ModeAction ModeChannelKey::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
{
diff --git a/src/modes/cmode_l.cpp b/src/modes/cmode_l.cpp
index a5fa5329b..89d67026c 100644
--- a/src/modes/cmode_l.cpp
+++ b/src/modes/cmode_l.cpp
@@ -20,6 +20,12 @@ std::pair<bool,std::string> ModeChannelLimit::ModeSet(userrec* source, userrec*
}
}
+bool ModeChannelLimit::CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
+{
+ /* When TS is equal, the higher channel limit wins */
+ return (atoi(their_param.c_str()) < atoi(our_param.c_str()));
+}
+
ModeAction ModeChannelLimit::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
{
if (adding)
diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp
index cd64ed7c5..77929b382 100644
--- a/src/modules/m_spanningtree.cpp
+++ b/src/modules/m_spanningtree.cpp
@@ -919,7 +919,6 @@ class TreeSocket : public InspSocket
{
/* Everything else is fine to append to the modelist */
modelist[n++] = params[q].c_str();
- log(DEBUG,"Add param: %s",params[q].c_str());
}
}
@@ -939,6 +938,182 @@ class TreeSocket : public InspSocket
ourTS = chan->age;
}
}
+
+ /* TS is equal: Merge the mode changes, use voooodoooooo on modes
+ * with parameters.
+ */
+ if (TS == ourTS)
+ {
+ log(DEBUG,"Entering TS equality check");
+ ModeHandler* mh = NULL;
+ unsigned long paramptr = 3;
+ std::string to_bounce = "";
+ std::string to_keep = "";
+ std::vector<std::string> params_to_keep;
+ std::string params_to_bounce = "";
+ bool adding = true;
+ char cur_change = 1;
+ char old_change = 0;
+ char old_bounce_change = 0;
+ /* Merge modes, basically do special stuff to mode with params */
+ for (std::string::iterator x = params[2].begin(); x != params[2].end(); x++)
+ {
+ switch (*x)
+ {
+ case '-':
+ adding = false;
+ break;
+ case '+':
+ adding = true;
+ break;
+ default:
+ if (adding)
+ {
+ /* We only care about whats being set,
+ * not whats being unset
+ */
+ mh = ServerInstance->ModeGrok->FindMode(*x, chan ? MODETYPE_CHANNEL : MODETYPE_USER);
+
+ if ((mh->GetNumParams(adding) > 0) && (!mh->IsListMode()))
+ {
+ /* We only want to do special things to
+ * modes with parameters, we are going to rewrite
+ * those parameters
+ */
+ std::pair<bool, std::string> ret;
+ adding ? cur_change = '+' : cur_change = '-';
+
+ ret = mh->ModeSet(smode ? NULL : who, dst, chan, params[paramptr]);
+
+ /* The mode is set here, check which we should keep */
+ if (ret.first)
+ {
+ bool which_to_keep = mh->CheckTimeStamp(TS, ourTS, params[paramptr], ret.second, chan);
+
+ if (which_to_keep == true)
+ {
+ /* Keep ours, bounce theirs:
+ * Send back ours to them and
+ * drop their mode changs
+ */
+ adding ? cur_change = '+' : cur_change = '-';
+ if (cur_change != old_bounce_change)
+ to_bounce += cur_change;
+ to_bounce += *x;
+ old_bounce_change = cur_change;
+
+ if ((mh->GetNumParams(adding) > 0) && (paramptr < params.size()))
+ params_to_bounce.append(" ").append(ret.second);
+ }
+ else
+ {
+ /* Keep theirs: Accept their mode change,
+ * do nothing else
+ */
+ adding ? cur_change = '+' : cur_change = '-';
+ if (cur_change != old_change)
+ to_keep += cur_change;
+ to_keep += *x;
+ old_change = cur_change;
+
+ if ((mh->GetNumParams(adding) > 0) && (paramptr < params.size()))
+ params_to_keep.push_back(params[paramptr]);
+ }
+ }
+ else
+ {
+ /* Mode isnt set here, we want it */
+ adding ? cur_change = '+' : cur_change = '-';
+ if (cur_change != old_change)
+ to_keep += cur_change;
+ to_keep += *x;
+ old_change = cur_change;
+
+ if ((mh->GetNumParams(adding) > 0) && (paramptr < params.size()))
+ params_to_keep.push_back(params[paramptr]);
+ }
+
+ paramptr++;
+ }
+ else
+ {
+ mh = ServerInstance->ModeGrok->FindMode(*x, chan ? MODETYPE_CHANNEL : MODETYPE_USER);
+
+ if (mh)
+ {
+ adding ? cur_change = '+' : cur_change = '-';
+
+ /* Just keep this, safe to merge with no checks
+ * it has no parameters
+ */
+
+ if (cur_change != old_change)
+ to_keep += cur_change;
+ to_keep += *x;
+ old_change = cur_change;
+
+ if ((mh->GetNumParams(adding) > 0) && (paramptr < params.size()))
+ {
+ log(DEBUG,"Mode removal %d %d",adding, mh->GetNumParams(adding));
+ params_to_keep.push_back(params[paramptr++]);
+ }
+ }
+ }
+ }
+ else
+ {
+ mh = ServerInstance->ModeGrok->FindMode(*x, chan ? MODETYPE_CHANNEL : MODETYPE_USER);
+
+ if (mh)
+ {
+ /* Taking a mode away */
+ adding ? cur_change = '+' : cur_change = '-';
+
+ if (cur_change != old_change)
+ to_keep += cur_change;
+ to_keep += *x;
+ old_change = cur_change;
+
+ if ((mh->GetNumParams(adding) > 0) && (paramptr < params.size()))
+ params_to_keep.push_back(params[paramptr++]);
+ }
+ }
+ break;
+ }
+ }
+
+ if (to_bounce.length())
+ {
+ std::deque<std::string> newparams;
+ newparams.push_back(params[0]);
+ newparams.push_back(ConvToStr(ourTS));
+ newparams.push_back(to_bounce+params_to_bounce);
+ DoOneToOne(Srv->GetServerName(),"FMODE",newparams,sourceserv);
+ }
+
+ if (to_keep.length())
+ {
+ n = 0;
+ modelist[0] = params[0].c_str();
+ modelist[1] = to_keep.c_str();
+
+ for (unsigned int q = 2; (q < params.size()) && (q < 64); q++)
+ modelist[q] = params_to_keep[n++].c_str();
+
+ if (smode)
+ {
+ Srv->SendMode(modelist, n+2, who);
+ }
+ else
+ {
+ Srv->CallCommandHandler("MODE", modelist, n+2, who);
+ }
+
+ /* HOT POTATO! PASS IT ON! */
+ DoOneToAllButSender(source,"FMODE",params,sourceserv);
+ }
+ }
+ else
/* U-lined servers always win regardless of their TS */
if ((TS > ourTS) && (!Srv->IsUlined(source)))
{
@@ -3938,9 +4113,6 @@ class ModuleSpanningTree : public Module
virtual void OnMode(userrec* user, void* dest, int target_type, const std::string &text)
{
- /* 1.1 Series InspIRCd Spanning Tree now uses FMODE for all user modes,
- * with a timestamp to prevent certain types of modehack
- */
if ((user->fd > -1) && (user->registered == 7))
{
if (target_type == TYPE_USER)
@@ -3948,18 +4120,16 @@ class ModuleSpanningTree : public Module
userrec* u = (userrec*)dest;
std::deque<std::string> params;
params.push_back(u->nick);
- params.push_back(ConvToStr(u->age));
params.push_back(text);
- DoOneToMany(user->nick,"FMODE",params);
+ DoOneToMany(user->nick,"MODE",params);
}
else
{
chanrec* c = (chanrec*)dest;
std::deque<std::string> params;
params.push_back(c->name);
- params.push_back(ConvToStr(c->age));
params.push_back(text);
- DoOneToMany(user->nick,"FMODE",params);
+ DoOneToMany(user->nick,"MODE",params);
}
}
}