+ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
+{
+ for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+ {
+ unsigned char pos = (mode-65) | MASK_CHANNEL;
+
+ if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
+ {
+ return modehandlers[pos];
+ }
+ }
+ return NULL;
+}
+
+std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
+{
+ std::string types;
+ std::string pars;
+
+ if (!channel || !user)
+ return "";
+
+ for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+ {
+ unsigned char pos = (mode-65) | MASK_CHANNEL;
+ ModeHandler* mh = modehandlers[pos];
+ if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
+ {
+ ModePair ret;
+ ret = mh->ModeSet(NULL, user, channel, user->nick);
+ if ((ret.first) && (ret.second == user->nick))
+ {
+ if (nick_suffix)
+ {
+ pars.append(" ");
+ pars.append(user->nick);
+ }
+ types.push_back(mh->GetModeChar());
+ }
+ }
+ }
+
+ if (nick_suffix)
+ return types+pars;
+ else
+ return types;
+}
+
+std::string ModeParser::GiveModeList(ModeMasks m)
+{
+ std::string type1; /* Listmodes EXCEPT those with a prefix */
+ std::string type2; /* Modes that take a param when adding or removing */
+ std::string type3; /* Modes that only take a param when adding */
+ std::string type4; /* Modes that dont take a param */
+
+ for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+ {
+ unsigned char pos = (mode-65) | m;
+ /* One parameter when adding */
+ if (modehandlers[pos])
+ {
+ if (modehandlers[pos]->GetNumParams(true))
+ {
+ if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
+ {
+ type1 += modehandlers[pos]->GetModeChar();
+ }
+ else
+ {
+ /* ... and one parameter when removing */
+ if (modehandlers[pos]->GetNumParams(false))
+ {
+ /* But not a list mode */
+ if (!modehandlers[pos]->GetPrefix())
+ {
+ type2 += modehandlers[pos]->GetModeChar();
+ }
+ }
+ else
+ {
+ /* No parameters when removing */
+ type3 += modehandlers[pos]->GetModeChar();
+ }
+ }
+ }
+ else
+ {
+ type4 += modehandlers[pos]->GetModeChar();
+ }
+ }
+ }
+
+ return type1 + "," + type2 + "," + type3 + "," + type4;
+}
+
+std::string ModeParser::BuildPrefixes()
+{
+ std::string mletters;
+ std::string mprefixes;
+ std::map<int,std::pair<char,char> > prefixes;
+
+ for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+ {
+ unsigned char pos = (mode-65) | MASK_CHANNEL;
+
+ if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
+ {
+ prefixes[modehandlers[pos]->GetPrefixRank()] = std::make_pair(
+ modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetModeChar());
+ }
+ }
+
+ for(std::map<int,std::pair<char,char> >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); n++)
+ {
+ mletters = mletters + n->second.first;
+ mprefixes = mprefixes + n->second.second;
+ }
+
+ return "(" + mprefixes + ")" + mletters;
+}
+
+bool ModeParser::AddModeWatcher(ModeWatcher* mw)
+{
+ unsigned char mask = 0;
+ unsigned char pos = 0;
+
+ if (!mw)
+ return false;
+
+ if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
+ return false;
+
+ mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
+ pos = (mw->GetModeChar()-65) | mask;
+
+ modewatchers[pos].push_back(mw);
+
+ return true;
+}
+
+bool ModeParser::DelModeWatcher(ModeWatcher* mw)
+{
+ unsigned char mask = 0;
+ unsigned char pos = 0;
+
+ if (!mw)
+ return false;
+
+ if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
+ return false;
+
+ mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
+ pos = (mw->GetModeChar()-65) | mask;
+
+ ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
+
+ if (a == modewatchers[pos].end())
+ {
+ return false;
+ }
+
+ modewatchers[pos].erase(a);
+
+ return true;
+}
+
+/** This default implementation can remove simple user modes
+ */
+void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
+{
+ char moderemove[MAXBUF];
+ std::vector<std::string> parameters;
+
+ if (user->IsModeSet(this->GetModeChar()))
+ {
+ if (stack)
+ {
+ stack->Push(this->GetModeChar());
+ }
+ else
+ {
+ sprintf(moderemove,"-%c",this->GetModeChar());
+ parameters.push_back(user->nick);
+ parameters.push_back(moderemove);
+ ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
+ }
+ }
+}
+
+/** This default implementation can remove simple channel modes
+ * (no parameters)
+ */
+void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
+{
+ char moderemove[MAXBUF];
+ std::vector<std::string> parameters;
+
+ if (channel->IsModeSet(this->GetModeChar()))
+ {
+ if (stack)
+ {
+ stack->Push(this->GetModeChar());
+ }
+ else
+ {
+ sprintf(moderemove,"-%c",this->GetModeChar());
+ parameters.push_back(channel->name);
+ parameters.push_back(moderemove);
+ ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
+ }
+ }
+}
+
+ModeParser::ModeParser()
+{
+ ModeHandler* modes[] =
+ {
+ new ModeChannelSecret,
+ new ModeChannelPrivate,
+ new ModeChannelModerated,
+ new ModeChannelTopicOps,
+
+ new ModeChannelNoExternal,
+ new ModeChannelInviteOnly,
+ new ModeChannelKey,
+ new ModeChannelLimit,
+
+ new ModeChannelBan,
+ new ModeChannelOp,
+ new ModeChannelHalfOp,
+ new ModeChannelVoice,
+
+ new ModeUserWallops,
+ new ModeUserInvisible,
+ new ModeUserOperator,
+ new ModeUserServerNoticeMask,
+#define BUILTIN_MODE_COUNT 16
+ };
+
+ /* Clear mode handler list */
+ memset(modehandlers, 0, sizeof(modehandlers));
+
+ /* Last parse string */
+ LastParse.clear();
+
+ /* Initialise the RFC mode letters */
+ for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
+ this->AddMode(modes[index]);
+
+ seq = 0;
+ memset(&sent, 0, sizeof(sent));
+}
+
+ModeParser::~ModeParser()
+{
+ int count = 0;
+ for(int i=0; i < 256; i++)
+ {
+ ModeHandler* mh = modehandlers[i];
+ if (mh)
+ {
+ count++;
+ delete mh;
+ }
+ }
+ if (count != BUILTIN_MODE_COUNT)
+ throw CoreException("Mode handler found non-core modes remaining at deallocation");
+}