2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2018, 2020 Sadie Powell <sadie@witchery.services>
5 * Copyright (C) 2018 Attila Molnar <attilamolnar@hush.com>
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.
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
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/>.
23 namespace ClientProtocol
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.
48 class ClientProtocol::Messages::Numeric : public ClientProtocol::Message
52 void InitCommand(unsigned int number)
54 snprintf(numericstr, sizeof(numericstr), "%03u", number);
55 SetCommand(numericstr);
58 void InitFromNumeric(const ::Numeric::Numeric& numeric)
60 InitCommand(numeric.GetNumeric());
61 for (std::vector<std::string>::const_iterator i = numeric.GetParams().begin(); i != numeric.GetParams().end(); ++i)
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.
70 Numeric(const ::Numeric::Numeric& num, User* user)
71 : ClientProtocol::Message(NULL, (num.GetServer() ? num.GetServer()->GetName() : ServerInstance->Config->ServerName))
73 if (user->registered & REG_NICK)
74 PushParamRef(user->nick);
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.
84 Numeric(const ::Numeric::Numeric& num, const std::string& target)
85 : ClientProtocol::Message(NULL, (num.GetServer() ? num.GetServer()->GetName() : ServerInstance->Config->ServerName))
91 /** Constructor. Only the numeric number has to be specified.
92 * @param num Numeric number.
94 Numeric(unsigned int num)
95 : ClientProtocol::Message(NULL, ServerInstance->Config->ServerName)
103 * Sent when a user joins a channel.
105 class ClientProtocol::Messages::Join : public ClientProtocol::Message
110 /** Constructor. Does not populate parameters, call SetParams() before sending the message.
113 : ClientProtocol::Message("JOIN")
119 * @param Memb Membership of the joining user.
121 Join(Membership* Memb)
122 : ClientProtocol::Message("JOIN", Memb->user)
128 * @param Memb Membership of the joining user.
129 * @param sourcestrref Message source string, must remain valid as long as this object is alive.
131 Join(Membership* Memb, const std::string& sourcestrref)
132 : ClientProtocol::Message("JOIN", sourcestrref, Memb->user)
137 /** Populate parameters from a Membership
138 * @param Memb Membership of the joining user.
140 void SetParams(Membership* Memb)
143 PushParamRef(memb->chan->name);
146 /** Get the Membership of the joining user.
147 * @return Membership of the joining user.
149 Membership* GetMember() const { return memb; }
153 * Sent when a user parts a channel.
155 struct ClientProtocol::Messages::Part : public ClientProtocol::Message
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.
161 Part(Membership* memb, const std::string& reason)
162 : ClientProtocol::Message("PART", memb->user)
164 PushParamRef(memb->chan->name);
166 PushParamRef(reason);
171 * Sent when a user is kicked from a channel.
173 struct ClientProtocol::Messages::Kick : public ClientProtocol::Message
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.
180 Kick(User* source, Membership* memb, const std::string& reason)
181 : ClientProtocol::Message("KICK", source)
183 PushParamRef(memb->chan->name);
184 PushParamRef(memb->user->nick);
185 PushParamRef(reason);
190 * Sent when a user quits.
192 struct ClientProtocol::Messages::Quit : public ClientProtocol::Message
195 * @param source User quitting.
196 * @param reason Quit reason, may be empty. Must remain valid as long as this object is alive.
198 Quit(User* source, const std::string& reason)
199 : ClientProtocol::Message("QUIT", source)
202 PushParamRef(reason);
207 * Sent when a user changes their nickname.
209 struct ClientProtocol::Messages::Nick : public ClientProtocol::Message
212 * @param source User changing nicks.
213 * @param newnick New nickname. Must remain valid as long as this object is alive.
215 Nick(User* source, const std::string& newnick)
216 : ClientProtocol::Message("NICK", source)
218 PushParamRef(newnick);
223 * Sent when modes are changed on a user or channel.
225 class ClientProtocol::Messages::Mode : public ClientProtocol::Message
229 Modes::ChangeList::List::const_iterator beginit;
230 Modes::ChangeList::List::const_iterator lastit;
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.
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)
241 std::string::size_type paramlength = 0;
242 char output_pm = '\0'; // current output state, '+' or '-'
244 Modes::ChangeList::List::const_iterator i;
245 for (i = beginit; i != list.end(); ++i)
247 const Modes::Change& item = *i;
249 const char needed_pm = (item.adding ? '+' : '-');
250 if (needed_pm != output_pm)
252 output_pm = needed_pm;
253 ret.push_back(output_pm);
256 if (!item.param.empty())
257 paramlength += item.param.length() + 1;
258 if (ret.length() + 1 + paramlength > maxlinelen)
260 // Mode sequence is getting too long
261 const char c = *ret.rbegin();
262 if ((c == '+') || (c == '-'))
263 ret.erase(ret.size()-1);
267 ret.push_back(item.mh->GetModeChar());
274 /** Push mode parameters for modes that have one, starting at beginit to lastit (not including lastit).
276 void PushModeParams()
278 for (Modes::ChangeList::List::const_iterator i = beginit; i != lastit; ++i)
280 const Modes::Change& item = *i;
281 if (!item.param.empty())
282 PushParamRef(item.param);
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.
291 static std::string ToModeLetters(const Modes::ChangeList& changelist)
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);
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'.
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)
311 PushParamRef(GetStrTarget());
312 PushParam(ToModeLetters(changelist.getlist(), 450, beginit, lastit));
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.
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())
328 PushParamRef(GetStrTarget());
329 PushParam(ToModeLetters(changelist.getlist(), 450, beginit, lastit));
333 /** Constructor. Does not populate parameters, call SetParams() before sending the message.
334 * The message source is set to the local server.
337 : ClientProtocol::Message("MODE", ServerInstance->FakeClient)
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.
348 void SetParams(Channel* Chantarget, User* Usertarget, const Modes::ChangeList& changelist)
352 chantarget = Chantarget;
353 usertarget = Usertarget;
354 beginit = changelist.getlist().begin();
356 PushParamRef(GetStrTarget());
357 PushParam(ToModeLetters(changelist.getlist(), 450, beginit, lastit));
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.
364 Modes::ChangeList::List::const_iterator GetBeginIterator() const { return beginit; }
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.
369 Modes::ChangeList::List::const_iterator GetEndIterator() const { return lastit; }
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.
376 const std::string& GetStrTarget() const { return (chantarget ? chantarget->name : usertarget->nick); }
379 * @return User target or NULL if the mode change targets a channel.
381 User* GetUserTarget() const { return usertarget; }
383 /** Get channel target.
384 * @return Channel target or NULL if the mode change targets a user.
386 Channel* GetChanTarget() const { return chantarget; }
391 struct ClientProtocol::Messages::Topic : public ClientProtocol::Message
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.
398 Topic(User* source, const Channel* chan, const std::string& newtopic)
399 : ClientProtocol::Message("TOPIC", source)
401 PushParamRef(chan->name);
402 PushParamRef(newtopic);
406 /** PRIVMSG and NOTICE message.
408 class ClientProtocol::Messages::Privmsg : public ClientProtocol::Message
410 void PushTargetChan(char status, const Channel* targetchan)
414 std::string rawtarget(1, status);
415 rawtarget.append(targetchan->name);
416 PushParam(rawtarget);
420 PushParamRef(targetchan->name);
424 void PushTargetUser(const User* targetuser)
426 if (targetuser->registered & REG_NICK)
427 PushParamRef(targetuser->nick);
433 /** Used to differentiate constructors that copy the text from constructors that do not.
435 enum NoCopy { nocopy };
437 /** Get command name from MessageType.
438 * @param mt Message type to get command name for.
439 * @return Command name for the message type.
441 static const char* CommandStrFromMsgType(MessageType mt)
443 return ((mt == MSG_PRIVMSG) ? "PRIVMSG" : "NOTICE");
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.
452 Privmsg(User* source, const std::string& target, const std::string& text, MessageType mt = MSG_PRIVMSG)
453 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
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.
466 Privmsg(User* source, const Channel* targetchan, const std::string& text, MessageType mt = MSG_PRIVMSG, char status = 0)
467 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
469 PushTargetChan(status, targetchan);
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.
479 Privmsg(User* source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG)
480 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
482 PushTargetUser(targetuser);
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.
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)
498 std::string rawtarget(1, status);
499 rawtarget.append(target);
500 PushParam(rawtarget);
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.
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)
519 PushTargetChan(status, targetchan);
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.
529 Privmsg(const std::string& source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG)
530 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
532 PushTargetUser(targetuser);
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.
542 Privmsg(NoCopy, User* source, const std::string& target, const std::string& text, MessageType mt = MSG_PRIVMSG)
543 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
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.
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)
559 PushTargetChan(status, targetchan);
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.
569 Privmsg(NoCopy, User* source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG)
570 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
572 PushTargetUser(targetuser);
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.
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)
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.
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)
599 PushTargetChan(status, targetchan);
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.
609 Privmsg(NoCopy, const std::string& source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG)
610 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
612 PushTargetUser(targetuser);
618 * Sent when a user is invited to join a channel.
620 struct ClientProtocol::Messages::Invite : public ClientProtocol::Message
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.
627 Invite(User* source, User* target, Channel* chan)
628 : ClientProtocol::Message("INVITE", source)
630 PushParamRef(target->nick);
631 PushParamRef(chan->name);
636 * Used to check if a connection is still alive.
638 struct ClientProtocol::Messages::Ping : public ClientProtocol::Message
641 * The ping cookie is the name of the local server.
644 : ClientProtocol::Message("PING")
646 PushParamRef(ServerInstance->Config->ServerName);
650 * @param cookie Ping cookie. Must remain valid as long as this object is alive.
652 Ping(const std::string& cookie)
653 : ClientProtocol::Message("PING")
655 PushParamRef(cookie);
660 * Sent as a reply to PING.
662 struct ClientProtocol::Messages::Pong : public ClientProtocol::Message
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.
668 Pong(const std::string& cookie, const std::string& server = "")
669 : ClientProtocol::Message("PONG", ServerInstance->Config->ServerName)
671 PushParamRef(ServerInstance->Config->ServerName);
673 PushParamRef(server);
674 PushParamRef(cookie);
679 * Sent to clients upon disconnection.
681 struct ClientProtocol::Messages::Error : public ClientProtocol::Message
684 * @param text Error text.
686 Error(const std::string& text)
687 : ClientProtocol::Message("ERROR")