]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/m_ircv3.cpp
Fix a bunch of weird indentation and spacing issues.
[user/henk/code/inspircd.git] / src / modules / m_ircv3.cpp
index 59a69f6691ede180a2a43afa50e1ec8056618714..e23999045934fe66e83c97e275d62254e7625410 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * InspIRCd -- Internet Relay Chat Daemon
  *
- *   Copyright (C) 2012 Attila Molnar <attilamolnar@hush.com>
+ *   Copyright (C) 2013, 2018-2019 Sadie Powell <sadie@witchery.services>
+ *   Copyright (C) 2012-2013, 2015, 2018 Attila Molnar <attilamolnar@hush.com>
  *
  * This file is part of InspIRCd.  InspIRCd is free software: you can
  * redistribute it and/or modify it under the terms of the GNU General Public
 
 #include "inspircd.h"
 #include "modules/account.h"
+#include "modules/away.h"
 #include "modules/cap.h"
+#include "modules/ircv3.h"
 
-class ModuleIRCv3 : public Module
+class AwayMessage : public ClientProtocol::Message
 {
-       GenericCap cap_accountnotify;
-       GenericCap cap_awaynotify;
-       GenericCap cap_extendedjoin;
-       bool accountnotify;
-       bool awaynotify;
-       bool extendedjoin;
-
-       CUList last_excepts;
-
-       void WriteNeighboursWithExt(User* user, const std::string& line, const LocalIntExt& ext)
+ public:
+       AwayMessage(User* user)
+               : ClientProtocol::Message("AWAY", user)
        {
-               UserChanList chans(user->chans);
-
-               std::map<User*, bool> exceptions;
-               FOREACH_MOD(OnBuildNeighborList, (user, chans, exceptions));
-
-               // Send it to all local users who were explicitly marked as neighbours by modules and have the required ext
-               for (std::map<User*, bool>::const_iterator i = exceptions.begin(); i != exceptions.end(); ++i)
-               {
-                       LocalUser* u = IS_LOCAL(i->first);
-                       if ((u) && (i->second) && (ext.get(u)))
-                               u->Write(line);
-               }
-
-               // Now consider sending it to all other users who has at least a common channel with the user
-               std::set<User*> already_sent;
-               for (UCListIter i = chans.begin(); i != chans.end(); ++i)
-               {
-                       const UserMembList* userlist = (*i)->GetUsers();
-                       for (UserMembList::const_iterator m = userlist->begin(); m != userlist->end(); ++m)
-                       {
-                               /*
-                                * Send the line if the channel member in question meets all of the following criteria:
-                                * - local
-                                * - not the user who is doing the action (i.e. whose channels we're iterating)
-                                * - has the given extension
-                                * - not on the except list built by modules
-                                * - we haven't sent the line to the member yet
-                                *
-                                */
-                               LocalUser* member = IS_LOCAL(m->first);
-                               if ((member) && (member != user) && (ext.get(member)) && (exceptions.find(member) == exceptions.end()) && (already_sent.insert(member).second))
-                                       member->Write(line);
-                       }
-               }
+               SetParams(user, user->awaymsg);
        }
 
- public:
-       ModuleIRCv3() : cap_accountnotify(this, "account-notify"),
-                                       cap_awaynotify(this, "away-notify"),
-                                       cap_extendedjoin(this, "extended-join")
+       AwayMessage()
+               : ClientProtocol::Message("AWAY")
        {
        }
 
-       void init() CXX11_OVERRIDE
+       void SetParams(User* user, const std::string& awaymsg)
        {
-               OnRehash(NULL);
+               // Going away: 1 parameter which is the away reason
+               // Back from away: no parameter
+               if (!awaymsg.empty())
+                       PushParam(awaymsg);
        }
+};
+
+class JoinHook : public ClientProtocol::EventHook
+{
+       ClientProtocol::Events::Join extendedjoinmsg;
 
-       void OnRehash(User* user) CXX11_OVERRIDE
+ public:
+       const std::string asterisk;
+       ClientProtocol::EventProvider awayprotoev;
+       AwayMessage awaymsg;
+       Cap::Capability extendedjoincap;
+       Cap::Capability awaycap;
+
+       JoinHook(Module* mod)
+               : ClientProtocol::EventHook(mod, "JOIN")
+               , asterisk(1, '*')
+               , awayprotoev(mod, "AWAY")
+               , extendedjoincap(mod, "extended-join")
+               , awaycap(mod, "away-notify")
        {
-               ConfigTag* conf = ServerInstance->Config->ConfValue("ircv3");
-               accountnotify = conf->getBool("accoutnotify", true);
-               awaynotify = conf->getBool("awaynotify", true);
-               extendedjoin = conf->getBool("extendedjoin", true);
        }
 
-       void OnEvent(Event& ev) CXX11_OVERRIDE
+       void OnEventInit(const ClientProtocol::Event& ev) CXX11_OVERRIDE
        {
-               if (awaynotify)
-                       cap_awaynotify.HandleEvent(ev);
-               if (extendedjoin)
-                       cap_extendedjoin.HandleEvent(ev);
+               const ClientProtocol::Events::Join& join = static_cast<const ClientProtocol::Events::Join&>(ev);
+
+               // An extended join has two extra parameters:
+               // First the account name of the joining user or an asterisk if the user is not logged in.
+               // The second parameter is the realname of the joining user.
 
-               if (accountnotify)
+               Membership* const memb = join.GetMember();
+               const std::string* account = &asterisk;
+               const AccountExtItem* const accountext = GetAccountExtItem();
+               if (accountext)
                {
-                       cap_accountnotify.HandleEvent(ev);
-
-                       if (ev.id == "account_login")
-                       {
-                               AccountEvent* ae = static_cast<AccountEvent*>(&ev);
-
-                               // :nick!user@host ACCOUNT account
-                               // or
-                               // :nick!user@host ACCOUNT *
-                               std::string line =  ":" + ae->user->GetFullHost() + " ACCOUNT ";
-                               if (ae->account.empty())
-                                       line += "*";
-                               else
-                                       line += std::string(ae->account);
-
-                               WriteNeighboursWithExt(ae->user, line, cap_accountnotify.ext);
-                       }
+                       const std::string* accountname = accountext->get(memb->user);
+                       if (accountname)
+                               account = accountname;
+               }
+
+               extendedjoinmsg.ClearParams();
+               extendedjoinmsg.SetSource(join);
+               extendedjoinmsg.PushParamRef(memb->chan->name);
+               extendedjoinmsg.PushParamRef(*account);
+               extendedjoinmsg.PushParamRef(memb->user->GetRealName());
+
+               awaymsg.ClearParams();
+               if ((memb->user->IsAway()) && (awaycap.IsActive()))
+               {
+                       awaymsg.SetSource(join);
+                       awaymsg.SetParams(memb->user, memb->user->awaymsg);
                }
        }
 
-       void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) CXX11_OVERRIDE
+       ModResult OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist) CXX11_OVERRIDE
        {
-               // Remember who is not going to see the JOIN because of other modules
-               if ((awaynotify) && (memb->user->IsAway()))
-                       last_excepts = excepts;
+               if (extendedjoincap.get(user))
+                       messagelist.front() = &extendedjoinmsg;
 
-               if (!extendedjoin)
-                       return;
+               if ((!awaymsg.GetParams().empty()) && (awaycap.get(user)))
+                       messagelist.push_back(&awaymsg);
 
-               /*
-                * Send extended joins to clients who have the extended-join capability.
-                * An extended join looks like this:
-                *
-                * :nick!user@host JOIN #chan account :realname
-                *
-                * account is the joining user's account if he's logged in, otherwise it's an asterisk (*).
-                */
+               return MOD_RES_PASSTHRU;
+       }
+};
 
-               std::string line;
-               std::string mode;
+class ModuleIRCv3
+       : public Module
+       , public AccountEventListener
+       , public Away::EventListener
+{
+       Cap::Capability cap_accountnotify;
+       JoinHook joinhook;
 
-               const UserMembList* userlist = memb->chan->GetUsers();
-               for (UserMembCIter it = userlist->begin(); it != userlist->end(); ++it)
-               {
-                       // Send the extended join line if the current member is local, has the extended-join cap and isn't excepted
-                       User* member = IS_LOCAL(it->first);
-                       if ((member) && (cap_extendedjoin.ext.get(member)) && (excepts.find(member) == excepts.end()))
-                       {
-                               // Construct the lines we're going to send if we haven't constructed them already
-                               if (line.empty())
-                               {
-                                       bool has_account = false;
-                                       line = ":" + memb->user->GetFullHost() + " JOIN " + memb->chan->name + " ";
-                                       const AccountExtItem* accountext = GetAccountExtItem();
-                                       if (accountext)
-                                       {
-                                               std::string* accountname;
-                                               accountname = accountext->get(memb->user);
-                                               if (accountname)
-                                               {
-                                                       line += *accountname;
-                                                       has_account = true;
-                                               }
-                                       }
-
-                                       if (!has_account)
-                                               line += "*";
-
-                                       line += " :" + memb->user->fullname;
-
-                                       // If the joining user received privileges from another module then we must send them as well,
-                                       // since silencing the normal join means the MODE will be silenced as well
-                                       if (!memb->modes.empty())
-                                       {
-                                               const std::string& modefrom = ServerInstance->Config->CycleHostsFromUser ? memb->user->GetFullHost() : ServerInstance->Config->ServerName;
-                                               mode = ":" + modefrom + " MODE " + memb->chan->name + " +" + memb->modes;
-
-                                               for (unsigned int i = 0; i < memb->modes.length(); i++)
-                                                       mode += " " + memb->user->nick;
-                                       }
-                               }
-
-                               // Write the JOIN and the MODE, if any
-                               member->Write(line);
-                               if ((!mode.empty()) && (member != memb->user))
-                                       member->Write(mode);
-
-                               // Prevent the core from sending the JOIN and MODE to this user
-                               excepts.insert(it->first);
-                       }
-               }
-       }
+       ClientProtocol::EventProvider accountprotoev;
 
-       ModResult OnSetAway(User* user, const std::string &awaymsg) CXX11_OVERRIDE
+ public:
+       ModuleIRCv3()
+               : AccountEventListener(this)
+               , Away::EventListener(this)
+               , cap_accountnotify(this, "account-notify")
+               , joinhook(this)
+               , accountprotoev(this, "ACCOUNT")
        {
-               if (awaynotify)
-               {
-                       // Going away: n!u@h AWAY :reason
-                       // Back from away: n!u@h AWAY
-                       std::string line = ":" + user->GetFullHost() + " AWAY";
-                       if (!awaymsg.empty())
-                               line += " :" + awaymsg;
+       }
 
-                       WriteNeighboursWithExt(user, line, cap_awaynotify.ext);
-               }
-               return MOD_RES_PASSTHRU;
+       void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+       {
+               ConfigTag* conf = ServerInstance->Config->ConfValue("ircv3");
+               cap_accountnotify.SetActive(conf->getBool("accountnotify", true));
+               joinhook.awaycap.SetActive(conf->getBool("awaynotify", true));
+               joinhook.extendedjoincap.SetActive(conf->getBool("extendedjoin", true));
        }
 
-       void OnPostJoin(Membership *memb) CXX11_OVERRIDE
+       void OnAccountChange(User* user, const std::string& newaccount) CXX11_OVERRIDE
        {
-               if ((!awaynotify) || (!memb->user->IsAway()))
+               if (!(user->registered & REG_NICKUSER))
                        return;
 
-               std::string line = ":" + memb->user->GetFullHost() + " AWAY :" + memb->user->awaymsg;
+               // Logged in: 1 parameter which is the account name
+               // Logged out: 1 parameter which is a "*"
+               ClientProtocol::Message msg("ACCOUNT", user);
+               const std::string& param = (newaccount.empty() ? joinhook.asterisk : newaccount);
+               msg.PushParamRef(param);
+               ClientProtocol::Event accountevent(accountprotoev, msg);
+               IRCv3::WriteNeighborsWithCap(user, accountevent, cap_accountnotify);
+       }
 
-               const UserMembList* userlist = memb->chan->GetUsers();
-               for (UserMembCIter it = userlist->begin(); it != userlist->end(); ++it)
-               {
-                       // Send the away notify line if the current member is local, has the away-notify cap and isn't excepted
-                       User* member = IS_LOCAL(it->first);
-                       if ((member) && (cap_awaynotify.ext.get(member)) && (last_excepts.find(member) == last_excepts.end()))
-                       {
-                               member->Write(line);
-                       }
-               }
+       void OnUserAway(User* user) CXX11_OVERRIDE
+       {
+               if (!joinhook.awaycap.IsActive())
+                       return;
 
-               last_excepts.clear();
+               // Going away: n!u@h AWAY :reason
+               AwayMessage msg(user);
+               ClientProtocol::Event awayevent(joinhook.awayprotoev, msg);
+               IRCv3::WriteNeighborsWithCap(user, awayevent, joinhook.awaycap);
        }
 
-       void Prioritize()
+       void OnUserBack(User* user) CXX11_OVERRIDE
        {
-               ServerInstance->Modules->SetPriority(this, I_OnUserJoin, PRIORITY_LAST);
+               if (!joinhook.awaycap.IsActive())
+                       return;
+
+               // Back from away: n!u@h AWAY
+               AwayMessage msg(user);
+               ClientProtocol::Event awayevent(joinhook.awayprotoev, msg);
+               IRCv3::WriteNeighborsWithCap(user, awayevent, joinhook.awaycap);
        }
 
        Version GetVersion() CXX11_OVERRIDE
        {
-               return Version("Provides support for extended-join, away-notify and account-notify CAP capabilities", VF_VENDOR);
+               return Version("Provides the IRCv3 account-notify, away-notify, and extended-join client capabilities.", VF_VENDOR);
        }
 };