The InspIRCd Project
Home | Developers | Wiki | Forums | Bug Tracker | SVN | Download
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

mode.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
00006  * See: http://www.inspircd.org/wiki/index.php/Credits
00007  *
00008  * This program is free but copyrighted software; see
00009  *            the file COPYING for details.
00010  *
00011  * ---------------------------------------------------
00012  */
00013 
00014 /* $Core */
00015 /* $ExtraDeps: $(RELCPPFILES) */
00016 /* $ExtraObjects: modes/modeclasses.a */
00017 /* $ExtraBuild: @${MAKE} -C "modes" DIRNAME="src/modes" CC="$(CC)" $(MAKEARGS) CPPFILES="$(CPPFILES)" */
00018 
00019 #include "inspircd.h"
00020 #include "inspstring.h"
00021 
00022 /* +s (secret) */
00023 #include "modes/cmode_s.h"
00024 /* +p (private) */
00025 #include "modes/cmode_p.h"
00026 /* +b (bans) */
00027 #include "modes/cmode_b.h"
00028 /* +m (moderated) */
00029 #include "modes/cmode_m.h"
00030 /* +t (only (half) ops can change topic) */
00031 #include "modes/cmode_t.h"
00032 /* +n (no external messages) */
00033 #include "modes/cmode_n.h"
00034 /* +i (invite only) */
00035 #include "modes/cmode_i.h"
00036 /* +k (keyed channel) */
00037 #include "modes/cmode_k.h"
00038 /* +l (channel user limit) */
00039 #include "modes/cmode_l.h"
00040 /* +o (channel op) */
00041 #include "modes/cmode_o.h"
00042 /* +h (channel halfop) */
00043 #include "modes/cmode_h.h"
00044 /* +v (channel voice) */
00045 #include "modes/cmode_v.h"
00046 /* +w (see wallops) */
00047 #include "modes/umode_w.h"
00048 /* +i (invisible) */
00049 #include "modes/umode_i.h"
00050 /* +o (operator) */
00051 #include "modes/umode_o.h"
00052 /* +s (server notice masks) */
00053 #include "modes/umode_s.h"
00054 
00055 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired)
00056         : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), oper(operonly), prefix(mprefix), count(0), prefixneeded(prefixrequired)
00057 {
00058 }
00059 
00060 ModeHandler::~ModeHandler()
00061 {
00062 }
00063 
00064 bool ModeHandler::IsListMode()
00065 {
00066         return list;
00067 }
00068 
00069 char ModeHandler::GetNeededPrefix()
00070 {
00071         return prefixneeded;
00072 }
00073 
00074 void ModeHandler::SetNeededPrefix(char needsprefix)
00075 {
00076         prefixneeded = needsprefix;
00077 }
00078 
00079 unsigned int ModeHandler::GetPrefixRank()
00080 {
00081         return 0;
00082 }
00083 
00084 unsigned int ModeHandler::GetCount()
00085 {
00086         return 0;
00087 }
00088 
00089 void ModeHandler::ChangeCount(int modifier)
00090 {
00091         count += modifier;
00092         ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
00093 }
00094 
00095 ModeType ModeHandler::GetModeType()
00096 {
00097         return m_type;
00098 }
00099 
00100 bool ModeHandler::NeedsOper()
00101 {
00102         return oper;
00103 }
00104 
00105 char ModeHandler::GetPrefix()
00106 {
00107         return prefix;
00108 }
00109 
00110 int ModeHandler::GetNumParams(bool adding)
00111 {
00112         return adding ? n_params_on : n_params_off;
00113 }
00114 
00115 char ModeHandler::GetModeChar()
00116 {
00117         return mode;
00118 }
00119 
00120 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
00121 {
00122         return MODEACTION_DENY;
00123 }
00124 
00125 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
00126 {
00127         if (dest)
00128         {
00129                 return std::make_pair(dest->IsModeSet(this->mode), "");
00130         }
00131         else
00132         {
00133                 return std::make_pair(channel->IsModeSet(this->mode), "");
00134         }
00135 }
00136 
00137 void ModeHandler::DisplayList(User*, Channel*)
00138 {
00139 }
00140 
00141 void ModeHandler::DisplayEmptyList(User*, Channel*)
00142 {
00143 }
00144 
00145 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
00146 {
00147 }
00148 
00149 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
00150 {
00151         return (ours < theirs);
00152 }
00153 
00154 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
00155 {
00156 }
00157 
00158 SimpleUserModeHandler::~SimpleUserModeHandler()
00159 {
00160 }
00161 
00162 SimpleChannelModeHandler::~SimpleChannelModeHandler()
00163 {
00164 }
00165 
00166 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
00167 {
00168 }
00169 
00170 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding, bool servermode)
00171 {
00172         /* Only opers can change other users modes */
00173         if (source != dest)
00174                 return MODEACTION_DENY;
00175 
00176         if (adding)
00177         {
00178                 if (!dest->IsModeSet(this->GetModeChar()))
00179                 {
00180                         dest->SetMode(this->GetModeChar(),true);
00181                         return MODEACTION_ALLOW;
00182                 }
00183         }
00184         else
00185         {
00186                 if (dest->IsModeSet(this->GetModeChar()))
00187                 {
00188                         dest->SetMode(this->GetModeChar(),false);
00189                         return MODEACTION_ALLOW;
00190                 }
00191         }
00192 
00193         return MODEACTION_DENY;
00194 }
00195 
00196 
00197 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding, bool servermode)
00198 {
00199         if (adding)
00200         {
00201                 if (!channel->IsModeSet(this->GetModeChar()))
00202                 {
00203                         channel->SetMode(this->GetModeChar(),true);
00204                         return MODEACTION_ALLOW;
00205                 }
00206         }
00207         else
00208         {
00209                 if (channel->IsModeSet(this->GetModeChar()))
00210                 {
00211                         channel->SetMode(this->GetModeChar(),false);
00212                         return MODEACTION_ALLOW;
00213                 }
00214         }
00215 
00216         return MODEACTION_DENY;
00217 }
00218 
00219 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
00220 {
00221 }
00222 
00223 ModeWatcher::~ModeWatcher()
00224 {
00225 }
00226 
00227 char ModeWatcher::GetModeChar()
00228 {
00229         return mode;
00230 }
00231 
00232 ModeType ModeWatcher::GetModeType()
00233 {
00234         return m_type;
00235 }
00236 
00237 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
00238 {
00239         return true;
00240 }
00241 
00242 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
00243 {
00244 }
00245 
00246 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
00247 {
00248         User *d;
00249         if ((!user) || (!dest) || (!chan) || (!*dest))
00250         {
00251                 return NULL;
00252         }
00253         d = ServerInstance->FindNick(dest);
00254         if (!d)
00255         {
00256                 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
00257                 return NULL;
00258         }
00259         return d;
00260 }
00261 
00262 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
00263 {
00264         if (!chan)
00265                 return "";
00266 
00267         UCListIter n = d->chans.find(chan);
00268         if (n != d->chans.end())
00269         {
00270                 if (n->second & MASK)
00271                 {
00272                         return "";
00273                 }
00274                 n->second = n->second | MASK;
00275                 switch (MASK)
00276                 {
00277                         case UCMODE_OP:
00278                                 n->first->AddOppedUser(d);
00279                         break;
00280                         case UCMODE_HOP:
00281                                 n->first->AddHalfoppedUser(d);
00282                         break;
00283                         case UCMODE_VOICE:
00284                                 n->first->AddVoicedUser(d);
00285                         break;
00286                 }
00287                 return d->nick.c_str();
00288         }
00289         return "";
00290 }
00291 
00292 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
00293 {
00294         if (!chan)
00295                 return "";
00296 
00297         UCListIter n = d->chans.find(chan);
00298         if (n != d->chans.end())
00299         {
00300                 if ((n->second & MASK) == 0)
00301                 {
00302                         return "";
00303                 }
00304                 n->second ^= MASK;
00305                 switch (MASK)
00306                 {
00307                         case UCMODE_OP:
00308                                 n->first->DelOppedUser(d);
00309                         break;
00310                         case UCMODE_HOP:
00311                                 n->first->DelHalfoppedUser(d);
00312                         break;
00313                         case UCMODE_VOICE:
00314                                 n->first->DelVoicedUser(d);
00315                         break;
00316                 }
00317                 return d->nick.c_str();
00318         }
00319         return "";
00320 }
00321 
00322 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
00323 {
00324         if (targetchannel)
00325         {
00326                 /* Display channel's current mode string */
00327                 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
00328                 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
00329                 return;
00330         }
00331         else if (targetuser)
00332         {
00333                 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
00334                 {
00335                         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
00336                         return;
00337                 }
00338 
00339                 if ((targetuser == user) || (IS_OPER(user)))
00340                 {
00341                         /* Display user's current mode string */
00342                         user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
00343                         if (IS_OPER(targetuser))
00344                                 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
00345                         return;
00346                 }
00347                 else
00348                 {
00349                         user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
00350                         return;
00351                 }
00352         }
00353 
00354         /* No such nick/channel */
00355         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
00356         return;
00357 }
00358 
00359 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
00360 {
00361         std::string target = parameters[0];
00362         ModeType type = MODETYPE_USER;
00363         unsigned char mask = 0;
00364         Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
00365         User* targetuser  = ServerInstance->FindNick(parameters[0]);
00366 
00367         LastParse.clear();
00368 
00369         /* Special case for displaying the list for listmodes,
00370          * e.g. MODE #chan b, or MODE #chan +b without a parameter
00371          */
00372         if ((targetchannel) && (parameters.size() == 2))
00373         {
00374                 const char* mode = parameters[1].c_str();
00375                 int nonlistmodes_found = 0;
00376 
00377                 seq++;
00378 
00379                 mask = MASK_CHANNEL;
00380                 
00381                 while (mode && *mode)
00382                 {
00383                         unsigned char mletter = *mode;
00384 
00385                         if (*mode == '+')
00386                         {
00387                                 mode++;
00388                                 continue;
00389                         }
00390                         
00391                         /* Ensure the user doesnt request the same mode twice,
00392                          * so they cant flood themselves off out of idiocy.
00393                          */
00394                         if (sent[mletter] != seq)
00395                         {
00396                                 sent[mletter] = seq;
00397                         }
00398                         else
00399                         {
00400                                 mode++;
00401                                 continue;
00402                         }
00403 
00404                         ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
00405                         bool display = true;
00406 
00407                         if ((mh) && (mh->IsListMode()))
00408                         {
00409                                 int MOD_RESULT = 0;
00410                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
00411                                 if (MOD_RESULT == ACR_DENY)
00412                                 {
00413                                         mode++;
00414                                         continue;
00415                                 }
00416 
00417                                 if (!IS_OPER(user))
00418                                 {
00419                                         if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
00420                                         {
00421                                                 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",user->nick.c_str(), targetchannel->name.c_str(), *mode++);
00422                                                 mh->DisplayEmptyList(user, targetchannel);
00423                                                 continue;
00424                                         }
00425                                 }
00426 
00429                                 unsigned char handler_id = (*mode - 65) | mask;
00430 
00431                                 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
00432                                 {
00433                                         std::string dummyparam;
00434                                         
00435                                         if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
00436                                                 display = false;
00437                                 }
00438 
00439                                 if (display)
00440                                         mh->DisplayList(user, targetchannel);
00441                         }
00442                         else
00443                                 nonlistmodes_found++;
00444 
00445                         mode++;
00446                 }
00447 
00448                 /* We didnt have any modes that were non-list, we can return here */
00449                 if (!nonlistmodes_found)
00450                         return;
00451         }
00452 
00453         if (parameters.size() == 1)
00454         {
00455                 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
00456         }
00457         else if (parameters.size() > 1)
00458         {
00459                 bool SkipAccessChecks = false;
00460 
00461                 if (targetchannel)
00462                 {
00463                         type = MODETYPE_CHANNEL;
00464                         mask = MASK_CHANNEL;
00465 
00466                         /* Extra security checks on channel modes
00467                          * (e.g. are they a (half)op?
00468                          */
00469 
00470                         if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
00471                         {
00472                                 /* We don't have halfop */
00473                                 int MOD_RESULT = 0;
00474                                 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
00475                                 if (MOD_RESULT == ACR_DENY)
00476                                         return;
00477                                 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
00478                         }
00479                 }
00480                 else if (targetuser)
00481                 {
00482                         type = MODETYPE_USER;
00483                         mask = MASK_USER;
00484                         if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
00485                         {
00486                                 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
00487                                 return;
00488                         }
00489                 }
00490                 else
00491                 {
00492                         /* No such nick/channel */
00493                         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
00494                         return;
00495                 }
00496 
00497                 std::string mode_sequence = parameters[1];
00498                 std::string parameter;
00499                 std::ostringstream parameter_list;
00500                 std::string output_sequence;
00501                 bool adding = true, state_change = false;
00502                 unsigned char handler_id = 0;
00503                 unsigned int parameter_counter = 2; /* Index of first parameter */
00504                 unsigned int parameter_count = 0;
00505                 bool last_successful_state_change = false;
00506 
00507                 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
00508                 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
00509                         mode_sequence.insert(0, "+");
00510 
00511                 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
00512                 {
00513                         unsigned char modechar = *letter;
00514 
00515                         switch (modechar)
00516                         {
00517                                 /* NB:
00518                                  * For + and - mode characters, we don't just stick the character into the output sequence.
00519                                  * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
00520                                  * appearing in the output sequence, we store a flag which says there was a state change,
00521                                  * which is set on any + or -, however, the + or - that we finish on is only appended to
00522                                  * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
00523                                  */
00524                                 case '+':
00525                                         /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
00526                                          * however, will allow the + if it is the first item in the sequence, regardless.
00527                                          */
00528                                         if ((!adding) || (!output_sequence.length()))
00529                                                 state_change = true;
00530                                         adding = true;
00531                                         if (!output_sequence.length())
00532                                                 last_successful_state_change = false;
00533                                         continue;
00534                                 break;
00535                                 case '-':
00536                                         if ((adding) || (!output_sequence.length()))
00537                                                 state_change = true;
00538                                         adding = false;
00539                                         if (!output_sequence.length())
00540                                                 last_successful_state_change = true;
00541                                         continue;
00542                                 break;
00543                                 default:
00544 
00554                                         handler_id = (modechar - 65) | mask;
00555 
00556                                         if (modehandlers[handler_id])
00557                                         {
00558                                                 bool abort = false;
00559 
00560                                                 if (modehandlers[handler_id]->GetModeType() == type)
00561                                                 {
00562                                                         int MOD_RESULT = 0;
00563 
00564                                                         if (modehandlers[handler_id]->GetNumParams(adding))
00565                                                         {
00566                                                                 /* This mode expects a parameter, do we have any parameters left in our list to use? */
00567                                                                 if (parameter_counter < parameters.size())
00568                                                                 {
00569                                                                         parameter = parameters[parameter_counter++];
00570 
00571                                                                         /* Yerk, invalid! */
00572                                                                         if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
00573                                                                                 parameter.clear();
00574                                                                 }
00575                                                                 else
00576                                                                 {
00577                                                                         /* No parameter, continue to the next mode */
00578                                                                         modehandlers[handler_id]->OnParameterMissing(user, targetuser, targetchannel);
00579                                                                         continue;
00580                                                                 }
00581 
00582                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
00583                                                         }
00584                                                         else
00585                                                         {
00586                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
00587                                                         }
00588 
00589                                                         if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
00590                                                                 continue;
00591 
00592                                                         if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
00593                                                         {
00594                                                                 /* Check access to this mode character */
00595                                                                 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
00596                                                                 {
00597                                                                         char needed = modehandlers[handler_id]->GetNeededPrefix();
00598                                                                         ModeHandler* prefixmode = FindPrefix(needed);
00599 
00600                                                                         /* If the mode defined by the handler is not '\0', but the handler for it
00601                                                                          * cannot be found, they probably dont have the right module loaded to implement
00602                                                                          * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
00603                                                                          * Revert to checking against the minimum core prefix, '%'.
00604                                                                          */
00605                                                                         if (needed && !prefixmode)
00606                                                                                 prefixmode = FindPrefix('%');
00607                                                 
00608                                                                         unsigned int neededrank = prefixmode->GetPrefixRank();
00609                                                                         /* Compare our rank on the channel against the rank of the required prefix,
00610                                                                          * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
00611                                                                          * in NAMES(X) are not in rank order, we know the most powerful mode is listed
00612                                                                          * first, so we don't need to iterate, we just look up the first instead.
00613                                                                          */
00614                                                                         std::string modestring = targetchannel->GetAllPrefixChars(user);
00615                                                                         char ml = (modestring.empty() ? '\0' : modestring[0]);
00616                                                                         ModeHandler* ourmode = FindPrefix(ml);
00617                                                                         if (!ourmode || ourmode->GetPrefixRank() < neededrank)
00618                                                                         {
00619                                                                                 /* Bog off */
00620                                                                                 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
00621                                                                                                 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
00622                                                                                 continue;
00623                                                                         }
00624                                                                 }
00625                                                         }
00626 
00627                                                         bool had_parameter = !parameter.empty();
00628                                                                 
00629                                                         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
00630                                                         {
00631                                                                 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
00632                                                                 {
00633                                                                         abort = true;
00634                                                                         break;
00635                                                                 }
00636                                                                 /* A module whacked the parameter completely, and there was one. abort. */
00637                                                                 if ((had_parameter) && (parameter.empty()))
00638                                                                 {
00639                                                                         abort = true;
00640                                                                         break;
00641                                                                 }
00642                                                         }
00643 
00644                                                         if (abort)
00645                                                                 continue;
00646 
00647                                                         /* If it's disabled, they have to be an oper.
00648                                                          */
00649                                                         if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
00650                                                         {
00651                                                                 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
00652                                                                                 user->nick.c_str(),
00653                                                                                 type == MODETYPE_CHANNEL ? "channel" : "user",
00654                                                                                 modehandlers[handler_id]->GetModeChar());
00655                                                                 continue;
00656                                                         }
00657 
00658                                                         /* It's an oper only mode, check if theyre an oper. If they arent,
00659                                                          * eat any parameter that  came with the mode, and continue to next
00660                                                          */
00661                                                         if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
00662                                                         {
00663                                                                 if (IS_OPER(user))
00664                                                                 {
00665                                                                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
00666                                                                                         user->nick.c_str(),
00667                                                                                         user->oper.c_str(),
00668                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
00669                                                                                         modehandlers[handler_id]->GetModeChar());
00670                                                                 }
00671                                                                 else
00672                                                                 {
00673                                                                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
00674                                                                                         user->nick.c_str(),
00675                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
00676                                                                                         modehandlers[handler_id]->GetModeChar());
00677                                                                 }
00678                                                                 continue;
00679                                                         }
00680 
00681                                                         /* Call the handler for the mode */
00682                                                         ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
00683 
00684                                                         if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
00685                                                         {
00686                                                                 /* The handler nuked the parameter and they are supposed to have one.
00687                                                                  * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
00688                                                                  * so we bail to the next mode character.
00689                                                                  */
00690                                                                 continue;
00691                                                         }
00692 
00693                                                         if (ma == MODEACTION_ALLOW)
00694                                                         {
00695                                                                 /* We're about to output a valid mode letter - was there previously a pending state-change? */
00696                                                                 if (state_change)
00697                                                                 {
00698                                                                         if (adding != last_successful_state_change)
00699                                                                                 output_sequence.append(adding ? "+" : "-");
00700                                                                         last_successful_state_change = adding;
00701                                                                 }
00702                                                                 
00703                                                                 /* Add the mode letter */
00704                                                                 output_sequence.push_back(modechar);
00705 
00706                                                                 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
00707 
00708                                                                 /* Is there a valid parameter for this mode? If so add it to the parameter list */
00709                                                                 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
00710                                                                 {
00711                                                                         parameter_list << " " << parameter;
00712                                                                         parameter_count++;
00713                                                                         /* Does this mode have a prefix? */
00714                                                                         if (modehandlers[handler_id]->GetPrefix() && targetchannel)
00715                                                                         {
00716                                                                                 User* user_to_prefix = ServerInstance->FindNick(parameter);
00717                                                                                 if (user_to_prefix)
00718                                                                                         targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
00719                                                                                                         modehandlers[handler_id]->GetPrefixRank(), adding);
00720                                                                         }
00721                                                                 }
00722 
00723                                                                 /* Call all the AfterMode events in the mode watchers for this mode */
00724                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
00725                                                                         (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
00726 
00727                                                                 /* Reset the state change flag */
00728                                                                 state_change = false;
00729 
00730                                                                 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
00731                                                                                 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
00732                                                                 {
00733                                                                         /* We cant have a mode sequence this long */
00734                                                                         letter = mode_sequence.end() - 1;
00735                                                                         continue;
00736                                                                 }
00737                                                         }
00738                                                 }
00739                                         }
00740                                         else
00741                                         {
00742                                                 /* No mode handler? Unknown mode character then. */
00743                                                 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
00744                                         }
00745                                 break;
00746                         }
00747                 }
00748 
00749                 /* Was there at least one valid mode in the sequence? */
00750                 if (!output_sequence.empty())
00751                 {
00752                         if (servermode)
00753                         {
00754                                 if (type == MODETYPE_CHANNEL)
00755                                 {
00756                                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
00757                                         this->LastParse = targetchannel->name;
00758                                 }
00759                                 else
00760                                 {
00761                                         targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
00762                                         this->LastParse = targetuser->nick;
00763                                 }
00764                         }
00765                         else
00766                         {
00767                                 if (type == MODETYPE_CHANNEL)
00768                                 {
00769                                         targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
00770                                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
00771                                         this->LastParse = targetchannel->name;
00772                                 }
00773                                 else
00774                                 {
00775                                         user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
00776                                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
00777                                         this->LastParse = targetuser->nick;
00778                                 }
00779                         }
00780 
00781                         LastParse.append(" ");
00782                         LastParse.append(output_sequence);
00783                         LastParse.append(parameter_list.str());
00784                 }
00785         }
00786 }
00787 
00788 const std::string& ModeParser::GetLastParse()
00789 {
00790         return LastParse;
00791 }
00792 
00793 void ModeParser::CleanMask(std::string &mask)
00794 {
00795         std::string::size_type pos_of_pling = mask.find_first_of('!');
00796         std::string::size_type pos_of_at = mask.find_first_of('@');
00797         std::string::size_type pos_of_dot = mask.find_first_of('.');
00798         std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
00799 
00800         if (mask.length() >= 2 && mask[1] == ':')
00801                 return; // if it's an extban, don't even try guess how it needs to be formed.
00802 
00803         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
00804         {
00805                 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
00806                 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
00807                 {
00808                         /* It has no '.' in it, it must be a nick. */
00809                         mask.append("!*@*");
00810                 }
00811                 else
00812                 {
00813                         /* Got a dot in it? Has to be a host */
00814                         mask = "*!*@" + mask;
00815                 }
00816         }
00817         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
00818         {
00819                 /* Has an @ but no !, its a user@host */
00820                  mask = "*!" + mask;
00821         }
00822         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
00823         {
00824                 /* Has a ! but no @, it must be a nick!ident */
00825                 mask.append("@*");
00826         }
00827 }
00828 
00829 bool ModeParser::AddMode(ModeHandler* mh)
00830 {
00831         unsigned char mask = 0;
00832         unsigned char pos = 0;
00833 
00834         /* Yes, i know, this might let people declare modes like '_' or '^'.
00835          * If they do that, thats their problem, and if i ever EVER see an
00836          * official InspIRCd developer do that, i'll beat them with a paddle!
00837          */
00838         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
00839                 return false;
00840 
00841         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
00842          * A mode prefix of ':' will fuck up both server to server, and client to server.
00843          * A mode prefix of '#' will mess up /whois and /privmsg
00844          */
00845         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
00846                 return false;
00847 
00848         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
00849         pos = (mh->GetModeChar()-65) | mask;
00850 
00851         if (modehandlers[pos])
00852                 return false;
00853 
00854         modehandlers[pos] = mh;
00855         return true;
00856 }
00857 
00858 bool ModeParser::DelMode(ModeHandler* mh)
00859 {
00860         unsigned char mask = 0;
00861         unsigned char pos = 0;
00862 
00863         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
00864                 return false;
00865 
00866         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
00867         pos = (mh->GetModeChar()-65) | mask;
00868 
00869         if (!modehandlers[pos])
00870                 return false;
00871 
00872         /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
00873          * To stack here we have to make the algorithm slower. Discuss.
00874          */
00875         switch (mh->GetModeType())
00876         {
00877                 case MODETYPE_USER:
00878                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
00879                         {
00880                                 mh->RemoveMode(i->second);
00881                         }
00882                 break;
00883                 case MODETYPE_CHANNEL:
00884                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
00885                         {
00886                                 mh->RemoveMode(i->second);
00887                         }
00888                 break;
00889         }
00890 
00891         modehandlers[pos] = NULL;
00892 
00893         return true;
00894 }
00895 
00896 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
00897 {
00898         unsigned char mask = 0;
00899         unsigned char pos = 0;
00900 
00901         if ((modeletter < 'A') || (modeletter > 'z'))
00902                 return NULL;
00903 
00904         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
00905         pos = (modeletter-65) | mask;
00906 
00907         return modehandlers[pos];
00908 }
00909 
00910 std::string ModeParser::UserModeList()
00911 {
00912         char modestr[256];
00913         int pointer = 0;
00914 
00915         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
00916         {
00917                 unsigned char pos = (mode-65) | MASK_USER;
00918 
00919                 if (modehandlers[pos])
00920                         modestr[pointer++] = mode;
00921         }
00922         modestr[pointer++] = 0;
00923         return modestr;
00924 }
00925 
00926 std::string ModeParser::ChannelModeList()
00927 {
00928         char modestr[256];
00929         int pointer = 0;
00930 
00931         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
00932         {
00933                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
00934                         continue;
00935 
00936                 unsigned char pos = (mode-65) | MASK_CHANNEL;
00937 
00938                 if (modehandlers[pos])
00939                         modestr[pointer++] = mode;
00940         }
00941         modestr[pointer++] = 0;
00942         return modestr;
00943 }
00944 
00945 std::string ModeParser::ParaModeList()
00946 {
00947         char modestr[256];
00948         int pointer = 0;
00949 
00950         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
00951         {
00952                 if ((!ServerInstanc