]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/mode.cpp
Remove an extern, partly because it's unused, partly because it then gets shadowed...
[user/henk/code/inspircd.git] / src / mode.cpp
index 7d6423d02f1621162fc0f8b4e5527d67fceaefe7..3842b01e6ea02301b5d3b86e2221d89948dd1409 100644 (file)
@@ -54,7 +54,7 @@ extern ServerConfig* Config;
 
 extern time_t TIME;
 
-ModeHandler::ModeHandler(char modeletter, int parameters, bool listmode, ModeType type, bool operonly) : mode(modeletter), n_params(parameters), list(listmode), m_type(type), oper(operonly)
+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)
 {
 }
 
@@ -77,9 +77,9 @@ bool ModeHandler::NeedsOper()
        return oper;
 }
 
-int ModeHandler::GetNumParams()
+int ModeHandler::GetNumParams(bool adding)
 {
-       return n_params;
+       return adding ? n_params_on : n_params_off;
 }
 
 char ModeHandler::GetModeChar()
@@ -475,7 +475,7 @@ char* ModeParser::TakeBan(userrec *user,char *dest,chanrec *chan,int status)
        return NULL;
 }
 
-void ModeParser::Process(char **parameters, int pcnt, userrec *user)
+void ModeParser::Process(char **parameters, int pcnt, userrec *user, bool servermode)
 {
        std::string target = parameters[0];
        ModeType type = MODETYPE_USER;
@@ -503,105 +503,115 @@ void ModeParser::Process(char **parameters, int pcnt, userrec *user)
                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;
-                                       state_change = true;
                                        continue;
                                break;
                                case '-':
+                                       if ((adding) || (!output_sequence.length()))
+                                               state_change = true;
                                        adding = false;
-                                       state_change = true;
                                        continue;
                                break;
                                default:
-                                       if (state_change)
-                                               output_sequence.append(adding ? "+" : "-");
 
-                                       handler_id = *modeletter-65;
-                                       state_change = false;
+                                       /* 65 is the ascii value of 'A' */
+                                       handler_id = *modeletter - 65;
 
                                        if (modehandlers[handler_id])
                                        {
                                                bool abort = false;
-                                               for (std::vector<ModeWatcher*>::iterator watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
+                                               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;
 
-                                                               for (std::vector<ModeWatcher*>::iterator watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
+                                                               /* 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;
+                                                               }
+
+                                                               /* 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;
                        }
                }
-       }
-}
-
-
-/** 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)
-{
-       /*
-        * 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;
-
-               if(!channelmodes || (channelmodes && (strchr("itnmsp", *i) || (ModeDefined(*i, MT_CHANNEL) && !ModeDefinedOn(*i,MT_CHANNEL) && !ModeDefinedOff(*i,MT_CHANNEL)))))
-               {
-                       log(DEBUG,"Tidy mode %c", *i);
-                       counts[*i]++;
-                       active[*i] = true;
-               }
-       }
-       
-       for(unsigned char j = 65; j < 127; j++)
-       {
-               if ((counts[j] > 1) && (active[j] == true))
+               /* Was there at least one valid mode in the sequence? */
+               if (output_sequence != "")
                {
-                       std::string::size_type pos;
-
-                       while((pos = modes.find(j)) != std::string::npos)
+                       if (servermode)
+                       {
+                               if (type == MODETYPE_CHANNEL)
+                               {
+                                       WriteChannelWithServ(Config->ServerName,targetchannel,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
+                               }
+                       }
+                       else
                        {
-                               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)
+                               {
+                                       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)