]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/clientprotocolmsg.h
Fix RPL_ADMINME not having the correct parameters.
[user/henk/code/inspircd.git] / include / clientprotocolmsg.h
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com>
5  *
6  * This file is part of InspIRCd.  InspIRCd is free software: you can
7  * redistribute it and/or modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation, version 2.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
13  * details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19
20 #pragma once
21
22 namespace ClientProtocol
23 {
24         namespace Messages
25         {
26                 class Numeric;
27                 class Join;
28                 struct Part;
29                 struct Kick;
30                 struct Quit;
31                 struct Nick;
32                 class Mode;
33                 struct Topic;
34                 class Privmsg;
35                 struct Invite;
36                 struct Ping;
37                 struct Pong;
38                 struct Error;
39         }
40 }
41
42 /** Numeric message.
43  * Doesn't have a fixed command name, it's always a 3 digit number padded with zeroes if necessary.
44  * The first parameter is the target of the numeric which is almost always the nick of the user
45  * the numeric will be sent to.
46  */
47 class ClientProtocol::Messages::Numeric : public ClientProtocol::Message
48 {
49         char numericstr[4];
50
51         void InitCommand(unsigned int number)
52         {
53                 snprintf(numericstr, sizeof(numericstr), "%03u", number);
54                 SetCommand(numericstr);
55         }
56
57         void InitFromNumeric(const ::Numeric::Numeric& numeric)
58         {
59                 InitCommand(numeric.GetNumeric());
60                 for (std::vector<std::string>::const_iterator i = numeric.GetParams().begin(); i != numeric.GetParams().end(); ++i)
61                         PushParamRef(*i);
62         }
63
64  public:
65         /** Constructor, target is a User.
66          * @param num Numeric object to send. Must remain valid as long as this object is alive and must not be modified.
67          * @param user User to send the numeric to. May be unregistered, must remain valid as long as this object is alive.
68          */
69         Numeric(const ::Numeric::Numeric& num, User* user)
70                 : ClientProtocol::Message(NULL, (num.GetServer() ? num.GetServer()->GetName() : ServerInstance->Config->ServerName))
71         {
72                 if (user->registered & REG_NICK)
73                         PushParamRef(user->nick);
74                 else
75                         PushParam("*");
76                 InitFromNumeric(num);
77         }
78
79         /** Constructor, target is a string.
80          * @param num Numeric object to send. Must remain valid as long as this object is alive and must not be modified.
81          * @param target Target string, must stay valid as long as this object is alive.
82          */
83         Numeric(const ::Numeric::Numeric& num, const std::string& target)
84                 : ClientProtocol::Message(NULL, (num.GetServer() ? num.GetServer()->GetName() : ServerInstance->Config->ServerName))
85         {
86                 PushParamRef(target);
87                 InitFromNumeric(num);
88         }
89
90         /** Constructor. Only the numeric number has to be specified.
91          * @param num Numeric number.
92          */
93         Numeric(unsigned int num)
94                 : ClientProtocol::Message(NULL, ServerInstance->Config->ServerName)
95         {
96                 InitCommand(num);
97                 PushParam("*");
98         }
99 };
100
101 /** JOIN message.
102  * Sent when a user joins a channel.
103  */
104 class ClientProtocol::Messages::Join : public ClientProtocol::Message
105 {
106         Membership* memb;
107
108  public:
109         /** Constructor. Does not populate parameters, call SetParams() before sending the message.
110          */
111         Join()
112                 : ClientProtocol::Message("JOIN")
113                 , memb(NULL)
114         {
115         }
116
117         /** Constructor.
118          * @param Memb Membership of the joining user.
119          */
120         Join(Membership* Memb)
121                 : ClientProtocol::Message("JOIN", Memb->user)
122         {
123                 SetParams(Memb);
124         }
125
126         /** Constructor.
127          * @param Memb Membership of the joining user.
128          * @param sourcestrref Message source string, must remain valid as long as this object is alive.
129          */
130         Join(Membership* Memb, const std::string& sourcestrref)
131                 : ClientProtocol::Message("JOIN", sourcestrref, Memb->user)
132         {
133                 SetParams(Memb);
134         }
135
136         /** Populate parameters from a Membership
137          * @param Memb Membership of the joining user.
138          */
139         void SetParams(Membership* Memb)
140         {
141                 memb = Memb;
142                 PushParamRef(memb->chan->name);
143         }
144
145         /** Get the Membership of the joining user.
146          * @return Membership of the joining user.
147          */
148         Membership* GetMember() const { return memb; }
149 };
150
151 /** PART message.
152  * Sent when a user parts a channel.
153  */
154 struct ClientProtocol::Messages::Part : public ClientProtocol::Message
155 {
156         /** Constructor.
157          * @param memb Member parting.
158          * @param reason Part reason, may be empty. If non-empty, must remain valid as long as this object is alive.
159          */
160         Part(Membership* memb, const std::string& reason)
161                 : ClientProtocol::Message("PART", memb->user)
162         {
163                 PushParamRef(memb->chan->name);
164                 if (!reason.empty())
165                         PushParamRef(reason);
166         }
167 };
168
169 /** KICK message.
170  * Sent when a user is kicked from a channel.
171  */
172 struct ClientProtocol::Messages::Kick : public ClientProtocol::Message
173 {
174         /** Constructor.
175          * @param source User that does the kick.
176          * @param memb Membership of the user being kicked.
177          * @param reason Kick reason. Must remain valid as long as this object is alive.
178          */
179         Kick(User* source, Membership* memb, const std::string& reason)
180                 : ClientProtocol::Message("KICK", source)
181         {
182                 PushParamRef(memb->chan->name);
183                 PushParamRef(memb->user->nick);
184                 PushParamRef(reason);
185         }
186 };
187
188 /** QUIT message.
189  * Sent when a user quits.
190  */
191 struct ClientProtocol::Messages::Quit : public ClientProtocol::Message
192 {
193         /** Constructor.
194          * @param source User quitting.
195          * @param reason Quit reason, may be empty. Must remain valid as long as this object is alive.
196          */
197         Quit(User* source, const std::string& reason)
198                 : ClientProtocol::Message("QUIT", source)
199         {
200                 if (!reason.empty())
201                         PushParamRef(reason);
202         }
203 };
204
205 /** NICK message.
206  * Sent when a user changes their nickname.
207  */
208 struct ClientProtocol::Messages::Nick : public ClientProtocol::Message
209 {
210         /** Constructor.
211          * @param source User changing nicks.
212          * @param newnick New nickname. Must remain valid as long as this object is alive.
213          */
214         Nick(User* source, const std::string& newnick)
215                 : ClientProtocol::Message("NICK", source)
216         {
217                 PushParamRef(newnick);
218         }
219 };
220
221 /** MODE message.
222  * Sent when modes are changed on a user or channel.
223  */
224 class ClientProtocol::Messages::Mode : public ClientProtocol::Message
225 {
226         Channel* chantarget;
227         User* usertarget;
228         Modes::ChangeList::List::const_iterator beginit;
229         Modes::ChangeList::List::const_iterator lastit;
230
231         /** Convert a range of a mode change list to mode letters and '+', '-' symbols.
232          * @param list Mode change list.
233          * @param maxlinelen Maximum output length.
234          * @param beginit Iterator to the first element in 'list' to process.
235          * @param lastit Iterator which is set to the first element not processed due to length limitations by the method.
236          */
237         static std::string ToModeLetters(const Modes::ChangeList::List& list, std::string::size_type maxlinelen, Modes::ChangeList::List::const_iterator beginit, Modes::ChangeList::List::const_iterator& lastit)
238         {
239                 std::string ret;
240                 std::string::size_type paramlength = 0;
241                 char output_pm = '\0'; // current output state, '+' or '-'
242
243                 Modes::ChangeList::List::const_iterator i;
244                 for (i = beginit; i != list.end(); ++i)
245                 {
246                         const Modes::Change& item = *i;
247
248                         const char needed_pm = (item.adding ? '+' : '-');
249                         if (needed_pm != output_pm)
250                         {
251                                 output_pm = needed_pm;
252                                 ret.push_back(output_pm);
253                         }
254
255                         if (!item.param.empty())
256                                 paramlength += item.param.length() + 1;
257                         if (ret.length() + 1 + paramlength > maxlinelen)
258                         {
259                                 // Mode sequence is getting too long
260                                 const char c = *ret.rbegin();
261                                 if ((c == '+') || (c == '-'))
262                                         ret.erase(ret.size()-1);
263                                 break;
264                         }
265
266                         ret.push_back(item.mh->GetModeChar());
267                 }
268
269                 lastit = i;
270                 return ret;
271         }
272
273         /** Push mode parameters for modes that have one, starting at beginit to lastit (not including lastit).
274          */
275         void PushModeParams()
276         {
277                 for (Modes::ChangeList::List::const_iterator i = beginit; i != lastit; ++i)
278                 {
279                         const Modes::Change& item = *i;
280                         if (!item.param.empty())
281                                 PushParamRef(item.param);
282                 }
283         }
284
285  public:
286         /** Convert an entire mode change list into mode letters and '+' and '-' characters.
287          * @param changelist Mode change list to convert into mode letters.
288          * @return Mode letters.
289          */
290         static std::string ToModeLetters(const Modes::ChangeList& changelist)
291         {
292                 // TODO: This assumes that std::string::max_size() >= UINT_MAX
293                 Modes::ChangeList::List::const_iterator dummy;
294                 return ToModeLetters(changelist.getlist(), UINT_MAX, changelist.getlist().begin(), dummy);
295         }
296
297         /** Constructor, populate parameters starting from a given position in a mode change list.
298          * @param source User doing the mode change.
299          * @param Chantarget Channel target of the mode change. May be NULL if Usertarget is non-NULL.
300          * @param Usertarget User target of the mode change. May be NULL if Chantarget is non-NULL.
301          * @param changelist Mode change list. Must remain valid and unchanged as long as this object is alive or until the next SetParams() call.
302          * @param beginiter Starting position of mode changes in 'changelist'.
303          */
304         Mode(User* source, Channel* Chantarget, User* Usertarget, const Modes::ChangeList& changelist, Modes::ChangeList::List::const_iterator beginiter)
305                 : ClientProtocol::Message("MODE", source)
306                 , chantarget(Chantarget)
307                 , usertarget(Usertarget)
308                 , beginit(beginiter)
309         {
310                 PushParamRef(GetStrTarget());
311                 PushParam(ToModeLetters(changelist.getlist(), 450, beginit, lastit));
312                 PushModeParams();
313         }
314
315         /** Constructor, populate parameters starting from the beginning of a mode change list.
316          * @param source User doing the mode change.
317          * @param Chantarget Channel target of the mode change. May be NULL if Usertarget is non-NULL.
318          * @param Usertarget User target of the mode change. May be NULL if Chantarget is non-NULL.
319          * @param changelist Mode change list. Must remain valid and unchanged as long as this object is alive or until the next SetParams() call.
320          */
321         Mode(User* source, Channel* Chantarget, User* Usertarget, const Modes::ChangeList& changelist)
322                 : ClientProtocol::Message("MODE", source)
323                 , chantarget(Chantarget)
324                 , usertarget(Usertarget)
325                 , beginit(changelist.getlist().begin())
326         {
327                 PushParamRef(GetStrTarget());
328                 PushParam(ToModeLetters(changelist.getlist(), 450, beginit, lastit));
329                 PushModeParams();
330         }
331
332         /** Constructor. Does not populate parameters, call SetParams() before sending the message.
333          * The message source is set to the local server.
334          */
335         Mode()
336                 : ClientProtocol::Message("MODE", ServerInstance->FakeClient)
337                 , chantarget(NULL)
338                 , usertarget(NULL)
339         {
340         }
341
342         /** Set parameters
343          * @param Chantarget Channel target of the mode change. May be NULL if Usertarget is non-NULL.
344          * @param Usertarget User target of the mode change. May be NULL if Chantarget is non-NULL.
345          * @param changelist Mode change list. Must remain valid and unchanged as long as this object is alive or until the next SetParams() call.
346          */
347         void SetParams(Channel* Chantarget, User* Usertarget, const Modes::ChangeList& changelist)
348         {
349                 ClearParams();
350
351                 chantarget = Chantarget;
352                 usertarget = Usertarget;
353                 beginit = changelist.getlist().begin();
354
355                 PushParamRef(GetStrTarget());
356                 PushParam(ToModeLetters(changelist.getlist(), 450, beginit, lastit));
357                 PushModeParams();
358         }
359
360         /** Get first mode change included in this MODE message.
361          * @return Iterator to the first mode change that is included in this MODE message.
362          */
363         Modes::ChangeList::List::const_iterator GetBeginIterator() const { return beginit; }
364
365         /** Get first mode change not included in this MODE message.
366          * @return Iterator to the first mode change that is not included in this MODE message.
367          */
368         Modes::ChangeList::List::const_iterator GetEndIterator() const { return lastit; }
369
370         /** Get mode change target as a string.
371          * This is the name of the channel if the mode change targets a channel or the nickname of the user
372          * if the target is a user.
373          * @return Name of target as a string.
374          */
375         const std::string& GetStrTarget() const { return (chantarget ? chantarget->name : usertarget->nick); }
376
377         /** Get user target.
378          * @return User target or NULL if the mode change targets a channel.
379          */
380         User* GetUserTarget() const { return usertarget; }
381
382         /** Get channel target.
383          * @return Channel target or NULL if the mode change targets a user.
384          */
385         Channel* GetChanTarget() const { return chantarget; }
386 };
387
388 /** TOPIC message.
389  */
390 struct ClientProtocol::Messages::Topic : public ClientProtocol::Message
391 {
392         /** Constructor.
393          * @param source User changing the topic.
394          * @param chan Channel the topic is being changed on.
395          * @param newtopic New topic. May be empty, must remain valid as long as this object is alive.
396          */
397         Topic(User* source, const Channel* chan, const std::string& newtopic)
398                 : ClientProtocol::Message("TOPIC", source)
399         {
400                 PushParamRef(chan->name);
401                 PushParamRef(newtopic);
402         }
403 };
404
405 /** PRIVMSG and NOTICE message.
406  */
407 class ClientProtocol::Messages::Privmsg : public ClientProtocol::Message
408 {
409         void PushTargetChan(char status, const Channel* targetchan)
410         {
411                 if (status)
412                 {
413                         std::string rawtarget(1, status);
414                         rawtarget.append(targetchan->name);
415                         PushParam(rawtarget);
416                 }
417                 else
418                 {
419                         PushParamRef(targetchan->name);
420                 }
421         }
422
423         void PushTargetUser(const User* targetuser)
424         {
425                 if (targetuser->registered & REG_NICK)
426                         PushParamRef(targetuser->nick);
427                 else
428                         PushParam("*");
429         }
430
431  public:
432         /** Used to differentiate constructors that copy the text from constructors that do not.
433          */
434         enum NoCopy { nocopy };
435
436         /** Get command name from MessageType.
437          * @param mt Message type to get command name for.
438          * @return Command name for the message type.
439          */
440         static const char* CommandStrFromMsgType(MessageType mt)
441         {
442                 return ((mt == MSG_PRIVMSG) ? "PRIVMSG" : "NOTICE");
443         }
444
445         /** Constructor, user source, string target, copies text.
446          * @param source Source user.
447          * @param target Privmsg target string.
448          * @param text Privmsg text, will be copied.
449          * @param mt Message type.
450          */
451         Privmsg(User* source, const std::string& target, const std::string& text, MessageType mt = MSG_PRIVMSG)
452                 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
453         {
454                 PushParam(target);
455                 PushParam(text);
456         }
457
458         /** Constructor, user source, user target, copies text.
459          * @param source Source user.
460          * @param targetchan Target channel.
461          * @param text Privmsg text, will be copied.
462          * @param mt Message type.
463          * @param status Prefix character for status messages. If non-zero the message is a status message. Optional, defaults to 0.
464          */
465         Privmsg(User* source, const Channel* targetchan, const std::string& text, MessageType mt = MSG_PRIVMSG, char status = 0)
466                 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
467         {
468                 PushTargetChan(status, targetchan);
469                 PushParam(text);
470         }
471
472         /** Constructor, user source, user target, copies text.
473          * @param source Source user.
474          * @param targetuser Target user.
475          * @param text Privmsg text, will be copied.
476          * @param mt Message type.
477          */
478         Privmsg(User* source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG)
479                 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
480         {
481                 PushTargetUser(targetuser);
482                 PushParam(text);
483         }
484
485         /** Constructor, string source, string target, copies text.
486          * @param source Source user.
487          * @param target Target string.
488          * @param text Privmsg text, will be copied.
489          * @param mt Message type.
490          */
491         Privmsg(const std::string& source, const std::string& target, const std::string& text, MessageType mt = MSG_PRIVMSG)
492                 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
493         {
494                 PushParam(target);
495                 PushParam(text);
496         }
497
498         /** Constructor, string source, channel target, copies text.
499          * @param source Source string.
500          * @param targetchan Target channel.
501          * @param text Privmsg text, will be copied.
502          * @param status Prefix character for status messages. If non-zero the message is a status message. Optional, defaults to 0.
503          * @param mt Message type.
504          */
505         Privmsg(const std::string& source, const Channel* targetchan, const std::string& text, MessageType mt = MSG_PRIVMSG, char status = 0)
506                 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
507         {
508                 PushTargetChan(status, targetchan);
509                 PushParam(text);
510         }
511
512         /** Constructor, string source, user target, copies text.
513          * @param source Source string.
514          * @param targetuser Target user.
515          * @param text Privmsg text, will be copied.
516          * @param mt Message type.
517          */
518         Privmsg(const std::string& source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG)
519                 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
520         {
521                 PushTargetUser(targetuser);
522                 PushParam(text);
523         }
524
525         /** Constructor, user source, string target, copies text.
526          * @param source Source user.
527          * @param target Target string.
528          * @param text Privmsg text, will not be copied.
529          * @param mt Message type.
530          */
531         Privmsg(NoCopy, User* source, const std::string& target, const std::string& text, MessageType mt = MSG_PRIVMSG)
532                 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
533         {
534                 PushParam(target);
535                 PushParamRef(text);
536         }
537
538         /** Constructor, user source, channel target, does not copy text.
539          * @param source Source user.
540          * @param targetchan Target channel.
541          * @param text Privmsg text, will not be copied.
542          * @param status Prefix character for status messages. If non-zero the message is a status message. Optional, defaults to 0.
543          * @param mt Message type.
544          */
545         Privmsg(NoCopy, User* source, const Channel* targetchan, const std::string& text, MessageType mt = MSG_PRIVMSG, char status = 0)
546                 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
547         {
548                 PushTargetChan(status, targetchan);
549                 PushParamRef(text);
550         }
551
552         /** Constructor, user source, user target, does not copy text.
553          * @param source Source user.
554          * @param targetuser Target user.
555          * @param text Privmsg text, will not be copied.
556          * @param mt Message type.
557          */
558         Privmsg(NoCopy, User* source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG)
559                 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
560         {
561                 PushTargetUser(targetuser);
562                 PushParamRef(text);
563         }
564
565         /** Constructor, string source, string target, does not copy text.
566          * @param source Source string.
567          * @param target Target string.
568          * @param text Privmsg text, will not be copied.
569          * @param mt Message type.
570          */
571         Privmsg(NoCopy, const std::string& source, const std::string& target, const std::string& text, MessageType mt = MSG_PRIVMSG)
572                 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
573         {
574                 PushParam(target);
575                 PushParamRef(text);
576         }
577
578         /** Constructor, string source, channel target, does not copy text.
579          * @param source Source string.
580          * @param targetchan Target channel.
581          * @param text Privmsg text, will not be copied.
582          * @param status Prefix character for status messages. If non-zero the message is a status message. Optional, defaults to 0.
583          * @param mt Message type.
584          */
585         Privmsg(NoCopy, const std::string& source, const Channel* targetchan, const std::string& text, MessageType mt = MSG_PRIVMSG, char status = 0)
586                 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
587         {
588                 PushTargetChan(status, targetchan);
589                 PushParamRef(text);
590         }
591
592         /** Constructor, string source, user target, does not copy text.
593          * @param source Source string.
594          * @param targetuser Target user.
595          * @param text Privmsg text, will not be copied.
596          * @param mt Message type.
597          */
598         Privmsg(NoCopy, const std::string& source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG)
599                 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
600         {
601                 PushTargetUser(targetuser);
602                 PushParamRef(text);
603         }
604 };
605
606 /** INVITE message.
607  * Sent when a user is invited to join a channel.
608  */
609 struct ClientProtocol::Messages::Invite : public ClientProtocol::Message
610 {
611         /** Constructor.
612          * @param source User inviting the target user.
613          * @param target User being invited by source.
614          * @param chan Channel the target user is being invited to.
615          */
616         Invite(User* source, User* target, Channel* chan)
617                 : ClientProtocol::Message("INVITE", source)
618         {
619                 PushParamRef(target->nick);
620                 PushParamRef(chan->name);
621         }
622 };
623
624 /** PING message.
625  * Used to check if a connection is still alive.
626  */
627 struct ClientProtocol::Messages::Ping : public ClientProtocol::Message
628 {
629         /** Constructor.
630          * The ping cookie is the name of the local server.
631          */
632         Ping()
633                 : ClientProtocol::Message("PING")
634         {
635                 PushParamRef(ServerInstance->Config->ServerName);
636         }
637
638         /** Constructor.
639          * @param cookie Ping cookie. Must remain valid as long as this object is alive.
640          */
641         Ping(const std::string& cookie)
642                 : ClientProtocol::Message("PING")
643         {
644                 PushParamRef(cookie);
645         }
646 };
647
648 /** PONG message.
649  * Sent as a reply to PING.
650  */
651 struct ClientProtocol::Messages::Pong : public ClientProtocol::Message
652 {
653         /** Constructor.
654          * @param cookie Ping cookie. Must remain valid as long as this object is alive.
655          */
656         Pong(const std::string& cookie)
657                 : ClientProtocol::Message("PONG", ServerInstance->Config->ServerName)
658         {
659                 PushParamRef(ServerInstance->Config->ServerName);
660                 PushParamRef(cookie);
661         }
662 };
663
664 /** ERROR message.
665  * Sent to clients upon disconnection.
666  */
667 struct ClientProtocol::Messages::Error : public ClientProtocol::Message
668 {
669         /** Constructor.
670          * @param text Error text.
671          */
672         Error(const std::string& text)
673                         : ClientProtocol::Message("ERROR")
674         {
675                 PushParam(text);
676         }
677 };