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

ModeParser Class Reference

The mode parser handles routing of modes and handling of mode strings. More...

#include <mode.h>

Inheritance diagram for ModeParser:

Inheritance graph
[legend]
Collaboration diagram for ModeParser:

Collaboration graph
[legend]
List of all members.

Public Member Functions

 ModeParser (InspIRCd *Instance)
 The constructor initializes all the RFC basic modes by using ModeParserAddMode().
userrecSanityChecks (userrec *user, const char *dest, chanrec *chan, int status)
 Used to check if user 'd' should be allowed to do operation 'MASK' on channel 'chan'.
const char * Grant (userrec *d, chanrec *chan, int MASK)
 Grant a built in privilage (e.g.
const char * Revoke (userrec *d, chanrec *chan, int MASK)
 Revoke a built in privilage (e.g.
const std::stringGetLastParse ()
 Get the last string to be processed, as it was sent to the user or channel.
bool AddMode (ModeHandler *mh, unsigned const char modeletter)
 Add a mode to the mode parser.
bool DelMode (ModeHandler *mh)
 Delete a mode from the mode parser.
bool AddModeWatcher (ModeWatcher *mw)
 Add a mode watcher.
bool DelModeWatcher (ModeWatcher *mw)
 Delete a mode watcher.
void Process (const char **parameters, int pcnt, userrec *user, bool servermode)
 Process a set of mode changes from a server or user.
ModeHandlerFindMode (unsigned const char modeletter, ModeType mt)
 Find the mode handler for a given mode and type.
ModeHandlerFindPrefix (unsigned const char pfxletter)
 Find a mode handler by its prefix.
std::string UserModeList ()
 Returns a list of mode characters which are usermodes.
std::string ChannelModeList ()
 Returns a list of channel mode characters which are listmodes.
std::string ParaModeList ()
 Returns a list of channel mode characters which take parameters.
std::string ChanModes ()
 Generates the CHANMODES= 005 sequence.
std::string BuildPrefixes ()
 This returns the PREFIX=(ohv)%+ section of the 005 numeric.
std::string ModeString (userrec *user, chanrec *channel)
 This returns the privilages of a user upon a channel, in the format of a mode change.

Static Public Member Functions

static void CleanMask (std::string &mask)
 Tidy a banmask.
static bool PrefixComparison (prefixtype one, prefixtype two)
 Used by this class internally during std::sort and 005 generation.

Private Member Functions

void DisplayCurrentModes (userrec *user, userrec *targetuser, chanrec *targetchannel, const char *text)
 Displays the current modes of a channel or user.

Private Attributes

InspIRCdServerInstance
 Creator/owner pointer.
ModeHandlermodehandlers [256]
 Mode handlers for each mode, to access a handler subtract 65 from the ascii value of the mode letter.
std::vector< ModeWatcher * > modewatchers [256]
 Mode watcher classes arranged in the same way as the mode handlers, except for instead of having 256 of them we have 256 lists of them.
std::string LastParse
 The string representing the last set of modes to be parsed.

Detailed Description

The mode parser handles routing of modes and handling of mode strings.

It marshalls, controls and maintains both ModeWatcher and ModeHandler classes, parses client to server MODE strings for user and channel modes, and performs processing for the 004 mode list numeric, amongst other things.

Definition at line 369 of file mode.h.


Constructor & Destructor Documentation

ModeParser::ModeParser InspIRCd Instance  ) 
 

The constructor initializes all the RFC basic modes by using ModeParserAddMode().

Definition at line 1036 of file mode.cpp.

References AddMode(), LastParse, modehandlers, and modewatchers.

01036                                          : ServerInstance(Instance)
01037 {
01038         struct Initializer
01039         {
01040                 char modechar;
01041                 ModeHandler* handler;
01042         };
01043 
01044         Initializer modes[] = {
01045                 { 's', new ModeChannelSecret(Instance) },
01046                 { 'p', new ModeChannelPrivate(Instance) },
01047                 { 'm', new ModeChannelModerated(Instance) },
01048                 { 't', new ModeChannelTopicOps(Instance) },
01049                 { 'n', new ModeChannelNoExternal(Instance) },
01050                 { 'i', new ModeChannelInviteOnly(Instance) },
01051                 { 'k', new ModeChannelKey(Instance) },
01052                 { 'l', new ModeChannelLimit(Instance) },
01053                 { 'b', new ModeChannelBan(Instance) },
01054                 { 'o', new ModeChannelOp(Instance) },
01055                 { 'h', new ModeChannelHalfOp(Instance) },
01056                 { 'v', new ModeChannelVoice(Instance) },
01057                 { 's', new ModeUserServerNotice(Instance) },
01058                 { 'w', new ModeUserWallops(Instance) },
01059                 { 'i', new ModeUserInvisible(Instance) },
01060                 { 'o', new ModeUserOperator(Instance) },
01061                 { 'n', new ModeUserServerNoticeMask(Instance) },
01062                 { 0, NULL }
01063         };
01064 
01065         /* Clear mode list */
01066         memset(modehandlers, 0, sizeof(modehandlers));
01067         memset(modewatchers, 0, sizeof(modewatchers));
01068 
01069         /* Last parse string */
01070         LastParse.clear();
01071 
01072         /* Initialise the RFC mode letters */
01073         for (int index = 0; modes[index].modechar; index++)
01074                 this->AddMode(modes[index].handler, modes[index].modechar);
01075 }


Member Function Documentation

bool ModeParser::AddMode ModeHandler mh,
unsigned const char  modeletter
 

Add a mode to the mode parser.

The modeletter parameter is purely to save on doing a lookup in the function, as strictly it could be obtained via ModeHandler::GetModeChar().

Returns:
True if the mode was successfully added.

Definition at line 694 of file mode.cpp.

References ModeHandler::GetModeChar(), ModeHandler::GetModeType(), ModeHandler::GetPrefix(), MASK_CHANNEL, MASK_USER, modehandlers, and MODETYPE_USER.

Referenced by InspIRCd::AddMode(), and ModeParser().

00695 {
00696         unsigned char mask = 0;
00697         unsigned char pos = 0;
00698 
00699         /* Yes, i know, this might let people declare modes like '_' or '^'.
00700          * If they do that, thats their problem, and if i ever EVER see an
00701          * official InspIRCd developer do that, i'll beat them with a paddle!
00702          */
00703         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
00704                 return false;
00705 
00706         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
00707          * A mode prefix of ':' will fuck up both server to server, and client to server.
00708          * A mode prefix of '#' will mess up /whois and /privmsg
00709          */
00710         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
00711                 return false;
00712 
00713         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
00714         pos = (mh->GetModeChar()-65) | mask;
00715 
00716         if (modehandlers[pos])
00717                 return false;
00718 
00719         modehandlers[pos] = mh;
00720         return true;
00721 }

bool ModeParser::AddModeWatcher ModeWatcher mw  ) 
 

Add a mode watcher.

A mode watcher is triggered before and after a mode handler is triggered. See the documentation of class ModeWatcher for more information.

Parameters:
mw The ModeWatcher you want to add
Returns:
True if the ModeWatcher was added correctly

Definition at line 956 of file mode.cpp.

References ModeWatcher::GetModeChar(), ModeWatcher::GetModeType(), MASK_CHANNEL, MASK_USER, MODETYPE_USER, and modewatchers.

Referenced by InspIRCd::AddModeWatcher().

00957 {
00958         unsigned char mask = 0;
00959         unsigned char pos = 0;
00960 
00961         if (!mw)
00962                 return false;
00963 
00964         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
00965                 return false;
00966 
00967         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
00968         pos = (mw->GetModeChar()-65) | mask;
00969 
00970         modewatchers[pos].push_back(mw);
00971 
00972         return true;
00973 }

std::string ModeParser::BuildPrefixes  ) 
 

This returns the PREFIX=(ohv)%+ section of the 005 numeric.

Definition at line 924 of file mode.cpp.

References ServerConfig::AllowHalfop, InspIRCd::Config, ModeHandler::GetPrefix(), MASK_CHANNEL, modehandlers, PrefixComparison(), and ServerInstance.

Referenced by InspIRCd::BuildISupport(), TreeSocket::Capab(), and TreeSocket::SendCapabilities().

00925 {
00926         std::string mletters;
00927         std::string mprefixes;
00928         pfxcontainer pfx;
00929         std::map<char,char> prefix_to_mode;
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]) && (modehandlers[pos]->GetPrefix()))
00939                 {
00940                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
00941                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
00942                 }
00943         }
00944 
00945         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
00946 
00947         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
00948         {
00949                 mletters = mletters + n->first;
00950                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
00951         }
00952 
00953         return "(" + mprefixes + ")" + mletters;
00954 }

std::string ModeParser::ChanModes  ) 
 

Generates the CHANMODES= 005 sequence.

Definition at line 868 of file mode.cpp.

References ServerConfig::AllowHalfop, InspIRCd::Config, ModeHandler::GetModeChar(), MASK_CHANNEL, modehandlers, and ServerInstance.

Referenced by InspIRCd::BuildISupport(), and TreeSocket::SendCapabilities().

00869 {
00870         std::string type1;      /* Listmodes EXCEPT those with a prefix */
00871         std::string type2;      /* Modes that take a param when adding or removing */
00872         std::string type3;      /* Modes that only take a param when adding */
00873         std::string type4;      /* Modes that dont take a param */
00874 
00875         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
00876         {
00877                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
00878                         continue;
00879 
00880                 unsigned char pos = (mode-65) | MASK_CHANNEL;
00881                  /* One parameter when adding */
00882                 if (modehandlers[pos])
00883                 {       
00884                         if (modehandlers[pos]->GetNumParams(true))
00885                         {
00886                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
00887                                 {
00888                                         type1 += modehandlers[pos]->GetModeChar();
00889                                 }
00890                                 else
00891                                 {
00892                                         /* ... and one parameter when removing */
00893                                         if (modehandlers[pos]->GetNumParams(false))
00894                                         {
00895                                                 /* But not a list mode */
00896                                                 if (!modehandlers[pos]->GetPrefix())
00897                                                 {
00898                                                         type2 += modehandlers[pos]->GetModeChar();
00899                                                 }
00900                                         }
00901                                         else
00902                                         {
00903                                                 /* No parameters when removing */
00904                                                 type3 += modehandlers[pos]->GetModeChar();
00905                                         }
00906                                 }
00907                         }
00908                         else
00909                         {
00910                                 type4 += modehandlers[pos]->GetModeChar();
00911                         }
00912                 }
00913                          
00914         }
00915 
00916         return type1 + "," + type2 + "," + type3 + "," + type4;
00917 }

std::string ModeParser::ChannelModeList  ) 
 

Returns a list of channel mode characters which are listmodes.

This is used in the 004 numeric when users connect.

Definition at line 788 of file mode.cpp.

References ServerConfig::AllowHalfop, InspIRCd::Config, MASK_CHANNEL, modehandlers, and ServerInstance.

Referenced by userrec::FullConnect().

00789 {
00790         char modestr[256];
00791         int pointer = 0;
00792 
00793         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
00794         {
00795                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
00796                         continue;
00797 
00798                 unsigned char pos = (mode-65) | MASK_CHANNEL;
00799 
00800                 if (modehandlers[pos])
00801                         modestr[pointer++] = mode;
00802         }
00803         modestr[pointer++] = 0;
00804         return modestr;
00805 }

void ModeParser::CleanMask std::string mask  )  [static]
 

Tidy a banmask.

This makes a banmask 'acceptable' if fields are left out. E.g.

nick -> nick!*@*

nick!ident -> nick!ident@*

host.name -> *!*.name

ident@host.name -> *!ident.name

This method can be used on both IPV4 and IPV6 user masks.

Definition at line 661 of file mode.cpp.

Referenced by cmd_silence::Handle(), and ListModeBase::OnModeChange().

00662 {
00663         std::string::size_type pos_of_pling = mask.find_first_of('!');
00664         std::string::size_type pos_of_at = mask.find_first_of('@');
00665         std::string::size_type pos_of_dot = mask.find_first_of('.');
00666         std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
00667 
00668         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
00669         {
00670                 /* Just a nick, or just a host */
00671                 if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
00672                 {
00673                         /* It has no '.' in it, it must be a nick. */
00674                         mask.append("!*@*");
00675                 }
00676                 else
00677                 {
00678                         /* Got a dot in it? Has to be a host */
00679                         mask = "*!*@" + mask;
00680                 }
00681         }
00682         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
00683         {
00684                 /* Has an @ but no !, its a user@host */
00685                  mask = "*!" + mask;
00686         }
00687         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
00688         {
00689                 /* Has a ! but no @, it must be a nick!ident */
00690                 mask.append("@*");
00691         }
00692 }

bool ModeParser::DelMode ModeHandler mh  ) 
 

Delete a mode from the mode parser.

When a mode is deleted, the mode handler will be called for every user (if it is a user mode) or for every channel (if it is a channel mode) to unset the mode on all objects. This prevents modes staying in the system which no longer exist.

Parameters:
mh The mode handler to remove
Returns:
True if the mode was successfully removed.

Definition at line 723 of file mode.cpp.

References InspIRCd::chanlist, InspIRCd::clientlist, ModeHandler::GetModeChar(), ModeHandler::GetModeType(), MASK_CHANNEL, MASK_USER, modehandlers, MODETYPE_CHANNEL, MODETYPE_USER, ModeHandler::RemoveMode(), and ServerInstance.

Referenced by ModuleChanProtect::OnRehash(), ModuleAuditorium::~ModuleAuditorium(), ModuleBanException::~ModuleBanException(), ModuleBlockCAPS::~ModuleBlockCAPS(), ModuleBlockColour::~ModuleBlockColour(), ModuleBotMode::~ModuleBotMode(), ModuleCensor::~ModuleCensor(), ModuleChanFilter::~ModuleChanFilter(), ModuleChanProtect::~ModuleChanProtect(), ModuleCloaking::~ModuleCloaking(), ModuleDeaf::~ModuleDeaf(), ModuleHelpop::~ModuleHelpop(), ModuleHideChans::~ModuleHideChans(), ModuleHideOper::~ModuleHideOper(), ModuleInvisible::~ModuleInvisible(), ModuleInviteException::~ModuleInviteException(), ModuleJoinFlood::~ModuleJoinFlood(), ModuleKickNoRejoin::~ModuleKickNoRejoin(), ModuleKnock::~ModuleKnock(), ModuleMsgFlood::~ModuleMsgFlood(), ModuleNickFlood::~ModuleNickFlood(), ModuleNoCTCP::~ModuleNoCTCP(), ModuleNoInvite::~ModuleNoInvite(), ModuleNoKicks::~ModuleNoKicks(), ModuleNoNickChange::~ModuleNoNickChange(), ModuleNoNotice::~ModuleNoNotice(), ModuleOperChans::~ModuleOperChans(), ModulePrivacyMode::~ModulePrivacyMode(), ModuleRedirect::~ModuleRedirect(), ModuleServices::~ModuleServices(), ModuleServicesAccount::~ModuleServicesAccount(), ModuleShowwhois::~ModuleShowwhois(), ModuleSSLModes::~ModuleSSLModes(), and ModuleStripColor::~ModuleStripColor().

00724 {
00725         unsigned char mask = 0;
00726         unsigned char pos = 0;
00727 
00728         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
00729                 return false;
00730 
00731         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
00732         pos = (mh->GetModeChar()-65) | mask;
00733 
00734         if (!modehandlers[pos])
00735                 return false;
00736 
00737         switch (mh->GetModeType())
00738         {
00739                 case MODETYPE_USER:
00740                         for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)
00741                         {
00742                                 mh->RemoveMode(i->second);
00743                         }
00744                 break;
00745                 case MODETYPE_CHANNEL:
00746                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
00747                         {
00748                                 mh->RemoveMode(i->second);
00749                         }
00750                 break;
00751         }
00752 
00753         modehandlers[pos] = NULL;
00754 
00755         return true;
00756 }

bool ModeParser::DelModeWatcher ModeWatcher mw  ) 
 

Delete a mode watcher.

A mode watcher is triggered before and after a mode handler is triggered. See the documentation of class ModeWatcher for more information.

Parameters:
mw The ModeWatcher you want to delete
Returns:
True if the ModeWatcher was deleted correctly

Definition at line 975 of file mode.cpp.

References ModeWatcher::GetModeChar(), ModeWatcher::GetModeType(), MASK_CHANNEL, MASK_USER, MODETYPE_USER, and modewatchers.

Referenced by InspIRCd::DelModeWatcher(), ModuleBanRedirect::~ModuleBanRedirect(), and ModuleInvisible::~ModuleInvisible().

00976 {
00977         unsigned char mask = 0;
00978         unsigned char pos = 0;
00979 
00980         if (!mw)
00981                 return false;
00982 
00983         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
00984                 return false;
00985 
00986         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
00987         pos = (mw->GetModeChar()-65) | mask;
00988 
00989         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
00990 
00991         if (a == modewatchers[pos].end())
00992         {
00993                 return false;
00994         }
00995 
00996         modewatchers[pos].erase(a);
00997 
00998         return true;
00999 }

void ModeParser::DisplayCurrentModes userrec user,
userrec targetuser,
chanrec targetchannel,
const char *  text
[private]
 

Displays the current modes of a channel or user.

Used by ModeParser::Process.

Definition at line 243 of file mode.cpp.

References classbase::age, chanrec::ChanModes(), userrec::FormatModes(), userrec::FormatNoticeMasks(), chanrec::HasUser(), IS_OPER, chanrec::name, userrec::nick, userrec::Visibility, VisData::VisibleTo(), and userrec::WriteServ().

Referenced by Process().

00244 {
00245         if (targetchannel)
00246         {
00247                 /* Display channel's current mode string */
00248                 user->WriteServ("324 %s %s +%s",user->nick, targetchannel->name, targetchannel->ChanModes(targetchannel->HasUser(user)));
00249                 user->WriteServ("329 %s %s %lu", user->nick, targetchannel->name, (unsigned long)targetchannel->age);
00250                 return;
00251         }
00252         else if (targetuser)
00253         {
00254                 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
00255                 {
00256                         user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);
00257                         return;
00258                 }
00259 
00260                 if ((targetuser == user) || (IS_OPER(user)))
00261                 {
00262                         /* Display user's current mode string */
00263                         user->WriteServ("221 %s :+%s",targetuser->nick,targetuser->FormatModes());
00264                         if (IS_OPER(targetuser))
00265                                 user->WriteServ("008 %s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks());
00266                         return;
00267                 }
00268                 else
00269                 {
00270                         user->WriteServ("502 %s :Can't change mode for other users", user->nick);
00271                         return;
00272                 }
00273         }
00274 
00275         /* No such nick/channel */
00276         user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);
00277         return;
00278 }

ModeHandler * ModeParser::FindMode unsigned const char  modeletter,
ModeType  mt
 

Find the mode handler for a given mode and type.

Parameters:
modeletter mode letter to search for
type of mode to search for, user or channel
Returns:
a pointer to a ModeHandler class, or NULL of there isnt a handler for the given mode

Definition at line 758 of file mode.cpp.

References MASK_CHANNEL, MASK_USER, modehandlers, and MODETYPE_USER.

Referenced by userrec::DecrementModes(), TreeSocket::IntroduceClient(), InspIRCd::ModeCount(), Process(), TreeSocket::RemoveStatus(), and chanrec::SetDefaultModes().

00759 {
00760         unsigned char mask = 0;
00761         unsigned char pos = 0;
00762 
00763         if ((modeletter < 'A') || (modeletter > 'z'))
00764                 return NULL;
00765 
00766         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
00767         pos = (modeletter-65) | mask;
00768 
00769         return modehandlers[pos];
00770 }

ModeHandler * ModeParser::FindPrefix unsigned const char  pfxletter  ) 
 

Find a mode handler by its prefix.

If there is no mode handler with the given prefix, NULL will be returned.

Parameters:
pfxletter The prefix to find, e.g. '@'
Returns:
The mode handler which handles this prefix, or NULL if there is none.

Definition at line 826 of file mode.cpp.

References MASK_CHANNEL, and modehandlers.

Referenced by chanrec::ForceChan(), and TreeSocket::ForceJoin().

00827 {
00828         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
00829         {
00830                 unsigned char pos = (mode-65) | MASK_CHANNEL;
00831 
00832                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
00833                 {
00834                         return modehandlers[pos];
00835                 }
00836         }
00837         return NULL;
00838 }

const std::string & ModeParser::GetLastParse  ) 
 

Get the last string to be processed, as it was sent to the user or channel.

Use this to display a string you just sent to be parsed, as the actual output may be different to what you sent after it has been 'cleaned up' by the parser.

Returns:
Last parsed string, as seen by users.

Definition at line 656 of file mode.cpp.

References LastParse.

Referenced by cmd_samode::Handle(), ModuleTimedBans::OnBackgroundTimer(), and ModuleOverride::OnPostCommand().

00657 {
00658         return LastParse;
00659 }

const char * ModeParser::Grant userrec d,
chanrec chan,
int  MASK
 

Grant a built in privilage (e.g.

ops, halfops, voice) to a user on a channel

Definition at line 183 of file mode.cpp.

References userrec::chans, userrec::nick, UCMODE_HOP, UCMODE_OP, and UCMODE_VOICE.

00184 {
00185         if (!chan)
00186                 return "";
00187 
00188         UCListIter n = d->chans.find(chan);
00189         if (n != d->chans.end())
00190         {
00191                 if (n->second & MASK)
00192                 {
00193                         return "";
00194                 }
00195                 n->second = n->second | MASK;
00196                 switch (MASK)
00197                 {
00198                         case UCMODE_OP:
00199                                 n->first->AddOppedUser(d);
00200                         break;
00201                         case UCMODE_HOP:
00202                                 n->first->AddHalfoppedUser(d);
00203                         break;
00204                         case UCMODE_VOICE:
00205                                 n->first->AddVoicedUser(d);
00206                         break;
00207                 }
00208                 return d->nick;
00209         }
00210         return "";
00211 }

std::string ModeParser::ModeString userrec user,
chanrec channel
 

This returns the privilages of a user upon a channel, in the format of a mode change.

For example, if a user has privilages +avh, this will return the string "avh nick nick nick". This is used by the core when cycling a user to refresh their hostname. You may use it for similar purposes.

Parameters:
user The username to look up
channel The channel name to look up the privilages of the user for
Returns:
The mode string.

Definition at line 840 of file mode.cpp.

References ModeHandler::GetModeChar(), ModeHandler::GetNumParams(), MASK_CHANNEL, modehandlers, ModeHandler::ModeSet(), and userrec::nick.

Referenced by userrec::ChangeDisplayedHost(), userrec::ChangeIdent(), chanrec::ForceChan(), and InvisibleMode::OnModeChange().

00841 {
00842         std::string types;
00843         std::string pars;
00844 
00845         if (!channel || !user)
00846                 return "";
00847 
00848         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
00849         {
00850                 unsigned char pos = (mode-65) | MASK_CHANNEL;
00851                 ModeHandler* mh = modehandlers[pos];
00852                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
00853                 {
00854                         ModePair ret;
00855                         ret = mh->ModeSet(NULL, user, channel, user->nick);
00856                         if ((ret.first) && (ret.second == user->nick))
00857                         {
00858                                 pars.append(" ");
00859                                 pars.append(user->nick);
00860                                 types.push_back(mh->GetModeChar());
00861                         }
00862                 }
00863         }
00864 
00865         return types+pars;
00866 }

std::string ModeParser::ParaModeList  ) 
 

Returns a list of channel mode characters which take parameters.

This is used in the 004 numeric when users connect.

Definition at line 807 of file mode.cpp.

References ServerConfig::AllowHalfop, InspIRCd::Config, MASK_CHANNEL, modehandlers, and ServerInstance.

Referenced by userrec::FullConnect().

00808 {
00809         char modestr[256];
00810         int pointer = 0;
00811 
00812         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
00813         {
00814                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
00815                         continue;
00816 
00817                 unsigned char pos = (mode-65) | MASK_CHANNEL;
00818 
00819                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
00820                         modestr[pointer++] = mode;
00821         }
00822         modestr[pointer++] = 0;
00823         return modestr;
00824 }

bool ModeParser::PrefixComparison prefixtype  one,
prefixtype  two
[static]
 

Used by this class internally during std::sort and 005 generation.

Definition at line 919 of file mode.cpp.

Referenced by BuildPrefixes(), and chanrec::SetPrefix().

00920 {       
00921         return one.second > two.second;
00922 }

void ModeParser::Process const char **  parameters,
int  pcnt,
userrec user,
bool  servermode
 

Process a set of mode changes from a server or user.

Parameters:
parameters The parameters of the mode change, in the format they would be from a MODE command.
pcnt The number of items in the parameters array
user The user setting or removing the modes. When the modes are set by a server, an 'uninitialized' userrec is used, where *usernick == NULL and *user->server == NULL.
servermode True if a server is setting the mode.

Definition at line 280 of file mode.cpp.

References AC_GENERAL_MODE, ACR_DEFAULT, ACR_DENY, ServerConfig::AllowHalfop, ModeHandler::ChangeCount(), InspIRCd::Config, DisplayCurrentModes(), ModeHandler::DisplayEmptyList(), ModeHandler::DisplayList(), InspIRCd::FindChan(), FindMode(), InspIRCd::FindNick(), FOREACH_MOD, FOREACH_RESULT, ModeHandler::GetModeChar(), chanrec::GetStatus(), ServerConfig::HideModeLists, I_OnAccessCheck, I_OnMode, IS_LOCAL, IS_OPER, ModeHandler::IsListMode(), LastParse, MASK_CHANNEL, MASK_USER, MAXMODES, MODEACTION_ALLOW, modehandlers, MODETYPE_CHANNEL, MODETYPE_USER, modewatchers, chanrec::name, userrec::nick, ModeHandler::OnModeChange(), userrec::server, ServerInstance, ServerConfig::ServerName, chanrec::SetPrefix(), STATUS_HOP, TYPE_CHANNEL, TYPE_USER, InspIRCd::ULine(), chanrec::WriteChannel(), chanrec::WriteChannelWithServ(), userrec::WriteServ(), and userrec::WriteTo().

Referenced by InvisibleDeOper::BeforeMode(), cmd_mode::Handle(), and InspIRCd::SendMode().

00281 {
00282         std::string target = parameters[0];
00283         ModeType type = MODETYPE_USER;
00284         unsigned char mask = 0;
00285         chanrec* targetchannel = ServerInstance->FindChan(parameters[0]);
00286         userrec* targetuser  = ServerInstance->FindNick(parameters[0]);
00287 
00288         LastParse.clear();
00289 
00290         /* Special case for displaying the list for listmodes,
00291          * e.g. MODE #chan b, or MODE #chan +b without a parameter
00292          */
00293         if ((targetchannel) && (pcnt == 2))
00294         {
00295                 const char* mode = parameters[1];
00296                 int nonlistmodes_found = 0;
00297                 bool sent[256];
00298 
00299                 mask = MASK_CHANNEL;
00300 
00301                 memset(&sent, 0, 256);
00302                 
00303                 while (mode && *mode)
00304                 {
00305                         unsigned char mletter = *mode;
00306 
00307                         if (*mode == '+')
00308                         {
00309                                 mode++;
00310                                 continue;
00311                         }
00312 
00313                         /* Ensure the user doesnt request the same mode twice,
00314                          * so they cant flood themselves off out of idiocy.
00315                          */
00316                         if (!sent[mletter])
00317                         {
00318                                 sent[mletter] = true;
00319                         }
00320                         else
00321                         {
00322                                 mode++;
00323                                 continue;
00324                         }
00325 
00326                         ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
00327                         bool display = true;
00328 
00329                         if ((mh) && (mh->IsListMode()))
00330                         {
00331                                 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
00332                                 {
00333                                         user->WriteServ("482 %s %s :Only half-operators and above may view the +%c list",user->nick, targetchannel->name, *mode++);
00334                                         mh->DisplayEmptyList(user, targetchannel);
00335                                         continue;
00336                                 }
00337 
00340                                 unsigned char handler_id = (*mode - 65) | mask;
00341 
00342                                 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
00343                                 {
00344                                         std::string dummyparam;
00345                                         
00346                                         if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
00347                                                 display = false;
00348                                 }
00349 
00350                                 if (display)
00351                                         mh->DisplayList(user, targetchannel);
00352                         }
00353                         else
00354                                 nonlistmodes_found++;
00355 
00356                         mode++;
00357                 }
00358 
00359                 /* We didnt have any modes that were non-list, we can return here */
00360                 if (!nonlistmodes_found)
00361                         return;
00362         }
00363 
00364         if (pcnt == 1)
00365         {
00366                 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0]);
00367         }
00368         else if (pcnt > 1)
00369         {
00370                 if (targetchannel)
00371                 {
00372                         type = MODETYPE_CHANNEL;
00373                         mask = MASK_CHANNEL;
00374 
00375                         /* Extra security checks on channel modes
00376                          * (e.g. are they a (half)op?
00377                          */
00378 
00379                         if ((IS_LOCAL(user)) && (targetchannel->GetStatus(user) < STATUS_HOP))
00380                         {
00381                                 /* We don't have halfop */
00382                                 int MOD_RESULT = 0;
00383                                 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
00384                                 if (MOD_RESULT == ACR_DENY)
00385                                         return;
00386 
00387                                 if (MOD_RESULT == ACR_DEFAULT)
00388                                 {
00389                                         /* Are we a uline or is it a servermode? */
00390                                         if ((!ServerInstance->ULine(user->server)) && (!servermode))
00391                                         {
00392                                                 /* Not enough permission:
00393                                                  * NOT a uline and NOT a servermode,
00394                                                  * OR, NOT halfop or above.
00395                                                  */
00396                                                 user->WriteServ("482 %s %s :You're not a channel %soperator",user->nick, targetchannel->name,
00397                                                                 ServerInstance->Config->AllowHalfop ? "(half)" : "");
00398                                                 return;
00399                                         }
00400                                 }
00401                         }
00402                 }
00403                 else if (targetuser)
00404                 {
00405                         type = MODETYPE_USER;
00406                         mask = MASK_USER;
00407                         if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
00408                         {
00409                                 user->WriteServ("502 %s :Can't change mode for other users", user->nick);
00410                                 return;
00411                         }
00412                 }
00413                 else
00414                 {
00415                         /* No such nick/channel */
00416                         user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
00417                         return;
00418                 }
00419 
00420                 std::string mode_sequence = parameters[1];
00421                 std::string parameter;
00422                 std::ostringstream parameter_list;
00423                 std::string output_sequence;
00424                 bool adding = true, state_change = false;
00425                 unsigned char handler_id = 0;
00426                 int parameter_counter = 2; /* Index of first parameter */
00427                 int parameter_count = 0;
00428                 bool last_successful_state_change = false;
00429 
00430                 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
00431                 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
00432                         mode_sequence.insert(0, "+");
00433 
00434                 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
00435                 {
00436                         unsigned char modechar = *letter;
00437 
00438                         switch (modechar)
00439                         {
00440                                 /* NB:
00441                                  * For + and - mode characters, we don't just stick the character into the output sequence.
00442                                  * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
00443                                  * appearing in the output sequence, we store a flag which says there was a state change,
00444                                  * which is set on any + or -, however, the + or - that we finish on is only appended to
00445                                  * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
00446                                  */
00447                                 case '+':
00448                                         /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
00449                                          * however, will allow the + if it is the first item in the sequence, regardless.
00450                                          */
00451                                         if ((!adding) || (!output_sequence.length()))
00452                                                 state_change = true;
00453                                         adding = true;
00454                                         if (!output_sequence.length())
00455                                                 last_successful_state_change = false;
00456                                         continue;
00457                                 break;
00458                                 case '-':
00459                                         if ((adding) || (!output_sequence.length()))
00460                                                 state_change = true;
00461                                         adding = false;
00462                                         if (!output_sequence.length())
00463                                                 last_successful_state_change = true;
00464                                         continue;
00465                                 break;
00466                                 default:
00467 
00477                                         handler_id = (modechar - 65) | mask;
00478 
00479                                         if (modehandlers[handler_id])
00480                                         {
00481                                                 bool abort = false;
00482 
00483                                                 if (modehandlers[handler_id]->GetModeType() == type)
00484                                                 {
00485                                                         if (modehandlers[handler_id]->GetNumParams(adding))
00486                                                         {
00487                                                                 /* This mode expects a parameter, do we have any parameters left in our list to use? */
00488                                                                 if (parameter_counter < pcnt)
00489                                                                 {
00490                                                                         parameter = parameters[parameter_counter++];
00491 
00492                                                                         /* Yerk, invalid! */
00493                                                                         if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
00494                                                                                 parameter.clear();
00495                                                                 }
00496                                                                 else
00497                                                                 {
00498                                                                         /* No parameter, continue to the next mode */
00499                                                                         continue;
00500                                                                 }
00501 
00502                                                                 bool had_parameter = !parameter.empty();
00503                                                                 
00504                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
00505                                                                 {
00506                                                                         if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
00507                                                                         {
00508                                                                                 abort = true;
00509                                                                                 break;
00510                                                                         }
00511                                                                         /* A module whacked the parameter completely, and there was one. abort. */
00512                                                                         if ((had_parameter) && (parameter.empty()))
00513                                                                         {
00514                                                                                 abort = true;
00515                                                                                 break;
00516                                                                         }
00517                                                                 }
00518 
00519                                                                 if (abort)
00520                                                                         continue;
00521                                                         }
00522                                                         else
00523                                                         {
00524                                                                 /* Fix by brain: mode watchers not being called for parameterless modes */
00525                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
00526                                                                 {
00527                                                                         if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
00528                                                                         {
00529                                                                                 abort = true;
00530                                                                                 break;
00531                                                                         }
00532                                                                 }
00533 
00534                                                                 if (abort)
00535                                                                         continue;
00536                                                         }
00537 
00538                                                         /* It's an oper only mode, check if theyre an oper. If they arent,
00539                                                          * eat any parameter that  came with the mode, and continue to next
00540                                                          */
00541                                                         if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user)))
00542                                                         {
00543                                                                 user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick,
00544                                                                                 adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",
00545                                                                                 modehandlers[handler_id]->GetModeChar());
00546                                                                 continue;
00547                                                         }
00548 
00549                                                         /* Call the handler for the mode */
00550                                                         ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding);
00551 
00552                                                         if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
00553                                                         {
00554                                                                 /* The handler nuked the parameter and they are supposed to have one.
00555                                                                  * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
00556                                                                  * so we bail to the next mode character.
00557                                                                  */
00558                                                                 continue;
00559                                                         }
00560 
00561                                                         if (ma == MODEACTION_ALLOW)
00562                                                         {
00563                                                                 /* We're about to output a valid mode letter - was there previously a pending state-change? */
00564                                                                 if (state_change)
00565                                                                 {
00566                                                                         if (adding != last_successful_state_change)
00567                                                                                 output_sequence.append(adding ? "+" : "-");
00568                                                                         last_successful_state_change = adding;
00569                                                                 }
00570                                                                 
00571                                                                 /* Add the mode letter */
00572                                                                 output_sequence.push_back(modechar);
00573 
00574                                                                 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
00575 
00576                                                                 /* Is there a valid parameter for this mode? If so add it to the parameter list */
00577                                                                 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
00578                                                                 {
00579                                                                         parameter_list << " " << parameter;
00580                                                                         parameter_count++;
00581                                                                         /* Does this mode have a prefix? */
00582                                                                         if (modehandlers[handler_id]->GetPrefix() && targetchannel)
00583                                                                         {
00584                                                                                 userrec* user_to_prefix = ServerInstance->FindNick(parameter);
00585                                                                                 if (user_to_prefix)
00586                                                                                         targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
00587                                                                                                         modehandlers[handler_id]->GetPrefixRank(), adding);
00588                                                                         }
00589                                                                 }
00590 
00591                                                                 /* Call all the AfterMode events in the mode watchers for this mode */
00592                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
00593                                                                         (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type);
00594 
00595                                                                 /* Reset the state change flag */
00596                                                                 state_change = false;
00597 
00598                                                                 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
00599                                                                                 || (parameter_count > MAXMODES))
00600                                                                 {
00601                                                                         /* We cant have a mode sequence this long */
00602                                                                         letter = mode_sequence.end() - 1;
00603                                                                         continue;
00604                                                                 }
00605                                                         }
00606                                                 }
00607                                         }
00608                                         else
00609                                         {
00610                                                 /* No mode handler? Unknown mode character then. */
00611                                                 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
00612                                         }
00613                                 break;
00614                         }
00615                 }
00616 
00617                 /* Was there at least one valid mode in the sequence? */
00618                 if (!output_sequence.empty())
00619                 {
00620                         if (servermode)
00621                         {
00622                                 if (type == MODETYPE_CHANNEL)
00623                                 {
00624                                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
00625                                         this->LastParse = targetchannel->name;
00626                                 }
00627                                 else
00628                                 {
00629                                         targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
00630                                         this->LastParse = targetuser->nick;
00631                                 }
00632                         }
00633                         else
00634                         {
00635                                 if (type == MODETYPE_CHANNEL)
00636                                 {
00637                                         targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
00638                                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
00639                                         this->LastParse = targetchannel->name;
00640                                 }
00641                                 else
00642                                 {
00643                                         user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
00644                                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
00645                                         this->LastParse = targetuser->nick;
00646                                 }
00647                         }
00648 
00649                         LastParse.append(" ");
00650                         LastParse.append(output_sequence);
00651                         LastParse.append(parameter_list.str());
00652                 }
00653         }
00654 }

const char * ModeParser::Revoke userrec d,
chanrec chan,
int  MASK
 

Revoke a built in privilage (e.g.

ops, halfops, voice) to a user on a channel

Definition at line 213 of file mode.cpp.

References userrec::chans, userrec::nick, UCMODE_HOP, UCMODE_OP, and UCMODE_VOICE.

00214 {
00215         if (!chan)
00216                 return "";
00217 
00218         UCListIter n = d->chans.find(chan);
00219         if (n != d->chans.end())
00220         {
00221                 if ((n->second & MASK) == 0)
00222                 {
00223                         return "";
00224                 }
00225                 n->second ^= MASK;
00226                 switch (MASK)
00227                 {
00228                         case UCMODE_OP:
00229                                 n->first->DelOppedUser(d);
00230                         break;
00231                         case UCMODE_HOP:
00232                                 n->first->DelHalfoppedUser(d);
00233                         break;
00234                         case UCMODE_VOICE:
00235                                 n->first->DelVoicedUser(d);
00236                         break;
00237                 }
00238                 return d->nick;
00239         }
00240         return "";
00241 }

userrec * ModeParser::SanityChecks userrec user,
const char *  dest,
chanrec chan,
int  status
 

Used to check if user 'd' should be allowed to do operation 'MASK' on channel 'chan'.

for example, should 'user A' be able to 'op' on 'channel B'.

Definition at line 167 of file mode.cpp.

References InspIRCd::FindNick(), userrec::nick, ServerInstance, and userrec::WriteServ().

00168 {
00169         userrec *d;
00170         if ((!user) || (!dest) || (!chan) || (!*dest))
00171         {
00172                 return NULL;
00173         }
00174         d = ServerInstance->FindNick(dest);
00175         if (!d)
00176         {
00177                 user->WriteServ("401 %s %s :No such nick/channel",user->nick, dest);
00178                 return NULL;
00179         }
00180         return d;
00181 }

std::string ModeParser::UserModeList  ) 
 

Returns a list of mode characters which are usermodes.

This is used in the 004 numeric when users connect.

Definition at line 772 of file mode.cpp.

References MASK_USER, and modehandlers.

Referenced by userrec::FullConnect().

00773 {
00774         char modestr[256];
00775         int pointer = 0;
00776 
00777         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
00778         {
00779                 unsigned char pos = (mode-65) | MASK_USER;
00780 
00781                 if (modehandlers[pos])
00782                         modestr[pointer++] = mode;
00783         }
00784         modestr[pointer++] = 0;
00785         return modestr;
00786 }


Member Data Documentation

std::string ModeParser::LastParse [private]
 

The string representing the last set of modes to be parsed.

Use GetLastParse() to get this value, to be used for display purposes.

Definition at line 395 of file mode.h.

Referenced by GetLastParse(), ModeParser(), and Process().

ModeHandler* ModeParser::modehandlers[256] [private]
 

Mode handlers for each mode, to access a handler subtract 65 from the ascii value of the mode letter.

The upper bit of the value indicates if its a usermode or a channel mode, so we have 256 of them not 64.

Definition at line 381 of file mode.h.

Referenced by AddMode(), BuildPrefixes(), ChanModes(), ChannelModeList(), DelMode(), FindMode(), FindPrefix(), ModeParser(), ModeString(), ParaModeList(), Process(), and UserModeList().

std::vector<ModeWatcher*> ModeParser::modewatchers[256] [private]
 

Mode watcher classes arranged in the same way as the mode handlers, except for instead of having 256 of them we have 256 lists of them.

Definition at line 386 of file mode.h.

Referenced by AddModeWatcher(), DelModeWatcher(), ModeParser(), and Process().

InspIRCd* ModeParser::ServerInstance [private]
 

Creator/owner pointer.

Definition at line 375 of file mode.h.

Referenced by BuildPrefixes(), ChanModes(), ChannelModeList(), DelMode(), ParaModeList(), Process(), and SanityChecks().


The documentation for this class was generated from the following files: