]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/coremods/core_channel/cmd_invite.cpp
Update copyright headers.
[user/henk/code/inspircd.git] / src / coremods / core_channel / cmd_invite.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2018, 2020 Sadie Powell <sadie@witchery.services>
5  *   Copyright (C) 2018 linuxdaemon <linuxdaemon.irc@gmail.com>
6  *   Copyright (C) 2017 B00mX0r <b00mx0r@aureus.pw>
7  *   Copyright (C) 2013-2016, 2018 Attila Molnar <attilamolnar@hush.com>
8  *   Copyright (C) 2012, 2019 Robby <robby@chatbelgie.be>
9  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
10  *   Copyright (C) 2009 Uli Schlachter <psychon@inspircd.org>
11  *   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
12  *   Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
13  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
14  *   Copyright (C) 2006-2008 Craig Edwards <brain@inspircd.org>
15  *
16  * This file is part of InspIRCd.  InspIRCd is free software: you can
17  * redistribute it and/or modify it under the terms of the GNU General Public
18  * License as published by the Free Software Foundation, version 2.
19  *
20  * This program is distributed in the hope that it will be useful, but WITHOUT
21  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
23  * details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27  */
28
29
30 #include "inspircd.h"
31 #include "core_channel.h"
32 #include "invite.h"
33
34 enum
35 {
36         // From ircd-hybrid.
37         RPL_INVITELIST = 336,
38         RPL_ENDOFINVITELIST = 337
39 };
40
41 CommandInvite::CommandInvite(Module* parent, Invite::APIImpl& invapiimpl)
42         : Command(parent, "INVITE", 0, 0)
43         , invapi(invapiimpl)
44 {
45         Penalty = 4;
46         syntax = "[<nick> <channel> [<time>]]";
47 }
48
49 /** Handle /INVITE
50  */
51 CmdResult CommandInvite::Handle(User* user, const Params& parameters)
52 {
53         ModResult MOD_RESULT;
54
55         if (parameters.size() >= 2)
56         {
57                 User* u;
58                 if (IS_LOCAL(user))
59                         u = ServerInstance->FindNickOnly(parameters[0]);
60                 else
61                         u = ServerInstance->FindNick(parameters[0]);
62
63                 Channel* c = ServerInstance->FindChan(parameters[1]);
64                 time_t timeout = 0;
65                 if (parameters.size() >= 3)
66                 {
67                         if (IS_LOCAL(user))
68                         {
69                                 unsigned long duration;
70                                 if (!InspIRCd::Duration(parameters[2], duration))
71                                 {
72                                         user->WriteNotice("*** Invalid duration for invite");
73                                         return CMD_FAILURE;
74                                 }
75                                 timeout = ServerInstance->Time() + duration;
76                         }
77                         else if (parameters.size() > 3)
78                                 timeout = ConvToNum<time_t>(parameters[3]);
79                 }
80
81                 if (!c)
82                 {
83                         user->WriteNumeric(Numerics::NoSuchChannel(parameters[1]));
84                         return CMD_FAILURE;
85                 }
86                 if ((!u) || (u->registered != REG_ALL))
87                 {
88                         user->WriteNumeric(Numerics::NoSuchNick(parameters[0]));
89                         return CMD_FAILURE;
90                 }
91
92                 // Verify channel timestamp if the INVITE is coming from a remote server
93                 if (!IS_LOCAL(user))
94                 {
95                         // Remote INVITE commands must carry a channel timestamp
96                         if (parameters.size() < 3)
97                                 return CMD_INVALID;
98
99                         // Drop the invite if our channel TS is lower
100                         time_t RemoteTS = ConvToNum<time_t>(parameters[2]);
101                         if (c->age < RemoteTS)
102                                 return CMD_FAILURE;
103                 }
104
105                 if ((IS_LOCAL(user)) && (!c->HasUser(user)))
106                 {
107                         user->WriteNumeric(ERR_NOTONCHANNEL, c->name, "You're not on that channel!");
108                         return CMD_FAILURE;
109                 }
110
111                 if (c->HasUser(u))
112                 {
113                         user->WriteNumeric(ERR_USERONCHANNEL, u->nick, c->name, "is already on channel");
114                         return CMD_FAILURE;
115                 }
116
117                 FIRST_MOD_RESULT(OnUserPreInvite, MOD_RESULT, (user,u,c,timeout));
118
119                 if (MOD_RESULT == MOD_RES_DENY)
120                 {
121                         return CMD_FAILURE;
122                 }
123                 else if (MOD_RESULT == MOD_RES_PASSTHRU)
124                 {
125                         if (IS_LOCAL(user))
126                         {
127                                 unsigned int rank = c->GetPrefixValue(user);
128                                 if (rank < HALFOP_VALUE)
129                                 {
130                                         // Check whether halfop mode is available and phrase error message accordingly
131                                         ModeHandler* mh = ServerInstance->Modes->FindMode('h', MODETYPE_CHANNEL);
132                                         user->WriteNumeric(ERR_CHANOPRIVSNEEDED, c->name, InspIRCd::Format("You must be a channel %soperator",
133                                                 (mh && mh->name == "halfop" ? "half-" : "")));
134                                         return CMD_FAILURE;
135                                 }
136                         }
137                 }
138
139                 LocalUser* const localtargetuser = IS_LOCAL(u);
140                 if (localtargetuser)
141                 {
142                         invapi.Create(localtargetuser, c, timeout);
143                         ClientProtocol::Messages::Invite invitemsg(user, localtargetuser, c);
144                         localtargetuser->Send(ServerInstance->GetRFCEvents().invite, invitemsg);
145                 }
146
147                 if (IS_LOCAL(user))
148                 {
149                         user->WriteNumeric(RPL_INVITING, u->nick, c->name);
150                         if (u->IsAway())
151                                 user->WriteNumeric(RPL_AWAY, u->nick, u->awaymsg);
152                 }
153
154                 char prefix = 0;
155                 unsigned int minrank = 0;
156                 switch (announceinvites)
157                 {
158                         case Invite::ANNOUNCE_OPS:
159                         {
160                                 prefix = '@';
161                                 minrank = OP_VALUE;
162                                 break;
163                         }
164                         case Invite::ANNOUNCE_DYNAMIC:
165                         {
166                                 PrefixMode* mh = ServerInstance->Modes->FindPrefixMode('h');
167                                 if ((mh) && (mh->name == "halfop"))
168                                 {
169                                         prefix = mh->GetPrefix();
170                                         minrank = mh->GetPrefixRank();
171                                 }
172                                 break;
173                         }
174                         default:
175                         {
176                         }
177                 }
178
179                 CUList excepts;
180                 FOREACH_MOD(OnUserInvite, (user, u, c, timeout, minrank, excepts));
181
182                 if (announceinvites != Invite::ANNOUNCE_NONE)
183                 {
184                         excepts.insert(user);
185                         ClientProtocol::Messages::Privmsg privmsg(ServerInstance->FakeClient, c, InspIRCd::Format("*** %s invited %s into the channel", user->nick.c_str(), u->nick.c_str()), MSG_NOTICE);
186                         c->Write(ServerInstance->GetRFCEvents().privmsg, privmsg, prefix, excepts);
187                 }
188         }
189         else if (IS_LOCAL(user))
190         {
191                 // pinched from ircu - invite with not enough parameters shows channels
192                 // youve been invited to but haven't joined yet.
193                 const Invite::List* list = invapi.GetList(IS_LOCAL(user));
194                 if (list)
195                 {
196                         for (Invite::List::const_iterator i = list->begin(); i != list->end(); ++i)
197                                 user->WriteNumeric(RPL_INVITELIST, (*i)->chan->name);
198                 }
199                 user->WriteNumeric(RPL_ENDOFINVITELIST, "End of INVITE list");
200         }
201         return CMD_SUCCESS;
202 }
203
204 RouteDescriptor CommandInvite::GetRouting(User* user, const Params& parameters)
205 {
206         return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
207 }