X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmode.cpp;h=3842b01e6ea02301b5d3b86e2221d89948dd1409;hb=84a19a9ab6129deb71cdc24b216b74dd8eb80978;hp=913cea8a0faaf2ba556d4eb37e4c063b0e4ac143;hpb=0da6981ee161cbf86de1171dde94cbc915946262;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/mode.cpp b/src/mode.cpp index 913cea8a0..3842b01e6 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -3,7 +3,7 @@ * +------------------------------------+ * * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev. - * E-mail: + * E-mail: * * * @@ -18,7 +18,7 @@ using namespace std; #include "inspircd_config.h" #include "inspircd.h" -#include "inspircd_io.h" +#include "configreader.h" #include #include #include @@ -54,6 +54,80 @@ extern ServerConfig* Config; extern time_t TIME; +ModeHandler::ModeHandler(char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly) : mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), oper(operonly) +{ +} + +ModeHandler::~ModeHandler() +{ +} + +bool ModeHandler::IsListMode() +{ + return list; +} + +ModeType ModeHandler::GetModeType() +{ + return m_type; +} + +bool ModeHandler::NeedsOper() +{ + return oper; +} + +int ModeHandler::GetNumParams(bool adding) +{ + return adding ? n_params_on : n_params_off; +} + +char ModeHandler::GetModeChar() +{ + return mode; +} + +ModeAction ModeHandler::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) +{ + return MODEACTION_DENY; +} + +void ModeHandler::DisplayList(userrec* user, chanrec* channel) +{ +} + +bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel) +{ + return (ours < theirs); +} + +ModeWatcher::ModeWatcher(char modeletter, ModeType type) : mode(modeletter), m_type(type) +{ +} + +ModeWatcher::~ModeWatcher() +{ +} + +char ModeWatcher::GetModeChar() +{ + return mode; +} + +ModeType ModeWatcher::GetModeType() +{ + return m_type; +} + +bool ModeWatcher::BeforeMode(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding, ModeType type) +{ + return true; +} + +void ModeWatcher::AfterMode(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter, bool adding, ModeType type) +{ +} + userrec* ModeParser::SanityChecks(userrec *user,char *dest,chanrec *chan,int status) { userrec *d; @@ -390,10 +464,10 @@ char* ModeParser::TakeBan(userrec *user,char *dest,chanrec *chan,int status) { if (!strcasecmp(i->data,dest)) { - int MOD_RESULT = 0; - FOREACH_RESULT(I_OnDelBan,OnDelBan(user,chan,dest)); - if (MOD_RESULT) - return NULL; + int MOD_RESULT = 0; + FOREACH_RESULT(I_OnDelBan,OnDelBan(user,chan,dest)); + if (MOD_RESULT) + return NULL; chan->bans.erase(i); return dest; } @@ -401,55 +475,143 @@ char* ModeParser::TakeBan(userrec *user,char *dest,chanrec *chan,int status) return NULL; } - -/** ModeParser::CompressModes() - * Tidies up redundant modes, - * e.g. +nt-nt+i becomes +-+i - * A section further down the chain tidies up the +-+- crap. - */ -std::string ModeParser::CompressModes(std::string modes,bool channelmodes) +void ModeParser::Process(char **parameters, int pcnt, userrec *user, bool servermode) { - /* - * OK, iterate over the mode string and count how many times a certain mode appears in it. - * Then, erase all instances of any character that appears more than once. - * This only operates on modes with no parameters, you can still +v-v+v-v+v-v to your heart's content. - */ - - /* Do we really need an int here? Can you fit enough modes in a line to overflow a short? */ - short counts[127]; - bool active[127]; - memset(counts, 0, sizeof(counts)); - memset(active, 0, sizeof(active)); - - for(unsigned char* i = (unsigned char*)modes.c_str(); *i; i++) - { - if((*i == '+') || (*i == '-')) - continue; + std::string target = parameters[0]; + ModeType type = MODETYPE_USER; + chanrec* targetchannel = FindChan(parameters[0]); + userrec* targetuser = Find(parameters[0]); - if(!channelmodes || (channelmodes && (strchr("itnmsp", *i) || (ModeDefined(*i, MT_CHANNEL) && !ModeDefinedOn(*i,MT_CHANNEL) && !ModeDefinedOff(*i,MT_CHANNEL))))) + if (pcnt > 1) + { + if (targetchannel) { - log(DEBUG,"Tidy mode %c", *i); - counts[*i]++; - active[*i] = true; + type = MODETYPE_CHANNEL; } - } - - for(unsigned char j = 65; j < 127; j++) - { - if ((counts[j] > 1) && (active[j] == true)) + else if (targetuser) { - std::string::size_type pos; + type = MODETYPE_USER; + } + else + { + /* No such nick/channel */ + return; + } + std::string mode_sequence = parameters[1]; + std::string parameter = ""; + std::ostringstream parameter_list; + std::string output_sequence = ""; + bool adding = true, state_change = false; + int handler_id = 0; + int parameter_counter = 2; /* Index of first parameter */ + + for (std::string::const_iterator modeletter = mode_sequence.begin(); modeletter != mode_sequence.end(); modeletter++) + { + switch (*modeletter) + { + /* NB: + * For + and - mode characters, we don't just stick the character into the output sequence. + * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this + * appearing in the output sequence, we store a flag which says there was a state change, + * which is set on any + or -, however, the + or - that we finish on is only appended to + * the output stream in the event it is followed by a non "+ or -" character, such as o or v. + */ + case '+': + /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick, + * however, will allow the + if it is the first item in the sequence, regardless. + */ + if ((!adding) || (!output_sequence.length())) + state_change = true; + adding = true; + continue; + break; + case '-': + if ((adding) || (!output_sequence.length())) + state_change = true; + adding = false; + continue; + break; + default: + + /* 65 is the ascii value of 'A' */ + handler_id = *modeletter - 65; + + if (modehandlers[handler_id]) + { + bool abort = false; + for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++) + { + if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == MODEACTION_DENY) + abort = true; + } + if ((modehandlers[handler_id]->GetModeType() == type) && (!abort)) + { + if (modehandlers[handler_id]->GetNumParams(adding)) + { + if (pcnt < parameter_counter) + { + parameter = parameters[parameter_counter++]; + } + else + { + parameter = ""; + } + } + ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding); + if (ma == MODEACTION_ALLOW) + { + /* We're about to output a valid mode letter - was there previously a pending state-change? */ + if (state_change) + output_sequence.append(adding ? "+" : "-"); + + /* Add the mode letter */ + output_sequence = output_sequence + *modeletter; + + /* Is there a valid parameter for this mode? If so add it to the parameter list */ + if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter != "")) + { + parameter_list << " " << parameter; + } - while((pos = modes.find(j)) != std::string::npos) + /* Call all the AfterMode events in the mode watchers for this mode */ + for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++) + { + (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type); + } + + /* Reset the state change flag */ + state_change = false; + } + } + } + break; + } + } + /* Was there at least one valid mode in the sequence? */ + if (output_sequence != "") + { + if (servermode) { - log(DEBUG, "Deleting occurence of mode %c...", j); - modes.erase(pos, 1); - log(DEBUG,"New mode line: %s", modes.c_str()); + if (type == MODETYPE_CHANNEL) + { + WriteChannelWithServ(Config->ServerName,targetchannel,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str()); + } + } + else + { + if (type == MODETYPE_CHANNEL) + { + WriteChannel(targetchannel,user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str()); + FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str())); + } } } } - - return modes; +} + +std::string ModeParser::CompressModes(std::string modes,bool channelmodes) +{ + return ""; } void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int status, int pcnt, bool servermode, bool silent, bool local) @@ -533,10 +695,10 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int } else { - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'o', parameters[param], false, 1)); - if (!MOD_RESULT) - { + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'o', parameters[param], false, 1)); + if (!MOD_RESULT) + { r = TakeOps(user,parameters[param++],chan,status); } else param++; @@ -553,20 +715,20 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int r = NULL; if (mdir == 1) { - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'h', parameters[param], true, 1)); - if (!MOD_RESULT) - { + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'h', parameters[param], true, 1)); + if (!MOD_RESULT) + { r = GiveHops(user,parameters[param++],chan,status); } else param++; } else { - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'h', parameters[param], false, 1)); - if (!MOD_RESULT) - { + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'h', parameters[param], false, 1)); + if (!MOD_RESULT) + { r = TakeHops(user,parameters[param++],chan,status); } else param++; @@ -584,20 +746,20 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int r = NULL; if (mdir == 1) { - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'v', parameters[param], true, 1)); - if (!MOD_RESULT) - { + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'v', parameters[param], true, 1)); + if (!MOD_RESULT) + { r = GiveVoice(user,parameters[param++],chan,status); } else param++; } else { - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'v', parameters[param], false, 1)); - if (!MOD_RESULT) - { + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'v', parameters[param], false, 1)); + if (!MOD_RESULT) + { r = TakeVoice(user,parameters[param++],chan,status); } else param++; @@ -614,20 +776,20 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int r = NULL; if (mdir == 1) { - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'b', parameters[param], true, 1)); - if (!MOD_RESULT) - { + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'b', parameters[param], true, 1)); + if (!MOD_RESULT) + { r = AddBan(user,parameters[param++],chan,status); } else param++; } else { - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'b', parameters[param], false, 1)); - if (!MOD_RESULT) - { + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'b', parameters[param], false, 1)); + if (!MOD_RESULT) + { r = TakeBan(user,parameters[param++],chan,status); } else param++; @@ -653,7 +815,7 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int break; previously_set_k = true; - if (!*chan->key) + if (!chan->modes[CM_KEY]) { MOD_RESULT = 0; FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'k', parameters[param], true, 1)); @@ -664,6 +826,7 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int strlcpy(key,parameters[param++],32); outpars[pc++] = key; strlcpy(chan->key,key,MAXBUF); + chan->modes[CM_KEY] = 1; k_set = true; } else param++; @@ -688,6 +851,7 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int { *outl++ = 'k'; *chan->key = 0; + chan->modes[CM_KEY] = 0; outpars[pc++] = key; } } @@ -701,14 +865,15 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int if (previously_set_l) break; previously_unset_l = true; - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'l', "", false, 0)); - if (!MOD_RESULT) - { - if (chan->limit) + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'l', "", false, 0)); + if (!MOD_RESULT) + { + if (chan->modes[CM_LIMIT]) { *outl++ = 'l'; chan->limit = 0; + chan->modes[CM_LIMIT] = 0; } } } @@ -738,10 +903,10 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int if (invalid) break; - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'l', parameters[param], true, 1)); - if (!MOD_RESULT) - { + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'l', parameters[param], true, 1)); + if (!MOD_RESULT) + { chan->limit = atoi(parameters[param]); @@ -753,6 +918,7 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int if (chan->limit) { *outl++ = 'l'; + chan->modes[CM_LIMIT] = 1; outpars[pc++] = parameters[param++]; l_set = true; } @@ -760,100 +926,100 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int break; case 'i': - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'i', "", mdir, 0)); - if (!MOD_RESULT) - { + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'i', "", mdir, 0)); + if (!MOD_RESULT) + { if (mdir) { - if (!(chan->binarymodes & CM_INVITEONLY)) *outl++ = 'i'; - chan->binarymodes |= CM_INVITEONLY; + if (!(chan->modes[CM_INVITEONLY])) *outl++ = 'i'; + chan->modes[CM_INVITEONLY] = 1; } else { - if (chan->binarymodes & CM_INVITEONLY) *outl++ = 'i'; - chan->binarymodes &= ~CM_INVITEONLY; + if (chan->modes[CM_INVITEONLY]) *outl++ = 'i'; + chan->modes[CM_INVITEONLY] = 0; } } break; case 't': - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 't', "", mdir, 0)); - if (!MOD_RESULT) - { + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 't', "", mdir, 0)); + if (!MOD_RESULT) + { if (mdir) - { - if (!(chan->binarymodes & CM_TOPICLOCK)) *outl++ = 't'; - chan->binarymodes |= CM_TOPICLOCK; - } - else - { - if (chan->binarymodes & CM_TOPICLOCK) *outl++ = 't'; - chan->binarymodes &= ~CM_TOPICLOCK; - } + { + if (!(chan->modes[CM_TOPICLOCK])) *outl++ = 't'; + chan->modes[CM_TOPICLOCK] = 1; + } + else + { + if (chan->modes[CM_TOPICLOCK]) *outl++ = 't'; + chan->modes[CM_TOPICLOCK] = 0; + } } break; case 'n': - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'n', "", mdir, 0)); - if (!MOD_RESULT) - { - if (mdir) - { - if (!(chan->binarymodes & CM_NOEXTERNAL)) *outl++ = 'n'; - chan->binarymodes |= CM_NOEXTERNAL; - } - else - { - if (chan->binarymodes & CM_NOEXTERNAL) *outl++ = 'n'; - chan->binarymodes &= ~CM_NOEXTERNAL; - } + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'n', "", mdir, 0)); + if (!MOD_RESULT) + { + if (mdir) + { + if (!(chan->modes[CM_NOEXTERNAL])) *outl++ = 'n'; + chan->modes[CM_NOEXTERNAL] = 1; + } + else + { + if (chan->modes[CM_NOEXTERNAL]) *outl++ = 'n'; + chan->modes[CM_NOEXTERNAL] = 0; + } } break; case 'm': - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'm', "", mdir, 0)); - if (!MOD_RESULT) - { - if (mdir) - { - if (!(chan->binarymodes & CM_MODERATED)) *outl++ = 'm'; - chan->binarymodes |= CM_MODERATED; - } - else - { - if (chan->binarymodes & CM_MODERATED) *outl++ = 'm'; - chan->binarymodes &= ~CM_MODERATED; - } + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'm', "", mdir, 0)); + if (!MOD_RESULT) + { + if (mdir) + { + if (!(chan->modes[CM_MODERATED])) *outl++ = 'm'; + chan->modes[CM_MODERATED] = 1; + } + else + { + if (chan->modes[CM_MODERATED]) *outl++ = 'm'; + chan->modes[CM_MODERATED] = 0; + } } break; case 's': - MOD_RESULT = 0; - FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 's', "", mdir, 0)); - if (!MOD_RESULT) - { - if (mdir) - { - if (!(chan->binarymodes & CM_SECRET)) *outl++ = 's'; - chan->binarymodes |= CM_SECRET; - if (chan->binarymodes & CM_PRIVATE) - { - chan->binarymodes &= ~CM_PRIVATE; - if (mdir) - { + MOD_RESULT = 0; + FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 's', "", mdir, 0)); + if (!MOD_RESULT) + { + if (mdir) + { + if (!(chan->modes[CM_SECRET])) *outl++ = 's'; + chan->modes[CM_SECRET] = 1; + if (chan->modes[CM_PRIVATE]) + { + chan->modes[CM_PRIVATE] = 0; + if (mdir) + { *outl++ = '-'; *outl++ = 'p'; *outl++ = '+'; - } - } - } - else - { - if (chan->binarymodes & CM_SECRET) *outl++ = 's'; - chan->binarymodes &= ~CM_SECRET; - } + } + } + } + else + { + if (chan->modes[CM_SECRET]) *outl++ = 's'; + chan->modes[CM_SECRET] = 0; + } } break; @@ -864,14 +1030,14 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int { if(mdir) { - if(!(chan->binarymodes & CM_PRIVATE)) + if(!(chan->modes[CM_PRIVATE])) *outl++ = 'p'; - chan->binarymodes |= CM_PRIVATE; + chan->modes[CM_PRIVATE] = 1; - if(chan->binarymodes & CM_SECRET) + if(chan->modes[CM_SECRET]) { - chan->binarymodes &= ~CM_SECRET; + chan->modes[CM_SECRET] = 0; *outl++ = '-'; *outl++ = 's'; @@ -880,10 +1046,10 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int } else { - if(chan->binarymodes & CM_PRIVATE) + if(chan->modes[CM_PRIVATE]) *outl++ = 'p'; - chan->binarymodes &= ~CM_PRIVATE; + chan->modes[CM_PRIVATE] = 0; } } break; @@ -891,7 +1057,7 @@ void ModeParser::ProcessModes(char **parameters,userrec* user,chanrec *chan,int default: string_list p; p.clear(); - bool x = chan->custom_modes[*modechar-65]; + bool x = chan->modes[*modechar-65]; if ((!x && !mdir) || (x && mdir)) { if (!ModeIsListMode(*modechar,MT_CHANNEL)) @@ -1427,8 +1593,8 @@ void ModeParser::ServerMode(char **parameters, int pcnt, userrec *user) if ((dest) && (pcnt > 1)) { - std::string tidied = ServerInstance->ModeGrok->CompressModes(parameters[1],false); - parameters[1] = (char*)tidied.c_str(); + std::string tidied = ServerInstance->ModeGrok->CompressModes(parameters[1],false); + parameters[1] = (char*)tidied.c_str(); char dmodes[MAXBUF]; strlcpy(dmodes,dest->modes,MAXBUF); @@ -1447,8 +1613,8 @@ void ModeParser::ServerMode(char **parameters, int pcnt, userrec *user) switch (*i) { - case ' ': - continue; + case ' ': + continue; case '+': if ((direction != 1) && (next_ok)) @@ -1483,6 +1649,20 @@ void ModeParser::ServerMode(char **parameters, int pcnt, userrec *user) { charlcat(dmodes,*i,MAXBUF); charlcat(outpars,*i,53); + switch (*i) + { + case 'i': + dest->modebits |= UM_INVISIBLE; + break; + case 's': + dest->modebits |= UM_SERVERNOTICE; + break; + case 'w': + dest->modebits |= UM_WALLOPS; + break; + default: + break; + } } } } @@ -1497,6 +1677,20 @@ void ModeParser::ServerMode(char **parameters, int pcnt, userrec *user) { charlcat(outpars,*i,MAXBUF); charremove(dmodes,*i); + switch (*i) + { + case 'i': + dest->modebits &= ~UM_INVISIBLE; + break; + case 's': + dest->modebits &= ~UM_SERVERNOTICE; + break; + case 'w': + dest->modebits &= ~UM_WALLOPS; + break; + default: + break; + } } } } @@ -1504,43 +1698,43 @@ void ModeParser::ServerMode(char **parameters, int pcnt, userrec *user) break; } } - if (*outpars) - { - char b[MAXBUF]; - char* z = b; - - for (char* i = outpars; *i;) - { - *z++ = *i++; - if (((*i == '-') || (*i == '+')) && ((*(i+1) == '-') || (*(i+1) == '+'))) - { - // someones playing silly buggers and trying - // to put a +- or -+ into the line... - i++; - } - if (!*(i+1)) - { - // Someone's trying to make the last character in - // the line be a + or - symbol. - if ((*i == '-') || (*i == '+')) - { - i++; - } - } - } - *z = 0; - - if ((*b) && (!IS_SINGLE(b,'+')) && (!IS_SINGLE(b,'-'))) - { - WriteTo(user, dest, "MODE %s :%s", dest->nick, b); - FOREACH_MOD(I_OnMode,OnMode(user, dest, TYPE_USER, b)); - } - - log(DEBUG,"Stripped mode line"); - log(DEBUG,"Line dest is now %s",dmodes); - strlcpy(dest->modes,dmodes,MAXMODES-1); - - } + if (*outpars) + { + char b[MAXBUF]; + char* z = b; + + for (char* i = outpars; *i;) + { + *z++ = *i++; + if (((*i == '-') || (*i == '+')) && ((*(i+1) == '-') || (*(i+1) == '+'))) + { + // someones playing silly buggers and trying + // to put a +- or -+ into the line... + i++; + } + if (!*(i+1)) + { + // Someone's trying to make the last character in + // the line be a + or - symbol. + if ((*i == '-') || (*i == '+')) + { + i++; + } + } + } + *z = 0; + + if ((*b) && (!IS_SINGLE(b,'+')) && (!IS_SINGLE(b,'-'))) + { + WriteTo(user, dest, "MODE %s :%s", dest->nick, b); + FOREACH_MOD(I_OnMode,OnMode(user, dest, TYPE_USER, b)); + } + + log(DEBUG,"Stripped mode line"); + log(DEBUG,"Line dest is now %s",dmodes); + strlcpy(dest->modes,dmodes,MAXMODES-1); + + } return; }