]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_ircv3.cpp
54163f2b1beafc4ec69b7edb4f1a68c8cc6dcae0
[user/henk/code/inspircd.git] / src / modules / m_ircv3.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2013, 2018-2019 Sadie Powell <sadie@witchery.services>
5  *   Copyright (C) 2012-2013, 2015, 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 #include "inspircd.h"
21 #include "modules/account.h"
22 #include "modules/away.h"
23 #include "modules/cap.h"
24 #include "modules/ircv3.h"
25
26 class AwayMessage : public ClientProtocol::Message
27 {
28  public:
29         AwayMessage(User* user)
30                 : ClientProtocol::Message("AWAY", user)
31         {
32                 SetParams(user, user->awaymsg);
33         }
34
35         AwayMessage()
36                 : ClientProtocol::Message("AWAY")
37         {
38         }
39
40         void SetParams(User* user, const std::string& awaymsg)
41         {
42                 // Going away: 1 parameter which is the away reason
43                 // Back from away: no parameter
44                 if (!awaymsg.empty())
45                         PushParam(awaymsg);
46         }
47 };
48
49 class JoinHook : public ClientProtocol::EventHook
50 {
51         ClientProtocol::Events::Join extendedjoinmsg;
52
53  public:
54         const std::string asterisk;
55         ClientProtocol::EventProvider awayprotoev;
56         AwayMessage awaymsg;
57         Cap::Capability extendedjoincap;
58         Cap::Capability awaycap;
59
60         JoinHook(Module* mod)
61                 : ClientProtocol::EventHook(mod, "JOIN")
62                 , asterisk(1, '*')
63                 , awayprotoev(mod, "AWAY")
64                 , extendedjoincap(mod, "extended-join")
65                 , awaycap(mod, "away-notify")
66         {
67         }
68
69         void OnEventInit(const ClientProtocol::Event& ev) CXX11_OVERRIDE
70         {
71                 const ClientProtocol::Events::Join& join = static_cast<const ClientProtocol::Events::Join&>(ev);
72
73                 // An extended join has two extra parameters:
74                 // First the account name of the joining user or an asterisk if the user is not logged in.
75                 // The second parameter is the realname of the joining user.
76
77                 Membership* const memb = join.GetMember();
78                 const std::string* account = &asterisk;
79                 const AccountExtItem* const accountext = GetAccountExtItem();
80                 if (accountext)
81                 {
82                         const std::string* accountname = accountext->get(memb->user);
83                         if (accountname)
84                                 account = accountname;
85                 }
86
87                 extendedjoinmsg.ClearParams();
88                 extendedjoinmsg.SetSource(join);
89                 extendedjoinmsg.PushParamRef(memb->chan->name);
90                 extendedjoinmsg.PushParamRef(*account);
91                 extendedjoinmsg.PushParamRef(memb->user->GetRealName());
92
93                 awaymsg.ClearParams();
94                 if ((memb->user->IsAway()) && (awaycap.IsActive()))
95                 {
96                         awaymsg.SetSource(join);
97                         awaymsg.SetParams(memb->user, memb->user->awaymsg);
98                 }
99         }
100
101         ModResult OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist) CXX11_OVERRIDE
102         {
103                 if (extendedjoincap.get(user))
104                         messagelist.front() = &extendedjoinmsg;
105
106                 if ((!awaymsg.GetParams().empty()) && (awaycap.get(user)))
107                         messagelist.push_back(&awaymsg);
108
109                 return MOD_RES_PASSTHRU;
110         }
111 };
112
113 class ModuleIRCv3
114         : public Module
115         , public AccountEventListener
116         , public Away::EventListener
117 {
118         Cap::Capability cap_accountnotify;
119         JoinHook joinhook;
120
121         ClientProtocol::EventProvider accountprotoev;
122
123  public:
124         ModuleIRCv3()
125                 : AccountEventListener(this)
126                 , Away::EventListener(this)
127                 , cap_accountnotify(this, "account-notify")
128                 , joinhook(this)
129                 , accountprotoev(this, "ACCOUNT")
130         {
131         }
132
133         void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
134         {
135                 ConfigTag* conf = ServerInstance->Config->ConfValue("ircv3");
136                 cap_accountnotify.SetActive(conf->getBool("accountnotify", true));
137                 joinhook.awaycap.SetActive(conf->getBool("awaynotify", true));
138                 joinhook.extendedjoincap.SetActive(conf->getBool("extendedjoin", true));
139         }
140
141         void OnAccountChange(User* user, const std::string& newaccount) CXX11_OVERRIDE
142         {
143                 if (!(user->registered & REG_NICKUSER))
144                         return;
145
146                 // Logged in: 1 parameter which is the account name
147                 // Logged out: 1 parameter which is a "*"
148                 ClientProtocol::Message msg("ACCOUNT", user);
149                 const std::string& param = (newaccount.empty() ? joinhook.asterisk : newaccount);
150                 msg.PushParamRef(param);
151                 ClientProtocol::Event accountevent(accountprotoev, msg);
152                 IRCv3::WriteNeighborsWithCap(user, accountevent, cap_accountnotify);
153         }
154
155         void OnUserAway(User* user) CXX11_OVERRIDE
156         {
157                 if (!joinhook.awaycap.IsActive())
158                         return;
159
160                 // Going away: n!u@h AWAY :reason
161                 AwayMessage msg(user);
162                 ClientProtocol::Event awayevent(joinhook.awayprotoev, msg);
163                 IRCv3::WriteNeighborsWithCap(user, awayevent, joinhook.awaycap);
164         }
165
166         void OnUserBack(User* user) CXX11_OVERRIDE
167         {
168                 if (!joinhook.awaycap.IsActive())
169                         return;
170
171                 // Back from away: n!u@h AWAY
172                 AwayMessage msg(user);
173                 ClientProtocol::Event awayevent(joinhook.awayprotoev, msg);
174                 IRCv3::WriteNeighborsWithCap(user, awayevent, joinhook.awaycap);
175         }
176
177         Version GetVersion() CXX11_OVERRIDE
178         {
179                 return Version("Provides the IRCv3 account-notify, away-notify, and extended-join client capabilities.", VF_VENDOR);
180         }
181 };
182
183 MODULE_INIT(ModuleIRCv3)