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