2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com>
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.
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
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/>.
22 namespace ClientProtocol
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.
47 class ClientProtocol::Messages::Numeric : public ClientProtocol::Message
51 void InitCommand(unsigned int number)
53 snprintf(numericstr, sizeof(numericstr), "%03u", number);
54 SetCommand(numericstr);
57 void InitFromNumeric(const ::Numeric::Numeric& numeric)
59 InitCommand(numeric.GetNumeric());
60 for (std::vector<std::string>::const_iterator i = numeric.GetParams().begin(); i != numeric.GetParams().end(); ++i)
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.
69 Numeric(const ::Numeric::Numeric& num, User* user)
70 : ClientProtocol::Message(NULL, (num.GetServer() ? num.GetServer()->GetName() : ServerInstance->Config->ServerName))
72 if (user->registered & REG_NICK)
73 PushParamRef(user->nick);
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.
83 Numeric(const ::Numeric::Numeric& num, const std::string& target)
84 : ClientProtocol::Message(NULL, (num.GetServer() ? num.GetServer()->GetName() : ServerInstance->Config->ServerName))
90 /** Constructor. Only the numeric number has to be specified.
91 * @param num Numeric number.
93 Numeric(unsigned int num)
94 : ClientProtocol::Message(NULL, ServerInstance->Config->ServerName)
102 * Sent when a user joins a channel.
104 class ClientProtocol::Messages::Join : public ClientProtocol::Message
109 /** Constructor. Does not populate parameters, call SetParams() before sending the message.
112 : ClientProtocol::Message("JOIN")
118 * @param Memb Membership of the joining user.
120 Join(Membership* Memb)
121 : ClientProtocol::Message("JOIN", Memb->user)
127 * @param Memb Membership of the joining user.
128 * @param sourcestrref Message source string, must remain valid as long as this object is alive.
130 Join(Membership* Memb, const std::string& sourcestrref)
131 : ClientProtocol::Message("JOIN", sourcestrref, Memb->user)
136 /** Populate parameters from a Membership
137 * @param Memb Membership of the joining user.
139 void SetParams(Membership* Memb)
142 PushParamRef(memb->chan->name);
145 /** Get the Membership of the joining user.
146 * @return Membership of the joining user.
148 Membership* GetMember() const { return memb; }
152 * Sent when a user parts a channel.
154 struct ClientProtocol::Messages::Part : public ClientProtocol::Message
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.
160 Part(Membership* memb, const std::string& reason)
161 : ClientProtocol::Message("PART", memb->user)
163 PushParamRef(memb->chan->name);
165 PushParamRef(reason);
170 * Sent when a user is kicked from a channel.
172 struct ClientProtocol::Messages::Kick : public ClientProtocol::Message
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.
179 Kick(User* source, Membership* memb, const std::string& reason)
180 : ClientProtocol::Message("KICK", source)
182 PushParamRef(memb->chan->name);
183 PushParamRef(memb->user->nick);
184 PushParamRef(reason);
189 * Sent when a user quits.
191 struct ClientProtocol::Messages::Quit : public ClientProtocol::Message
194 * @param source User quitting.
195 * @param reason Quit reason, may be empty. Must remain valid as long as this object is alive.
197 Quit(User* source, const std::string& reason)
198 : ClientProtocol::Message("QUIT", source)
201 PushParamRef(reason);
206 * Sent when a user changes their nickname.
208 struct ClientProtocol::Messages::Nick : public ClientProtocol::Message
211 * @param source User changing nicks.
212 * @param newnick New nickname. Must remain valid as long as this object is alive.
214 Nick(User* source, const std::string& newnick)
215 : ClientProtocol::Message("NICK", source)
217 PushParamRef(newnick);
222 * Sent when modes are changed on a user or channel.
224 class ClientProtocol::Messages::Mode : public ClientProtocol::Message
228 Modes::ChangeList::List::const_iterator beginit;
229 Modes::ChangeList::List::const_iterator lastit;
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.
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)
240 std::string::size_type paramlength = 0;
241 char output_pm = '\0'; // current output state, '+' or '-'
243 Modes::ChangeList::List::const_iterator i;
244 for (i = beginit; i != list.end(); ++i)
246 const Modes::Change& item = *i;
248 const char needed_pm = (item.adding ? '+' : '-');
249 if (needed_pm != output_pm)
251 output_pm = needed_pm;
252 ret.push_back(output_pm);
255 if (!item.param.empty())
256 paramlength += item.param.length() + 1;
257 if (ret.length() + 1 + paramlength > maxlinelen)
259 // Mode sequence is getting too long
260 const char c = *ret.rbegin();
261 if ((c == '+') || (c == '-'))
262 ret.erase(ret.size()-1);
266 ret.push_back(item.mh->GetModeChar());
273 /** Push mode parameters for modes that have one, starting at beginit to lastit (not including lastit).
275 void PushModeParams()
277 for (Modes::ChangeList::List::const_iterator i = beginit; i != lastit; ++i)
279 const Modes::Change& item = *i;
280 if (!item.param.empty())
281 PushParamRef(item.param);
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.
290 static std::string ToModeLetters(const Modes::ChangeList& changelist)
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);
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'.
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)
310 PushParamRef(GetStrTarget());
311 PushParam(ToModeLetters(changelist.getlist(), 450, beginit, lastit));
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.
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())
327 PushParamRef(GetStrTarget());
328 PushParam(ToModeLetters(changelist.getlist(), 450, beginit, lastit));
332 /** Constructor. Does not populate parameters, call SetParams() before sending the message.
333 * The message source is set to the local server.
336 : ClientProtocol::Message("MODE", ServerInstance->FakeClient)
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.
347 void SetParams(Channel* Chantarget, User* Usertarget, const Modes::ChangeList& changelist)
351 chantarget = Chantarget;
352 usertarget = Usertarget;
353 beginit = changelist.getlist().begin();
355 PushParamRef(GetStrTarget());
356 PushParam(ToModeLetters(changelist.getlist(), 450, beginit, lastit));
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.
363 Modes::ChangeList::List::const_iterator GetBeginIterator() const { return beginit; }
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.
368 Modes::ChangeList::List::const_iterator GetEndIterator() const { return lastit; }
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.
375 const std::string& GetStrTarget() const { return (chantarget ? chantarget->name : usertarget->nick); }
378 * @return User target or NULL if the mode change targets a channel.
380 User* GetUserTarget() const { return usertarget; }
382 /** Get channel target.
383 * @return Channel target or NULL if the mode change targets a user.
385 Channel* GetChanTarget() const { return chantarget; }
390 struct ClientProtocol::Messages::Topic : public ClientProtocol::Message
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.
397 Topic(User* source, const Channel* chan, const std::string& newtopic)
398 : ClientProtocol::Message("TOPIC", source)
400 PushParamRef(chan->name);
401 PushParamRef(newtopic);
405 /** PRIVMSG and NOTICE message.
407 class ClientProtocol::Messages::Privmsg : public ClientProtocol::Message
409 void PushTargetChan(char status, const Channel* targetchan)
413 std::string rawtarget(1, status);
414 rawtarget.append(targetchan->name);
415 PushParam(rawtarget);
419 PushParamRef(targetchan->name);
423 void PushTargetUser(const User* targetuser)
425 if (targetuser->registered & REG_NICK)
426 PushParamRef(targetuser->nick);
432 /** Used to differentiate constructors that copy the text from constructors that do not.
434 enum NoCopy { nocopy };
436 /** Get command name from MessageType.
437 * @param mt Message type to get command name for.
438 * @return Command name for the message type.
440 static const char* CommandStrFromMsgType(MessageType mt)
442 return ((mt == MSG_PRIVMSG) ? "PRIVMSG" : "NOTICE");
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.
451 Privmsg(User* source, const std::string& target, const std::string& text, MessageType mt = MSG_PRIVMSG)
452 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
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.
465 Privmsg(User* source, const Channel* targetchan, const std::string& text, MessageType mt = MSG_PRIVMSG, char status = 0)
466 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
468 PushTargetChan(status, targetchan);
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.
478 Privmsg(User* source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG)
479 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
481 PushTargetUser(targetuser);
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.
491 Privmsg(const std::string& source, const std::string& target, const std::string& text, MessageType mt = MSG_PRIVMSG)
492 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
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.
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)
508 PushTargetChan(status, targetchan);
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.
518 Privmsg(const std::string& source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG)
519 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
521 PushTargetUser(targetuser);
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.
531 Privmsg(NoCopy, User* source, const std::string& target, const std::string& text, MessageType mt = MSG_PRIVMSG)
532 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
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.
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)
548 PushTargetChan(status, targetchan);
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.
558 Privmsg(NoCopy, User* source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG)
559 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
561 PushTargetUser(targetuser);
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.
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)
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.
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)
588 PushTargetChan(status, targetchan);
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.
598 Privmsg(NoCopy, const std::string& source, const User* targetuser, const std::string& text, MessageType mt = MSG_PRIVMSG)
599 : ClientProtocol::Message(CommandStrFromMsgType(mt), source)
601 PushTargetUser(targetuser);
607 * Sent when a user is invited to join a channel.
609 struct ClientProtocol::Messages::Invite : public ClientProtocol::Message
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.
616 Invite(User* source, User* target, Channel* chan)
617 : ClientProtocol::Message("INVITE", source)
619 PushParamRef(target->nick);
620 PushParamRef(chan->name);
625 * Used to check if a connection is still alive.
627 struct ClientProtocol::Messages::Ping : public ClientProtocol::Message
630 * The ping cookie is the name of the local server.
633 : ClientProtocol::Message("PING")
635 PushParamRef(ServerInstance->Config->ServerName);
639 * @param cookie Ping cookie. Must remain valid as long as this object is alive.
641 Ping(const std::string& cookie)
642 : ClientProtocol::Message("PING")
644 PushParamRef(cookie);
649 * Sent as a reply to PING.
651 struct ClientProtocol::Messages::Pong : public ClientProtocol::Message
654 * @param cookie Ping cookie. Must remain valid as long as this object is alive.
656 Pong(const std::string& cookie)
657 : ClientProtocol::Message("PONG", ServerInstance->Config->ServerName)
659 PushParamRef(ServerInstance->Config->ServerName);
660 PushParamRef(cookie);
665 * Sent to clients upon disconnection.
667 struct ClientProtocol::Messages::Error : public ClientProtocol::Message
670 * @param text Error text.
672 Error(const std::string& text)
673 : ClientProtocol::Message("ERROR")