]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/commands/cmd_privmsg.cpp
5519be2fa14d1a455cc39fb416b9151b7deaf9d4
[user/henk/code/inspircd.git] / src / commands / cmd_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  public:
35         MessageCommandBase(Module* parent, MessageType mt)
36                 : Command(parent, MessageTypeString[mt], 2, 2)
37                 , moderatedmode(parent, "moderated")
38                 , noextmsgmode(parent, "noextmsg")
39         {
40                 syntax = "<target>{,<target>} <message>";
41         }
42
43         /** Handle command.
44          * @param parameters The parameters to the comamnd
45          * @param user The user issuing the command
46          * @return A value from CmdResult to indicate command success or failure.
47          */
48         CmdResult HandleMessage(const std::vector<std::string>& parameters, User* user, MessageType mt);
49
50         RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
51         {
52                 if (IS_LOCAL(user))
53                         // This is handled by the OnUserMessage hook to split the LoopCall pieces
54                         return ROUTE_LOCALONLY;
55                 else
56                         return ROUTE_MESSAGE(parameters[0]);
57         }
58 };
59
60 CmdResult MessageCommandBase::HandleMessage(const std::vector<std::string>& parameters, User* user, MessageType mt)
61 {
62         User *dest;
63         Channel *chan;
64         CUList except_list;
65
66         LocalUser* localuser = IS_LOCAL(user);
67         if (localuser)
68                 localuser->idle_lastmsg = ServerInstance->Time();
69
70         if (CommandParser::LoopCall(user, this, parameters, 0))
71                 return CMD_SUCCESS;
72
73         if (parameters[0][0] == '$')
74         {
75                 if (!user->HasPrivPermission("users/mass-message"))
76                         return CMD_SUCCESS;
77
78                 ModResult MOD_RESULT;
79                 std::string temp = parameters[1];
80                 FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, except_list, mt));
81                 if (MOD_RESULT == MOD_RES_DENY)
82                         return CMD_FAILURE;
83
84                 const char* text = temp.c_str();
85                 const char* servermask = (parameters[0].c_str()) + 1;
86
87                 FOREACH_MOD(I_OnText,OnText(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list));
88                 if (InspIRCd::Match(ServerInstance->Config->ServerName, servermask, NULL))
89                 {
90                         user->SendAll(MessageTypeString[mt], "%s", text);
91                 }
92                 FOREACH_MOD(I_OnUserMessage,OnUserMessage(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list, mt));
93                 return CMD_SUCCESS;
94         }
95         char status = 0;
96         const char* target = parameters[0].c_str();
97
98         if (ServerInstance->Modes->FindPrefix(*target))
99         {
100                 status = *target;
101                 target++;
102         }
103         if (*target == '#')
104         {
105                 chan = ServerInstance->FindChan(target);
106
107                 except_list.insert(user);
108
109                 if (chan)
110                 {
111                         if (localuser && chan->GetPrefixValue(user) < VOICE_VALUE)
112                         {
113                                 if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(user))
114                                 {
115                                         user->WriteNumeric(404, "%s %s :Cannot send to channel (no external messages)", user->nick.c_str(), chan->name.c_str());
116                                         return CMD_FAILURE;
117                                 }
118
119                                 if (chan->IsModeSet(moderatedmode))
120                                 {
121                                         user->WriteNumeric(404, "%s %s :Cannot send to channel (+m)", user->nick.c_str(), chan->name.c_str());
122                                         return CMD_FAILURE;
123                                 }
124
125                                 if (ServerInstance->Config->RestrictBannedUsers)
126                                 {
127                                         if (chan->IsBanned(user))
128                                         {
129                                                 user->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", user->nick.c_str(), chan->name.c_str());
130                                                 return CMD_FAILURE;
131                                         }
132                                 }
133                         }
134                         ModResult MOD_RESULT;
135
136                         std::string temp = parameters[1];
137                         FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, chan, TYPE_CHANNEL, temp, status, except_list, mt));
138                         if (MOD_RESULT == MOD_RES_DENY)
139                                 return CMD_FAILURE;
140
141                         const char* text = temp.c_str();
142
143                         /* Check again, a module may have zapped the input string */
144                         if (temp.empty())
145                         {
146                                 user->WriteNumeric(412, "%s :No text to send", user->nick.c_str());
147                                 return CMD_FAILURE;
148                         }
149
150                         FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,except_list));
151
152                         if (status)
153                         {
154                                 if (ServerInstance->Config->UndernetMsgPrefix)
155                                 {
156                                         chan->WriteAllExcept(user, false, status, except_list, "%s %c%s :%c %s", MessageTypeString[mt], status, chan->name.c_str(), status, text);
157                                 }
158                                 else
159                                 {
160                                         chan->WriteAllExcept(user, false, status, except_list, "%s %c%s :%s", MessageTypeString[mt], status, chan->name.c_str(), text);
161                                 }
162                         }
163                         else
164                         {
165                                 chan->WriteAllExcept(user, false, status, except_list, "%s %s :%s", MessageTypeString[mt], chan->name.c_str(), text);
166                         }
167
168                         FOREACH_MOD(I_OnUserMessage, OnUserMessage(user,chan, TYPE_CHANNEL, text, status, except_list, mt));
169                 }
170                 else
171                 {
172                         /* no such nick/channel */
173                         user->WriteNumeric(401, "%s %s :No such nick/channel", user->nick.c_str(), target);
174                         return CMD_FAILURE;
175                 }
176                 return CMD_SUCCESS;
177         }
178
179         const char* destnick = parameters[0].c_str();
180
181         if (localuser)
182         {
183                 const char* targetserver = strchr(destnick, '@');
184
185                 if (targetserver)
186                 {
187                         std::string nickonly;
188
189                         nickonly.assign(destnick, 0, targetserver - destnick);
190                         dest = ServerInstance->FindNickOnly(nickonly);
191                         if (dest && strcasecmp(dest->server.c_str(), targetserver + 1))
192                         {
193                                 /* Incorrect server for user */
194                                 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
195                                 return CMD_FAILURE;
196                         }
197                 }
198                 else
199                         dest = ServerInstance->FindNickOnly(destnick);
200         }
201         else
202                 dest = ServerInstance->FindNick(destnick);
203
204         if ((dest) && (dest->registered == REG_ALL))
205         {
206                 if (parameters[1].empty())
207                 {
208                         user->WriteNumeric(412, "%s :No text to send", user->nick.c_str());
209                         return CMD_FAILURE;
210                 }
211
212                 if ((dest->IsAway()) && (mt == MSG_PRIVMSG))
213                 {
214                         /* auto respond with aweh msg */
215                         user->WriteNumeric(301, "%s %s :%s", user->nick.c_str(), dest->nick.c_str(), dest->awaymsg.c_str());
216                 }
217
218                 ModResult MOD_RESULT;
219
220                 std::string temp = parameters[1];
221                 FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, dest, TYPE_USER, temp, 0, except_list, mt));
222                 if (MOD_RESULT == MOD_RES_DENY)
223                         return CMD_FAILURE;
224
225                 const char* text = temp.c_str();
226
227                 FOREACH_MOD(I_OnText,OnText(user, dest, TYPE_USER, text, 0, except_list));
228
229                 if (IS_LOCAL(dest))
230                 {
231                         // direct write, same server
232                         user->WriteTo(dest, "%s %s :%s", MessageTypeString[mt], dest->nick.c_str(), text);
233                 }
234
235                 FOREACH_MOD(I_OnUserMessage,OnUserMessage(user, dest, TYPE_USER, text, 0, except_list, mt));
236         }
237         else
238         {
239                 /* no such nick/channel */
240                 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
241                 return CMD_FAILURE;
242         }
243         return CMD_SUCCESS;
244 }
245
246 template<MessageType MT>
247 class CommandMessage : public MessageCommandBase
248 {
249  public:
250         CommandMessage(Module* parent)
251                 : MessageCommandBase(parent, MT)
252         {
253         }
254
255         CmdResult Handle(const std::vector<std::string>& parameters, User* user)
256         {
257                 return HandleMessage(parameters, user, MT);
258         }
259 };
260
261 class ModuleCoreMessage : public Module
262 {
263         CommandMessage<MSG_PRIVMSG> CommandPrivmsg;
264         CommandMessage<MSG_NOTICE> CommandNotice;
265
266  public:
267         ModuleCoreMessage()
268                 : CommandPrivmsg(this), CommandNotice(this)
269         {
270         }
271
272         void init()
273         {
274                 ServerInstance->Modules->AddService(CommandPrivmsg);
275                 ServerInstance->Modules->AddService(CommandNotice);
276         }
277
278         Version GetVersion()
279         {
280                 return Version("PRIVMSG, NOTICE", VF_CORE|VF_VENDOR);
281         }
282 };
283
284 MODULE_INIT(ModuleCoreMessage)