]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_hostcycle.cpp
c3131b42478a6cff563d5f5d90cc4a2d34a0a0a0
[user/henk/code/inspircd.git] / src / modules / m_hostcycle.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2017-2018 Sadie Powell <sadie@witchery.services>
5  *   Copyright (C) 2013-2015, 2017-2018 Attila Molnar <attilamolnar@hush.com>
6  *
7  * This file is part of InspIRCd.  InspIRCd is free software: you can
8  * redistribute it and/or modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation, version 2.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20
21 #include "inspircd.h"
22 #include "modules/cap.h"
23
24 class ModuleHostCycle : public Module
25 {
26         Cap::Reference chghostcap;
27         const std::string quitmsghost;
28         const std::string quitmsgident;
29
30         /** Send fake quit/join/mode messages for host or ident cycle.
31          */
32         void DoHostCycle(User* user, const std::string& newident, const std::string& newhost, const std::string& reason)
33         {
34                 // The user has the original ident/host at the time this function is called
35                 ClientProtocol::Messages::Quit quitmsg(user, reason);
36                 ClientProtocol::Event quitevent(ServerInstance->GetRFCEvents().quit, quitmsg);
37
38                 already_sent_t silent_id = ServerInstance->Users.NextAlreadySentId();
39                 already_sent_t seen_id = ServerInstance->Users.NextAlreadySentId();
40
41                 IncludeChanList include_chans(user->chans.begin(), user->chans.end());
42                 std::map<User*,bool> exceptions;
43
44                 FOREACH_MOD(OnBuildNeighborList, (user, include_chans, exceptions));
45
46                 // Users shouldn't see themselves quitting when host cycling
47                 exceptions.erase(user);
48                 for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
49                 {
50                         LocalUser* u = IS_LOCAL(i->first);
51                         if ((u) && (!u->quitting) && (!chghostcap.get(u)))
52                         {
53                                 if (i->second)
54                                 {
55                                         u->already_sent = seen_id;
56                                         u->Send(quitevent);
57                                 }
58                                 else
59                                 {
60                                         u->already_sent = silent_id;
61                                 }
62                         }
63                 }
64
65                 std::string newfullhost = user->nick + "!" + newident + "@" + newhost;
66
67                 for (IncludeChanList::const_iterator i = include_chans.begin(); i != include_chans.end(); ++i)
68                 {
69                         Membership* memb = *i;
70                         Channel* c = memb->chan;
71
72                         ClientProtocol::Events::Join joinevent(memb, newfullhost);
73
74                         const Channel::MemberMap& ulist = c->GetUsers();
75                         for (Channel::MemberMap::const_iterator j = ulist.begin(); j != ulist.end(); ++j)
76                         {
77                                 LocalUser* u = IS_LOCAL(j->first);
78                                 if (u == NULL || u == user)
79                                         continue;
80                                 if (u->already_sent == silent_id)
81                                         continue;
82                                 if (chghostcap.get(u))
83                                         continue;
84
85                                 if (u->already_sent != seen_id)
86                                 {
87                                         u->Send(quitevent);
88                                         u->already_sent = seen_id;
89                                 }
90
91                                 u->Send(joinevent);
92                         }
93                 }
94         }
95
96  public:
97         ModuleHostCycle()
98                 : chghostcap(this, "chghost")
99                 , quitmsghost("Changing host")
100                 , quitmsgident("Changing ident")
101         {
102         }
103
104         void OnChangeIdent(User* user, const std::string& newident) CXX11_OVERRIDE
105         {
106                 DoHostCycle(user, newident, user->GetDisplayedHost(), quitmsgident);
107         }
108
109         void OnChangeHost(User* user, const std::string& newhost) CXX11_OVERRIDE
110         {
111                 DoHostCycle(user, user->ident, newhost, quitmsghost);
112         }
113
114         Version GetVersion() CXX11_OVERRIDE
115         {
116                 return Version("Sends a fake disconnection and reconnection when a user's username (ident) or hostname changes to allow clients to update their internal caches.", VF_VENDOR);
117         }
118 };
119
120 MODULE_INIT(ModuleHostCycle)