]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/coremods/core_privmsg.cpp
Handle module reloading in core_reloadmodule entirely
[user/henk/code/inspircd.git] / src / coremods / core_privmsg.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
6  *   Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
7  *
8  * This file is part of InspIRCd.  InspIRCd is free software: you can
9  * redistribute it and/or modify it under the terms of the GNU General Public
10  * License as published by the Free Software Foundation, version 2.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21
22 #include "inspircd.h"
23
24 namespace
25 {
26         const char* MessageTypeString[] = { "PRIVMSG", "NOTICE" };
27 }
28
29 class MessageCommandBase : public Command
30 {
31         ChanModeReference moderatedmode;
32         ChanModeReference noextmsgmode;
33
34         /** Send a PRIVMSG or NOTICE message to all local users from the given user
35          * @param user User sending the message
36          * @param msg The message to send
37          * @param mt Type of the message (MSG_PRIVMSG or MSG_NOTICE)
38          */
39         static void SendAll(User* user, const std::string& msg, MessageType mt);
40
41  public:
42         MessageCommandBase(Module* parent, MessageType mt)
43                 : Command(parent, MessageTypeString[mt], 2, 2)
44                 , moderatedmode(parent, "moderated")
45                 , noextmsgmode(parent, "noextmsg")
46         {
47                 syntax = "<target>{,<target>} <message>";
48         }
49
50         /** Handle command.
51          * @param parameters The parameters to the command
52          * @param user The user issuing the command
53          * @return A value from CmdResult to indicate command success or failure.
54          */
55         CmdResult HandleMessage(const std::vector<std::string>& parameters, User* user, MessageType mt);
56
57         RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
58         {
59                 if (IS_LOCAL(user))
60                         // This is handled by the OnUserMessage hook to split the LoopCall pieces
61                         return ROUTE_LOCALONLY;
62                 else
63                         return ROUTE_MESSAGE(parameters[0]);
64         }
65 };
66
67 void MessageCommandBase::SendAll(User* user, const std::string& msg, MessageType mt)
68 {
69         const std::string message = ":" + user->GetFullHost() + " " + MessageTypeString[mt] + " $* :" + msg;
70         const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
71         for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
72         {
73                 if ((*i)->registered == REG_ALL)
74                         (*i)->Write(message);
75         }
76 }
77
78 CmdResult MessageCommandBase::HandleMessage(const std::vector<std::string>& parameters, User* user, MessageType mt)
79 {
80         User *dest;
81         Channel *chan;
82         CUList except_list;
83
84         LocalUser* localuser = IS_LOCAL(user);
85         if (localuser)
86                 localuser->idle_lastmsg = ServerInstance->Time();
87
88         if (CommandParser::LoopCall(user, this, parameters, 0))
89                 return CMD_SUCCESS;
90
91         if (parameters[0][0] == '$')
92         {
93                 if (!user->HasPrivPermission("users/mass-message"))
94                         return CMD_SUCCESS;
95
96                 ModResult MOD_RESULT;
97                 std::string temp = parameters[1];
98                 FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, except_list, mt));
99                 if (MOD_RESULT == MOD_RES_DENY)
100                         return CMD_FAILURE;
101
102                 const char* text = temp.c_str();
103                 const char* servermask = (parameters[0].c_str()) + 1;
104
105                 FOREACH_MOD(OnText, (user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list));
106                 if (InspIRCd::Match(ServerInstance->Config->ServerName, servermask, NULL))
107                 {
108                         SendAll(user, text, mt);
109                 }
110                 FOREACH_MOD(OnUserMessage, (user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list, mt));
111                 return CMD_SUCCESS;
112         }
113         char status = 0;
114         const char* target = parameters[0].c_str();
115
116         if (ServerInstance->Modes->FindPrefix(*target))
117         {
118                 status = *target;
119                 target++;
120         }
121         if (*target == '#')
122         {
123                 chan = ServerInstance->FindChan(target);
124
125                 except_list.insert(user);
126
127                 if (chan)
128                 {
129                         if (localuser && chan->GetPrefixValue(user) < VOICE_VALUE)
130                         {
131                                 if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(user))
132                                 {
133                                         user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel (no external messages)", chan->name.c_str());
134                                         return CMD_FAILURE;
135                                 }
136
137                                 if (chan->IsModeSet(moderatedmode))
138                                 {
139                                         user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel (+m)", chan->name.c_str());
140                                         return CMD_FAILURE;
141                                 }
142
143                                 if (ServerInstance->Config->RestrictBannedUsers)
144                                 {
145                                         if (chan->IsBanned(user))
146                                         {
147                                                 user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel (you're banned)", chan->name.c_str());
148                                                 return CMD_FAILURE;
149                                         }
150                                 }
151                         }
152                         ModResult MOD_RESULT;
153
154                         std::string temp = parameters[1];
155                         FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, chan, TYPE_CHANNEL, temp, status, except_list, mt));
156                         if (MOD_RESULT == MOD_RES_DENY)
157                                 return CMD_FAILURE;
158
159                         const char* text = temp.c_str();
160
161                         /* Check again, a module may have zapped the input string */
162                         if (temp.empty())
163                         {
164                                 user->WriteNumeric(ERR_NOTEXTTOSEND, ":No text to send");
165                                 return CMD_FAILURE;
166                         }
167
168                         FOREACH_MOD(OnText, (user,chan,TYPE_CHANNEL,text,status,except_list));
169
170                         if (status)
171                         {
172                                 if (ServerInstance->Config->UndernetMsgPrefix)
173                                 {
174                                         chan->WriteAllExcept(user, false, status, except_list, "%s %c%s :%c %s", MessageTypeString[mt], status, chan->name.c_str(), status, text);
175                                 }
176                                 else
177                                 {
178                                         chan->WriteAllExcept(user, false, status, except_list, "%s %c%s :%s", MessageTypeString[mt], status, chan->name.c_str(), text);
179                                 }
180                         }
181                         else
182                         {
183                                 chan->WriteAllExcept(user, false, status, except_list, "%s %s :%s", MessageTypeString[mt], chan->name.c_str(), text);
184                         }
185
186                         FOREACH_MOD(OnUserMessage, (user,chan, TYPE_CHANNEL, text, status, except_list, mt));
187                 }
188                 else
189                 {
190                         /* no such nick/channel */
191                         user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", target);
192                         return CMD_FAILURE;
193                 }
194                 return CMD_SUCCESS;
195         }
196
197         const char* destnick = parameters[0].c_str();
198
199         if (localuser)
200         {
201                 const char* targetserver = strchr(destnick, '@');
202
203                 if (targetserver)
204                 {
205                         std::string nickonly;
206
207                         nickonly.assign(destnick, 0, targetserver - destnick);
208                         dest = ServerInstance->FindNickOnly(nickonly);
209                         if (dest && strcasecmp(dest->server->GetName().c_str(), targetserver + 1))
210                         {
211                                 /* Incorrect server for user */
212                                 user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
213                                 return CMD_FAILURE;
214                         }
215                 }
216                 else
217                         dest = ServerInstance->FindNickOnly(destnick);
218         }
219         else
220                 dest = ServerInstance->FindNick(destnick);
221
222         if ((dest) && (dest->registered == REG_ALL))
223         {
224                 if (parameters[1].empty())
225                 {
226                         user->WriteNumeric(ERR_NOTEXTTOSEND, ":No text to send");
227                         return CMD_FAILURE;
228                 }
229
230                 if ((dest->IsAway()) && (mt == MSG_PRIVMSG))
231                 {
232                         /* auto respond with aweh msg */
233                         user->WriteNumeric(RPL_AWAY, "%s :%s", dest->nick.c_str(), dest->awaymsg.c_str());
234                 }
235
236                 ModResult MOD_RESULT;
237
238                 std::string temp = parameters[1];
239                 FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, dest, TYPE_USER, temp, 0, except_list, mt));
240                 if (MOD_RESULT == MOD_RES_DENY)
241                         return CMD_FAILURE;
242
243                 const char* text = temp.c_str();
244
245                 FOREACH_MOD(OnText, (user, dest, TYPE_USER, text, 0, except_list));
246
247                 if (IS_LOCAL(dest))
248                 {
249                         // direct write, same server
250                         dest->WriteFrom(user, "%s %s :%s", MessageTypeString[mt], dest->nick.c_str(), text);
251                 }
252
253                 FOREACH_MOD(OnUserMessage, (user, dest, TYPE_USER, text, 0, except_list, mt));
254         }
255         else
256         {
257                 /* no such nick/channel */
258                 user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str());
259                 return CMD_FAILURE;
260         }
261         return CMD_SUCCESS;
262 }
263
264 template<MessageType MT>
265 class CommandMessage : public MessageCommandBase
266 {
267  public:
268         CommandMessage(Module* parent)
269                 : MessageCommandBase(parent, MT)
270         {
271         }
272
273         CmdResult Handle(const std::vector<std::string>& parameters, User* user)
274         {
275                 return HandleMessage(parameters, user, MT);
276         }
277 };
278
279 class ModuleCoreMessage : public Module
280 {
281         CommandMessage<MSG_PRIVMSG> CommandPrivmsg;
282         CommandMessage<MSG_NOTICE> CommandNotice;
283
284  public:
285         ModuleCoreMessage()
286                 : CommandPrivmsg(this), CommandNotice(this)
287         {
288         }
289
290         Version GetVersion()
291         {
292                 return Version("PRIVMSG, NOTICE", VF_CORE|VF_VENDOR);
293         }
294 };
295
296 MODULE_INIT(ModuleCoreMessage)