1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
|
/*
* InspIRCd -- Internet Relay Chat Daemon
*
* Copyright (C) 2018-2023 Sadie Powell <sadie@witchery.services>
* Copyright (C) 2018 Attila Molnar <attilamolnar@hush.com>
*
* This file is part of InspIRCd. InspIRCd is free software: you can
* redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "event.h"
namespace ClientProtocol
{
class EventHook;
class MessageSource;
struct RFCEvents;
struct ParseOutput;
class TagSelection;
}
/** Contains a message parsed from wire format.
* Used by Serializer::Parse().
*/
struct CoreExport ClientProtocol::ParseOutput final
{
/** Command name, must not be empty.
*/
std::string cmd;
/** Parameter list, may be empty.
*/
ClientProtocol::ParamList params;
/** Message tags, may be empty.
*/
ClientProtocol::TagMap tags;
};
/** A selection of zero or more tags in a TagMap.
*/
class CoreExport ClientProtocol::TagSelection final
{
std::bitset<64> selection;
public:
/** Check if a tag is selected.
* @param tags TagMap the tag is in. The TagMap must contain the same tags as it had when the tag
* was selected with Select(), otherwise the result is not meaningful.
* @param it Iterator to the tag to check.
* @return True if the tag is selected, false otherwise.
*/
bool IsSelected(const TagMap& tags, TagMap::const_iterator it) const
{
const size_t index = std::distance(tags.begin(), it);
return ((index < selection.size()) && (selection[index]));
}
/** Select a tag.
* @param tags TagMap the tag is in. This parameter must be the same every time the method is called.
* The TagMap must not be altered otherwise the results of IsSelected() is not meaningful.
* @param it Iterator to the tag to mark as selected.
*/
void Select(const TagMap& tags, TagMap::const_iterator it)
{
const size_t index = std::distance(tags.begin(), it);
if (index < selection.size())
selection[index] = true;
}
/** Check if a TagSelection is equivalent to this object.
* @param other Other TagSelection object to compare this with.
* @return True if the objects are equivalent, false if they aren't.
*/
bool operator==(const TagSelection& other) const
{
return (this->selection == other.selection);
}
};
class CoreExport ClientProtocol::MessageSource
{
protected:
User* sourceuser;
const std::string* sourcestr;
bool sourceowned:1;
public:
/** Constructor, sets the source to be the full host of a user or sets it to be nothing.
* The actual source string when serializing will be obtained from User::GetFullHost() if the user is non-NULL.
* @param Sourceuser User to set as source of the message. If NULL, the message won't have a source when serialized.
* Optional, defaults to NULL.
*/
MessageSource(User* Sourceuser = nullptr)
: sourceowned(false)
{
SetSourceUser(Sourceuser);
}
~MessageSource()
{
if (sourceowned && sourcestr)
delete sourcestr;
}
/** Constructor, sets the source to the supplied string and optionally sets the source user.
* @param Sourcestr String to use as message source for serialization purposes. Must remain valid
* as long as this object is alive.
* @param Sourceuser User to set as source. Optional, defaults to NULL. It will not be used for serialization but
* if provided it may be used internally, for example to create message tags.
* Useful when the source string is synthesized but it is still related to a User.
*/
MessageSource(const std::string& Sourcestr, User* Sourceuser = nullptr)
: sourceowned(false)
{
SetSource(Sourcestr, Sourceuser);
}
/** Get the source of this message as a string.
* @return Pointer to the message source string or NULL if there is no source.
*/
const std::string* GetSource() const
{
// Return string if there's one explicitly set
if (sourcestr)
return sourcestr;
if (sourceuser)
return &sourceuser->GetMask();
return nullptr;
}
/** Get the source User.
* This shouldn't be used for serialization, use GetSource() for that.
* @return User pointer if the message has a source user, NULL otherwise.
*/
User* GetSourceUser() const { return sourceuser; }
/** Set the source of this message to a User.
* See the one parameter constructor for a more detailed description.
* @param Sourceuser User to set as source.
*/
void SetSourceUser(User* Sourceuser)
{
sourceuser = Sourceuser;
sourcestr = nullptr;
}
/** Set the source string and optionally source user.
* See the two parameter constructor for a more detailed description.
* @param Sourcestr String source, to be used for serialization purposes. Must remain valid as long
* as this object is alive.
* @param Sourceuser Source user to set, optional.
*/
void SetSource(const std::string& Sourcestr, User* Sourceuser = nullptr)
{
sourcestr = &Sourcestr;
sourceuser = Sourceuser;
}
/** Copy the source from a MessageSource object.
* @param other MessageSource object to copy from.
*/
void SetSource(const MessageSource& other)
{
sourcestr = other.sourcestr;
sourceuser = other.sourceuser;
}
};
/** Outgoing client protocol message.
* Represents a high level client protocol message which is turned into raw or wire format
* by a Serializer. Messages can be serialized into different format by different serializers.
*
* Messages are created on demand and are disposed of after they have been sent.
*
* All messages have a command name, a list of parameters and a map of tags, the last two can be empty.
* They also always have a source, see class MessageSource.
*/
class CoreExport ClientProtocol::Message
: public ClientProtocol::MessageSource
{
public:
/** Contains information required to identify a specific version of a serialized message.
*/
struct SerializedInfo final
{
const Serializer* serializer;
TagSelection tagwl;
/** Constructor.
* @param Ser Serializer used to serialize the message.
* @param Tagwl Tag whitelist used to serialize the message.
*/
SerializedInfo(const Serializer* Ser, const TagSelection& Tagwl)
: serializer(Ser)
, tagwl(Tagwl)
{
}
/** Check if a SerializedInfo object is equivalent to this object.
* @param other Other SerializedInfo object.
* @return True if other is equivalent to this object, false otherwise.
*/
bool operator==(const SerializedInfo& other) const
{
return ((serializer == other.serializer) && (tagwl == other.tagwl));
}
};
class Param final
{
const std::string* ptr;
insp::aligned_storage<std::string> str;
bool owned;
void InitFrom(const Param& other)
{
owned = other.owned;
if (owned)
new(str) std::string(*other.str);
else
ptr = other.ptr;
}
public:
operator const std::string&() const { return (owned ? *str : *ptr); }
Param()
: ptr(nullptr)
, owned(false)
{
}
Param(const std::string& s)
: ptr(&s)
, owned(false)
{
}
Param(int, const char* s)
: ptr(nullptr)
, owned(true)
{
new(str) std::string(s);
}
Param(int, const std::string& s)
: ptr(nullptr)
, owned(true)
{
new(str) std::string(s);
}
Param(const Param& other)
{
InitFrom(other);
}
~Param()
{
using std::string;
if (owned)
str->~string();
}
Param& operator=(const Param& other)
{
if (&other == this)
return *this;
using std::string;
if (owned)
str->~string();
InitFrom(other);
return *this;
}
bool IsOwned() const { return owned; }
};
typedef std::vector<Param> ParamList;
/** Escapes a value to the tag format.
* @param value The value to escape.
*/
static std::string EscapeTag(const std::string& value);
/** Unescapes a value from the tag format.
* @param value The value to unescape.
*/
static std::string UnescapeTag(const std::string& value);
private:
typedef std::vector<std::pair<SerializedInfo, SerializedMessage>> SerializedList;
ParamList params;
TagMap tags;
std::string command;
bool msginit_done = false;
mutable SerializedList serlist;
bool sideeffect = false;
protected:
/** Set command string.
* @param cmd Command string to set.
*/
void SetCommand(const char* cmd)
{
command.clear();
if (cmd)
command = cmd;
}
public:
/** Constructor.
* @param cmd Command name, e.g. "JOIN", "NICK". May be NULL. If NULL, the command must be set
* with SetCommand() before the message is serialized.
* @param Sourceuser See the one parameter constructor of MessageSource for description.
*/
Message(const char* cmd, User* Sourceuser = nullptr)
: ClientProtocol::MessageSource(Sourceuser)
, command(cmd ? cmd : std::string())
{
params.reserve(8);
serlist.reserve(8);
}
/** Constructor.
* @param cmd Command name, e.g. "JOIN", "NICK". May be NULL. If NULL, the command must be set
* with SetCommand() before the message is serialized.
* @param Sourcestr See the two parameter constructor of MessageSource for description.
* Must remain valid as long as this object is alive.
* @param Sourceuser See the two parameter constructor of MessageSource for description.
*/
Message(const char* cmd, const std::string& Sourcestr, User* Sourceuser = nullptr)
: ClientProtocol::MessageSource(Sourcestr, Sourceuser)
, command(cmd ? cmd : std::string())
{
params.reserve(8);
serlist.reserve(8);
}
/** Get the parameters of this message.
* @return List of parameters.
*/
const ParamList& GetParams() const { return params; }
/** Get a map of tags attached to this message.
* The map contains the tag providers that attached the tag to the message.
* @return Map of tags.
*/
const TagMap& GetTags() const { return tags; }
/** Get the command string.
* @return Command string, e.g. "NICK", "001".
*/
const char* GetCommand() const { return command.c_str(); }
/** Add a parameter to the parameter list.
* @param str String to add, will be copied.
*/
void PushParam(const char* str) { params.emplace_back(0, str); }
/** Add a parameter to the parameter list.
* @param str String to add, will be copied.
*/
void PushParam(const std::string& str) { params.emplace_back(0, str); }
/** Converts the given arguments to a string and adds them to the parameter list.
* @param args One or more parameters to add to the parameter list.
*/
template <typename... Args>
void PushParam(Args&&... args)
{
(PushParam(ConvToStr(args)), ...);
}
/** Add a parameter to the parameter list.
* @param str String to add.
* The string will NOT be copied, it must remain alive until ClearParams() is called or until the object is destroyed.
*/
void PushParamRef(const std::string& str) { params.push_back(str); }
/** Add a placeholder parameter to the parameter list.
* Placeholder parameters must be filled in later with actual parameters using ReplaceParam() or ReplaceParamRef().
*/
void PushParamPlaceholder() { params.emplace_back(); }
/** Replace a parameter or a placeholder that is already in the parameter list.
* @param index Index of the parameter to replace. Must be less than GetParams().size().
* @param str String to replace the parameter or placeholder with, will be copied.
*/
void ReplaceParam(size_t index, const char* str) { params[index] = Param(0, str); }
/** Replace a parameter or a placeholder that is already in the parameter list.
* @param index Index of the parameter to replace. Must be less than GetParams().size().
* @param str String to replace the parameter or placeholder with, will be copied.
*/
void ReplaceParam(size_t index, const std::string& str) { params[index] = Param(0, str); }
/** Replace a parameter or a placeholder that is already in the parameter list.
* @param index Index of the parameter to replace. Must be less than GetParams().size().
* @param str String to replace the parameter or placeholder with.
* The string will NOT be copied, it must remain alive until ClearParams() is called or until the object is destroyed.
*/
void ReplaceParamRef(size_t index, const std::string& str) { params[index] = Param(str); }
/** Add a tag.
* @param tagname Raw name of the tag to use in the protocol.
* @param tagprov Provider of the tag.
* @param val Tag value. If empty no value will be sent with the tag.
* @param tagdata Tag provider specific data, will be passed to MessageTagProvider::ShouldSendTag(). Optional, defaults to NULL.
*/
void AddTag(const std::string& tagname, MessageTagProvider* tagprov, const std::string& val, void* tagdata = nullptr)
{
tags.emplace(tagname, MessageTagData(tagprov, val, tagdata));
}
/** Add all tags in a TagMap to the tags in this message. Existing tags will not be overwritten.
* @param newtags New tags to add.
*/
void AddTags(const ClientProtocol::TagMap& newtags)
{
tags.insert(newtags.begin(), newtags.end());
}
/** Get the message in a serialized form.
* @param serializeinfo Information about which exact serialized form of the message is the caller asking for
* (which serializer to use and which tags to include).
* @return Serialized message according to serializeinfo. The returned reference remains valid until the
* next call to this method.
*/
const SerializedMessage& GetSerialized(const SerializedInfo& serializeinfo) const;
/** Clear the parameter list and tags.
*/
void ClearParams()
{
msginit_done = false;
params.clear();
tags.clear();
InvalidateCache();
}
/** Remove all serialized messages.
* If a parameter is changed after the message has been sent at least once, this method must be called before
* serializing the message again to ensure the cache won't contain stale data.
*/
void InvalidateCache()
{
serlist.clear();
}
void CopyAll()
{
size_t idx = 0;
for (const auto& param : params)
{
if (!param.IsOwned())
ReplaceParam(idx, param);
idx++;
}
if (GetSource())
{
sourcestr = new std::string(*GetSource());
sourceowned = true;
}
}
void SetSideEffect(bool Sideeffect) { sideeffect = Sideeffect; }
bool IsSideEffect() const { return sideeffect; }
friend class Serializer;
};
/** Client protocol event class.
* All messages sent to a user must be part of an event. A single event may result in more than one protocol message
* being sent, for example a join event may result in a JOIN and a MODE protocol message sent to members of the channel
* if the joining user has some prefix modes set.
*
* Event hooks attached to a specific event can alter the messages sent for that event.
*/
class CoreExport ClientProtocol::Event
{
EventProvider* event;
Message* initialmsg = nullptr;
const MessageList* initialmsglist = nullptr;
bool eventinit_done = false;
public:
/** Constructor.
* @param protoeventprov Protocol event provider the event is an instance of.
*/
Event(EventProvider& protoeventprov)
: event(&protoeventprov)
{
}
/** Constructor.
* @param protoeventprov Protocol event provider the event is an instance of.
* @param msg Message to include in this event by default.
*/
Event(EventProvider& protoeventprov, ClientProtocol::Message& msg)
: event(&protoeventprov)
, initialmsg(&msg)
{
}
/** Set a single message as the initial message in the event.
* Modules may alter this later.
*/
void SetMessage(Message* msg)
{
initialmsg = msg;
initialmsglist = nullptr;
}
/** Set a list of messages as the initial messages in the event.
* Modules may alter this later.
*/
void SetMessageList(const MessageList& msglist)
{
initialmsg = nullptr;
initialmsglist = &msglist;
}
/** Get a list of messages to send to a user.
* The exact messages sent to a user are determined by the initial message(s) set and hooks.
* @param user User to get the messages for.
* @param messagelist List to fill in with messages to send to the user for the event
*/
void GetMessagesForUser(LocalUser* user, MessageList& messagelist);
};
class CoreExport ClientProtocol::MessageTagEvent
: public Events::ModuleEventProvider
{
public:
MessageTagEvent(Module* mod)
: ModuleEventProvider(mod, "event/messagetag")
{
}
};
/** Base class for message tag providers.
* All message tags belong to a message tag provider. Message tag providers can populate messages
* with tags before the message is sent and they have the job of determining whether a user should
* get a message tag or be allowed to send one.
*/
class CoreExport ClientProtocol::MessageTagProvider
: public Events::ModuleEventListener
{
public:
/** Constructor.
* @param mod Module owning the provider.
* @param eventprio The priority to give this event listener.
*/
MessageTagProvider(Module* mod, unsigned int eventprio = DefaultPriority)
: Events::ModuleEventListener(mod, "event/messagetag", eventprio)
{
}
/** Called when a message is ready to be sent to give the tag provider a chance to add tags to the message.
* To add tags call Message::AddTag(). If the provided tag or tags have been added already elsewhere or if the
* provider doesn't want its tag(s) to be on the message, the implementation doesn't have to do anything special.
* The default implementation does nothing.
* @param msg Message to be populated with tags.
*/
virtual void OnPopulateTags(ClientProtocol::Message& msg)
{
}
/** Called for each tag that the server receives from a client in a message.
* @param user User that sent the tag.
* @param tagname Name of the tag.
* @param tagvalue Value of the tag, empty string if the tag has no value. May be modified.
* @return MOD_RES_ALLOW to accept the tag with the value in 'value', MOD_RES_DENY to reject the tag and act as if it wasn't sent,
* MOD_RES_PASSTHRU to make no decision. If no hooks accept a tag, the tag is rejected.
* The default implementation returns MOD_RES_PASSTHRU.
*/
virtual ModResult OnProcessTag(User* user, const std::string& tagname, std::string& tagvalue)
{
return MOD_RES_PASSTHRU;
}
/** Called whenever a user is about to receive a message that has a tag attached which is provided by this provider
* to determine whether or not the user should get the tag.
* @param user User in question.
* @param tagdata Tag in question.
* @return True if the tag should be sent to the user, false otherwise.
*/
virtual bool ShouldSendTag(LocalUser* user, const MessageTagData& tagdata) = 0;
};
/** Base class for client protocol event hooks.
* A protocol event hook is attached to a single event type. It has the ability to alter or block messages
* sent to users which belong to the event the hook is attached to.
*/
class CoreExport ClientProtocol::EventHook
: public Events::ModuleEventListener
{
public:
static std::string GetEventName(const std::string& name)
{
return "event/protoevent_" + name;
}
/** Constructor.
* @param mod Owner of the hook.
* @param name Name of the event to hook.
* @param priority Priority of the hook. Determines the order in which hooks for the same event get called.
* Optional.
*/
EventHook(Module* mod, const std::string& name, unsigned int priority = Events::ModuleEventListener::DefaultPriority)
: Events::ModuleEventListener(mod, GetEventName(name), priority)
{
}
/** Called exactly once before an event is sent to any user.
* The default implementation doesn't do anything.
* @param ev Event being sent to one or more users.
*/
virtual void OnEventInit(const ClientProtocol::Event& ev)
{
}
/** Called for each user that may receive the event.
* The hook may alter the messages sent to the user and decide whether further hooks should be executed.
* @param user User the message list is being prepared to be sent to.
* @param ev Event associated with the messages.
* @param messagelist List of messages to send to the user. The hook can alter this in any way it sees fit, for example it can replace messages,
* add new messages, etc. The list must not be empty when the method returns.
* @return MOD_RES_PASSTHRU to run hooks after the called hook or if no hooks are after the called hook, send the messages in messagelist to the user.
* MOD_RES_DENY to not send any messages to the user and to not run other hooks,
* MOD_RES_ALLOW to send the messages in messagelist to the user and to not run other hooks.
*/
virtual ModResult OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist) = 0;
};
/** Event provider for client protocol events.
* Protocol event hooks can be attached to the instances of these providers. The core has event
* providers for most common IRC events defined in RFC1459.
*/
class CoreExport ClientProtocol::EventProvider final
: public Events::ModuleEventProvider
{
public:
/** Constructor.
* @param Mod Module that owns the event provider.
* @param eventname Name of the event this provider is for, e.g. "JOIN", "PART", "NUMERIC".
* Should match command name if applicable.
*/
EventProvider(Module* Mod, const std::string& eventname)
: Events::ModuleEventProvider(Mod, ClientProtocol::EventHook::GetEventName(eventname))
{
}
};
/** Commonly used client protocol events.
* Available via InspIRCd::GetRFCEvents().
*/
struct CoreExport ClientProtocol::RFCEvents final
{
EventProvider numeric;
EventProvider join;
EventProvider part;
EventProvider kick;
EventProvider quit;
EventProvider nick;
EventProvider mode;
EventProvider topic;
EventProvider privmsg;
EventProvider invite;
EventProvider ping;
EventProvider pong;
EventProvider error;
RFCEvents()
: numeric(nullptr, "NUMERIC")
, join(nullptr, "JOIN")
, part(nullptr, "PART")
, kick(nullptr, "KICK")
, quit(nullptr, "QUIT")
, nick(nullptr, "NICK")
, mode(nullptr, "MODE")
, topic(nullptr, "TOPIC")
, privmsg(nullptr, "PRIVMSG")
, invite(nullptr, "INVITE")
, ping(nullptr, "PING")
, pong(nullptr, "PONG")
, error(nullptr, "ERROR")
{
}
};
/** Base class for client protocol serializers.
* A serializer has to implement serialization and parsing of protocol messages to/from wire format.
*/
class CoreExport ClientProtocol::Serializer
: public DataProvider
{
private:
ClientProtocol::MessageTagEvent evprov;
/** Make a white list containing which tags a user should get.
* @param user User in question.
* @param tagmap Tag map that contains all possible tags.
* @return Whitelist of tags to send to the user.
*/
static TagSelection MakeTagWhitelist(LocalUser* user, const TagMap& tagmap);
public:
/** Constructor.
* @param mod Module owning the serializer.
* @param Name Name of the serializer, e.g. "rfc".
*/
Serializer(Module* mod, const std::string& Name);
/** Handle a tag in a message being parsed. Call this method for each parsed tag.
* @param user User sending the tag.
* @param tagname Name of the tag.
* @param tagvalue Tag value, may be empty.
* @param tags TagMap to place the tag into, if it gets accepted.
* @return True if no error occurred, false if the tag name is invalid or if this tag already exists.
*/
bool HandleTag(LocalUser* user, const std::string& tagname, std::string& tagvalue, TagMap& tags) const;
/** Serialize a message for a user.
* @param user User to serialize the message for.
* @param msg Message to serialize.
* @return Raw serialized message, only containing the appropriate tags for the user.
* The reference is guaranteed to be valid as long as the Message object is alive and until the same
* Message is serialized for another user.
*/
const SerializedMessage& SerializeForUser(LocalUser* user, Message& msg);
/** Serialize a high level protocol message into wire format.
* @param msg High level message to serialize. Contains all necessary information about the message, including all possible tags.
* @param tagwl Message tags to include in the serialized message. Tags attached to the message but not included in the whitelist must not
* appear in the output. This is because each user may get a different set of tags for the same message.
* @return Protocol message in wire format. Must contain message delimiter as well, if any (e.g. CRLF for RFC1459).
*/
virtual std::string Serialize(const Message& msg, const TagSelection& tagwl) const = 0;
/** Parse a protocol message from wire format.
* @param user Source of the message.
* @param line Raw protocol message.
* @param parseoutput Output of the parser.
* @return True if the message was parsed successfully into parseoutput and should be processed, false to drop the message.
*/
virtual bool Parse(LocalUser* user, const std::string& line, ParseOutput& parseoutput) = 0;
};
inline ClientProtocol::MessageTagData::MessageTagData(MessageTagProvider* prov, const std::string& val, void* data)
: tagprov(prov)
, value(val)
, provdata(data)
{
}
|