mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-06 02:55:49 +03:00
5e1499d104
This commit un-deprecates DeprecatedString, and repurposes it as a byte string. As the null state has already been removed, there are no other particularly hairy blockers in repurposing this type as a byte string (what it _really_ is). This commit is auto-generated: $ xs=$(ack -l \bDeprecatedString\b\|deprecated_string AK Userland \ Meta Ports Ladybird Tests Kernel) $ perl -pie 's/\bDeprecatedString\b/ByteString/g; s/deprecated_string/byte_string/g' $xs $ clang-format --style=file -i \ $(git diff --name-only | grep \.cpp\|\.h) $ gn format $(git ls-files '*.gn' '*.gni')
772 lines
18 KiB
C++
772 lines
18 KiB
C++
/*
|
|
* Copyright (c) 2021, Kyle Pereira <hey@xylepereira.me>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Function.h>
|
|
#include <AK/Tuple.h>
|
|
#include <AK/Variant.h>
|
|
#include <LibCore/DateTime.h>
|
|
#include <LibCore/EventReceiver.h>
|
|
|
|
namespace IMAP {
|
|
enum class CommandType {
|
|
Append,
|
|
Authenticate,
|
|
Capability,
|
|
Copy,
|
|
Check,
|
|
Close,
|
|
Create,
|
|
Delete,
|
|
Examine,
|
|
Expunge,
|
|
Fetch,
|
|
Idle,
|
|
List,
|
|
ListSub,
|
|
Login,
|
|
Logout,
|
|
Noop,
|
|
Rename,
|
|
Search,
|
|
Select,
|
|
Status,
|
|
Store,
|
|
Subscribe,
|
|
UIDCopy,
|
|
UIDFetch,
|
|
UIDSearch,
|
|
UIDStore,
|
|
Unsubscribe,
|
|
};
|
|
|
|
enum class MailboxFlag : unsigned {
|
|
All = 1u << 0,
|
|
Drafts = 1u << 1,
|
|
Flagged = 1u << 2,
|
|
HasChildren = 1u << 3,
|
|
HasNoChildren = 1u << 4,
|
|
Important = 1u << 5,
|
|
Junk = 1u << 6,
|
|
Marked = 1u << 7,
|
|
NoInferiors = 1u << 8,
|
|
NoSelect = 1u << 9,
|
|
Sent = 1u << 10,
|
|
Trash = 1u << 11,
|
|
Unmarked = 1u << 12,
|
|
Unknown = 1u << 13,
|
|
};
|
|
|
|
enum class ResponseType : unsigned {
|
|
Capability = 1u << 0,
|
|
List = 1u << 1,
|
|
Exists = 1u << 2,
|
|
Recent = 1u << 3,
|
|
Flags = 1u << 4,
|
|
UIDNext = 1u << 5,
|
|
UIDValidity = 1u << 6,
|
|
Unseen = 1u << 7,
|
|
PermanentFlags = 1u << 8,
|
|
Fetch = 1u << 9,
|
|
Search = 1u << 10,
|
|
ListSub = 1u << 11,
|
|
Expunged = 1u << 12,
|
|
Bye = 1u << 13,
|
|
Status = 1u << 14
|
|
};
|
|
|
|
enum class FetchResponseType : unsigned {
|
|
Body = 1u << 1,
|
|
UID = 1u << 2,
|
|
InternalDate = 1u << 3,
|
|
Envelope = 1u << 4,
|
|
Flags = 1u << 5,
|
|
BodyStructure = 1u << 6,
|
|
};
|
|
|
|
enum class StatusItemType : unsigned {
|
|
Recent = 1u << 1,
|
|
UIDNext = 1u << 2,
|
|
UIDValidity = 1u << 3,
|
|
Unseen = 1u << 4,
|
|
Messages = 1u << 5,
|
|
};
|
|
|
|
class Parser;
|
|
|
|
class StatusItem {
|
|
public:
|
|
[[nodiscard]] unsigned status_items() const
|
|
{
|
|
return m_status_items;
|
|
}
|
|
|
|
[[nodiscard]] bool contains_status_item_type(StatusItemType type) const
|
|
{
|
|
return (static_cast<unsigned>(type) & m_status_items) != 0;
|
|
}
|
|
|
|
void add_status_item_type(StatusItemType type)
|
|
{
|
|
m_status_items |= static_cast<unsigned>(type);
|
|
}
|
|
|
|
void set_mailbox(ByteString&& mailbox) { m_mailbox = move(mailbox); }
|
|
ByteString& mailbox() { return m_mailbox; }
|
|
|
|
unsigned get(StatusItemType type) const
|
|
{
|
|
VERIFY(contains_status_item_type(type));
|
|
switch (type) {
|
|
case StatusItemType::Recent:
|
|
return m_recent;
|
|
case StatusItemType::UIDNext:
|
|
return m_uid_next;
|
|
case StatusItemType::UIDValidity:
|
|
return m_uid_validity;
|
|
case StatusItemType::Unseen:
|
|
return m_unseen;
|
|
case StatusItemType::Messages:
|
|
return m_messages;
|
|
}
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
|
|
void set(StatusItemType type, unsigned value)
|
|
{
|
|
add_status_item_type(type);
|
|
switch (type) {
|
|
case StatusItemType::Recent:
|
|
m_recent = value;
|
|
break;
|
|
case StatusItemType::UIDNext:
|
|
m_uid_next = value;
|
|
break;
|
|
case StatusItemType::UIDValidity:
|
|
m_uid_validity = value;
|
|
break;
|
|
case StatusItemType::Unseen:
|
|
m_unseen = value;
|
|
break;
|
|
case StatusItemType::Messages:
|
|
m_uid_next = value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
private:
|
|
unsigned m_status_items { 0 };
|
|
unsigned m_messages { 0 };
|
|
unsigned m_recent { 0 };
|
|
unsigned m_uid_next { 0 };
|
|
unsigned m_uid_validity { 0 };
|
|
unsigned m_unseen { 0 };
|
|
ByteString m_mailbox;
|
|
};
|
|
|
|
struct Address {
|
|
ByteString name;
|
|
ByteString source_route;
|
|
ByteString mailbox;
|
|
ByteString host;
|
|
};
|
|
|
|
struct Envelope {
|
|
ByteString date; // Format of date not specified.
|
|
ByteString subject;
|
|
Vector<Address> from;
|
|
Vector<Address> sender;
|
|
Vector<Address> reply_to;
|
|
Vector<Address> to;
|
|
Vector<Address> cc;
|
|
Vector<Address> bcc;
|
|
ByteString in_reply_to;
|
|
ByteString message_id;
|
|
};
|
|
|
|
class BodyStructure;
|
|
|
|
struct BodyExtension {
|
|
AK::Variant<Optional<ByteString>, unsigned, Vector<OwnPtr<BodyExtension>>> data;
|
|
};
|
|
|
|
struct MultiPartBodyStructureData {
|
|
Optional<Tuple<ByteString, HashMap<ByteString, ByteString>>> disposition;
|
|
Vector<OwnPtr<BodyStructure>> bodies;
|
|
Vector<ByteString> langs;
|
|
ByteString multipart_subtype;
|
|
HashMap<ByteString, ByteString> params;
|
|
ByteString location;
|
|
Vector<BodyExtension> extensions;
|
|
};
|
|
|
|
struct BodyStructureData {
|
|
ByteString type;
|
|
ByteString subtype;
|
|
ByteString id {};
|
|
ByteString desc {};
|
|
ByteString encoding;
|
|
HashMap<ByteString, ByteString> fields;
|
|
unsigned bytes { 0 };
|
|
unsigned lines { 0 };
|
|
Optional<Tuple<Envelope, NonnullOwnPtr<BodyStructure>>> contanied_message;
|
|
|
|
ByteString md5 {};
|
|
Optional<Tuple<ByteString, HashMap<ByteString, ByteString>>> disposition {};
|
|
Optional<Vector<ByteString>> langs {};
|
|
ByteString location {};
|
|
|
|
Vector<BodyExtension> extensions {};
|
|
};
|
|
|
|
class BodyStructure {
|
|
friend Parser;
|
|
|
|
public:
|
|
explicit BodyStructure(BodyStructureData&& data)
|
|
: m_data(move(data))
|
|
{
|
|
}
|
|
|
|
explicit BodyStructure(MultiPartBodyStructureData&& data)
|
|
: m_data(move(data))
|
|
{
|
|
}
|
|
|
|
AK::Variant<BodyStructureData, MultiPartBodyStructureData> const& data() const { return m_data; }
|
|
|
|
private:
|
|
AK::Variant<BodyStructureData, MultiPartBodyStructureData> m_data;
|
|
};
|
|
|
|
// Set -1 for '*' i.e highest possible value.
|
|
struct Sequence {
|
|
int start;
|
|
int end;
|
|
|
|
[[nodiscard]] ByteString serialize() const;
|
|
};
|
|
|
|
struct FetchCommand {
|
|
enum class DataItemType {
|
|
BodyStructure,
|
|
Envelope,
|
|
Flags,
|
|
InternalDate,
|
|
UID,
|
|
PeekBody,
|
|
BodySection
|
|
};
|
|
|
|
struct DataItem {
|
|
enum class SectionType {
|
|
Header,
|
|
HeaderFields,
|
|
HeaderFieldsNot,
|
|
Text,
|
|
Parts
|
|
};
|
|
struct Section {
|
|
SectionType type;
|
|
|
|
Optional<Vector<unsigned>> parts {};
|
|
bool ends_with_mime {};
|
|
|
|
Optional<Vector<ByteString>> headers {};
|
|
|
|
[[nodiscard]] ByteString serialize() const;
|
|
};
|
|
|
|
DataItemType type;
|
|
|
|
Optional<Section> section {};
|
|
bool partial_fetch { false };
|
|
int start { 0 };
|
|
int octets { 0 };
|
|
|
|
[[nodiscard]] ByteString serialize() const;
|
|
};
|
|
|
|
Vector<Sequence> sequence_set;
|
|
Vector<DataItem> data_items;
|
|
|
|
ByteString serialize();
|
|
};
|
|
struct Command {
|
|
public:
|
|
CommandType type;
|
|
int tag;
|
|
Vector<ByteString> args;
|
|
};
|
|
|
|
enum class ResponseStatus {
|
|
Bad,
|
|
No,
|
|
OK,
|
|
};
|
|
|
|
struct ListItem {
|
|
unsigned flags;
|
|
ByteString reference;
|
|
ByteString name;
|
|
};
|
|
|
|
class FetchResponseData {
|
|
public:
|
|
[[nodiscard]] unsigned response_type() const
|
|
{
|
|
return m_response_type;
|
|
}
|
|
|
|
[[nodiscard]] bool contains_response_type(FetchResponseType response_type) const
|
|
{
|
|
return (static_cast<unsigned>(response_type) & m_response_type) != 0;
|
|
}
|
|
|
|
void add_response_type(FetchResponseType type)
|
|
{
|
|
m_response_type |= static_cast<unsigned>(type);
|
|
}
|
|
|
|
void add_body_data(FetchCommand::DataItem&& data_item, ByteString&& body)
|
|
{
|
|
add_response_type(FetchResponseType::Body);
|
|
m_bodies.append({ move(data_item), move(body) });
|
|
}
|
|
|
|
Vector<Tuple<FetchCommand::DataItem, ByteString>>& body_data()
|
|
{
|
|
VERIFY(contains_response_type(FetchResponseType::Body));
|
|
return m_bodies;
|
|
}
|
|
|
|
void set_uid(unsigned uid)
|
|
{
|
|
add_response_type(FetchResponseType::UID);
|
|
m_uid = uid;
|
|
}
|
|
|
|
[[nodiscard]] unsigned uid() const
|
|
{
|
|
VERIFY(contains_response_type(FetchResponseType::UID));
|
|
return m_uid;
|
|
}
|
|
|
|
void set_internal_date(Core::DateTime time)
|
|
{
|
|
add_response_type(FetchResponseType::InternalDate);
|
|
m_internal_date = time;
|
|
}
|
|
|
|
Core::DateTime& internal_date()
|
|
{
|
|
VERIFY(contains_response_type(FetchResponseType::InternalDate));
|
|
return m_internal_date;
|
|
}
|
|
|
|
void set_envelope(Envelope&& envelope)
|
|
{
|
|
add_response_type(FetchResponseType::Envelope);
|
|
m_envelope = move(envelope);
|
|
}
|
|
|
|
Envelope& envelope()
|
|
{
|
|
VERIFY(contains_response_type(FetchResponseType::Envelope));
|
|
return m_envelope;
|
|
}
|
|
|
|
void set_flags(Vector<ByteString>&& flags)
|
|
{
|
|
add_response_type(FetchResponseType::Flags);
|
|
m_flags = move(flags);
|
|
}
|
|
|
|
Vector<ByteString>& flags()
|
|
{
|
|
VERIFY(contains_response_type(FetchResponseType::Flags));
|
|
return m_flags;
|
|
}
|
|
|
|
void set_body_structure(BodyStructure&& structure)
|
|
{
|
|
add_response_type(FetchResponseType::BodyStructure);
|
|
m_body_structure = move(structure);
|
|
}
|
|
|
|
BodyStructure& body_structure()
|
|
{
|
|
VERIFY(contains_response_type(FetchResponseType::BodyStructure));
|
|
return m_body_structure;
|
|
}
|
|
|
|
FetchResponseData()
|
|
: m_body_structure(BodyStructureData {})
|
|
{
|
|
}
|
|
|
|
private:
|
|
Vector<ByteString> m_flags;
|
|
Vector<Tuple<FetchCommand::DataItem, ByteString>> m_bodies;
|
|
Core::DateTime m_internal_date;
|
|
Envelope m_envelope;
|
|
unsigned m_uid { 0 };
|
|
unsigned m_response_type { 0 };
|
|
BodyStructure m_body_structure;
|
|
};
|
|
|
|
ByteString serialize_astring(StringView string);
|
|
|
|
struct SearchKey {
|
|
public:
|
|
// clang-format off
|
|
struct All { };
|
|
struct Answered { };
|
|
struct Bcc { ByteString bcc; };
|
|
struct Cc { ByteString cc; };
|
|
struct Deleted { };
|
|
struct Draft { };
|
|
struct From { ByteString from; };
|
|
struct Header { ByteString header; ByteString value; };
|
|
struct Keyword { ByteString keyword; };
|
|
struct Larger { unsigned number; };
|
|
struct New { };
|
|
struct Not { OwnPtr<SearchKey> operand; };
|
|
struct Old { };
|
|
struct On { Core::DateTime date; };
|
|
struct Or { OwnPtr<SearchKey> lhs; OwnPtr<SearchKey> rhs; };
|
|
struct Recent { };
|
|
struct SearchKeys { Vector<OwnPtr<SearchKey>> keys; };
|
|
struct Seen { };
|
|
struct SentBefore { Core::DateTime date; };
|
|
struct SentOn { Core::DateTime date; };
|
|
struct SentSince { Core::DateTime date; };
|
|
struct SequenceSet { Sequence sequence; };
|
|
struct Since { Core::DateTime date; };
|
|
struct Smaller { unsigned number; };
|
|
struct Subject { ByteString subject; };
|
|
struct Text { ByteString text; };
|
|
struct To { ByteString to; };
|
|
struct UID { unsigned uid; };
|
|
struct Unanswered { };
|
|
struct Undeleted { };
|
|
struct Undraft { };
|
|
struct Unkeyword { ByteString flag_keyword; };
|
|
struct Unseen { };
|
|
// clang-format on
|
|
|
|
Variant<All, Answered, Bcc, Cc, Deleted, Draft, From, Header, Keyword,
|
|
Larger, New, Not, Old, On, Or, Recent, SearchKeys, Seen, SentBefore, SentOn,
|
|
SentSince, SequenceSet, Since, Smaller, Subject, Text, To, UID, Unanswered,
|
|
Undeleted, Undraft, Unkeyword, Unseen>
|
|
data;
|
|
|
|
SearchKey(SearchKey&& other) noexcept
|
|
: data(move(other.data))
|
|
{
|
|
}
|
|
|
|
template<typename T>
|
|
explicit SearchKey(T&& t)
|
|
: data(forward<T>(t))
|
|
{
|
|
}
|
|
|
|
SearchKey& operator=(SearchKey&& other) noexcept
|
|
{
|
|
if (this == &other) {
|
|
return *this;
|
|
}
|
|
|
|
this->data = move(other.data);
|
|
|
|
return *this;
|
|
}
|
|
|
|
[[nodiscard]] ByteString serialize() const;
|
|
};
|
|
|
|
class ResponseData {
|
|
public:
|
|
[[nodiscard]] unsigned response_type() const
|
|
{
|
|
return m_response_type;
|
|
}
|
|
|
|
ResponseData()
|
|
: m_response_type(0)
|
|
{
|
|
}
|
|
|
|
ResponseData(ResponseData&) = delete;
|
|
ResponseData(ResponseData&&) = default;
|
|
ResponseData& operator=(ResponseData const&) = delete;
|
|
ResponseData& operator=(ResponseData&&) = default;
|
|
|
|
[[nodiscard]] bool contains_response_type(ResponseType response_type) const
|
|
{
|
|
return (static_cast<unsigned>(response_type) & m_response_type) != 0;
|
|
}
|
|
|
|
void add_response_type(ResponseType response_type)
|
|
{
|
|
m_response_type = m_response_type | static_cast<unsigned>(response_type);
|
|
}
|
|
|
|
void add_capabilities(Vector<ByteString>&& capabilities)
|
|
{
|
|
m_capabilities = move(capabilities);
|
|
add_response_type(ResponseType::Capability);
|
|
}
|
|
|
|
Vector<ByteString>& capabilities()
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::Capability));
|
|
return m_capabilities;
|
|
}
|
|
|
|
void add_list_item(ListItem&& item)
|
|
{
|
|
add_response_type(ResponseType::List);
|
|
m_list_items.append(move(item));
|
|
}
|
|
|
|
Vector<ListItem>& list_items()
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::List));
|
|
return m_list_items;
|
|
}
|
|
|
|
void add_lsub_item(ListItem&& item)
|
|
{
|
|
add_response_type(ResponseType::List);
|
|
m_lsub_items.append(move(item));
|
|
}
|
|
|
|
Vector<ListItem>& lsub_items()
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::ListSub));
|
|
return m_lsub_items;
|
|
}
|
|
|
|
void set_exists(unsigned exists)
|
|
{
|
|
add_response_type(ResponseType::Exists);
|
|
m_exists = exists;
|
|
}
|
|
|
|
[[nodiscard]] unsigned exists() const
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::Exists));
|
|
return m_exists;
|
|
}
|
|
|
|
void set_recent(unsigned recent)
|
|
{
|
|
add_response_type(ResponseType::Recent);
|
|
m_recent = recent;
|
|
}
|
|
|
|
[[nodiscard]] unsigned recent() const
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::Recent));
|
|
return m_recent;
|
|
}
|
|
|
|
void set_uid_next(unsigned uid_next)
|
|
{
|
|
add_response_type(ResponseType::UIDNext);
|
|
m_uid_next = uid_next;
|
|
}
|
|
|
|
[[nodiscard]] unsigned uid_next() const
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::UIDNext));
|
|
return m_uid_next;
|
|
}
|
|
|
|
void set_uid_validity(unsigned uid_validity)
|
|
{
|
|
add_response_type(ResponseType::UIDValidity);
|
|
m_uid_validity = uid_validity;
|
|
}
|
|
|
|
[[nodiscard]] unsigned uid_validity() const
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::UIDValidity));
|
|
return m_uid_validity;
|
|
}
|
|
|
|
void set_unseen(unsigned unseen)
|
|
{
|
|
add_response_type(ResponseType::Unseen);
|
|
m_unseen = unseen;
|
|
}
|
|
|
|
[[nodiscard]] unsigned unseen() const
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::Unseen));
|
|
return m_unseen;
|
|
}
|
|
|
|
void set_flags(Vector<ByteString>&& flags)
|
|
{
|
|
m_response_type |= static_cast<unsigned>(ResponseType::Flags);
|
|
m_flags = move(flags);
|
|
}
|
|
|
|
Vector<ByteString>& flags()
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::Flags));
|
|
return m_flags;
|
|
}
|
|
|
|
void set_permanent_flags(Vector<ByteString>&& flags)
|
|
{
|
|
add_response_type(ResponseType::PermanentFlags);
|
|
m_permanent_flags = move(flags);
|
|
}
|
|
|
|
Vector<ByteString>& permanent_flags()
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::PermanentFlags));
|
|
return m_permanent_flags;
|
|
}
|
|
|
|
void add_fetch_response(unsigned message, FetchResponseData&& data)
|
|
{
|
|
add_response_type(ResponseType::Fetch);
|
|
m_fetch_responses.append(Tuple<unsigned, FetchResponseData> { move(message), move(data) });
|
|
}
|
|
|
|
Vector<Tuple<unsigned, FetchResponseData>>& fetch_data()
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::Fetch));
|
|
return m_fetch_responses;
|
|
}
|
|
|
|
void set_search_results(Vector<unsigned>&& results)
|
|
{
|
|
add_response_type(ResponseType::Search);
|
|
m_search_results = move(results);
|
|
}
|
|
|
|
Vector<unsigned>& search_results()
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::Search));
|
|
return m_search_results;
|
|
}
|
|
|
|
void add_expunged(unsigned message)
|
|
{
|
|
add_response_type(ResponseType::Expunged);
|
|
m_expunged.append(message);
|
|
}
|
|
|
|
Vector<unsigned>& expunged()
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::Expunged));
|
|
return m_expunged;
|
|
}
|
|
|
|
void set_bye(Optional<ByteString> message)
|
|
{
|
|
add_response_type(ResponseType::Bye);
|
|
m_bye_message = move(message);
|
|
}
|
|
|
|
Optional<ByteString>& bye_message()
|
|
{
|
|
VERIFY(contains_response_type(ResponseType::Bye));
|
|
return m_bye_message;
|
|
}
|
|
|
|
void set_status(StatusItem&& status_item)
|
|
{
|
|
add_response_type(ResponseType::Status);
|
|
m_status_item = move(status_item);
|
|
}
|
|
|
|
StatusItem& status_item()
|
|
{
|
|
return m_status_item;
|
|
}
|
|
|
|
private:
|
|
unsigned m_response_type;
|
|
|
|
Vector<ByteString> m_capabilities;
|
|
Vector<ListItem> m_list_items;
|
|
Vector<ListItem> m_lsub_items;
|
|
Vector<unsigned> m_expunged;
|
|
|
|
unsigned m_recent {};
|
|
unsigned m_exists {};
|
|
|
|
unsigned m_uid_next {};
|
|
unsigned m_uid_validity {};
|
|
unsigned m_unseen {};
|
|
Vector<ByteString> m_permanent_flags;
|
|
Vector<ByteString> m_flags;
|
|
Vector<Tuple<unsigned, FetchResponseData>> m_fetch_responses;
|
|
Vector<unsigned> m_search_results;
|
|
Optional<ByteString> m_bye_message;
|
|
StatusItem m_status_item;
|
|
};
|
|
|
|
enum class StoreMethod {
|
|
Replace,
|
|
Add,
|
|
Remove
|
|
};
|
|
|
|
class SolidResponse {
|
|
// Parser is allowed to set up fields
|
|
friend class Parser;
|
|
|
|
public:
|
|
ResponseStatus status() { return m_status; }
|
|
|
|
int tag() const { return m_tag; }
|
|
|
|
ResponseData& data() { return m_data; }
|
|
|
|
ByteString response_text() { return m_response_text; }
|
|
|
|
SolidResponse()
|
|
: SolidResponse(ResponseStatus::Bad, -1)
|
|
{
|
|
}
|
|
|
|
SolidResponse(ResponseStatus status, int tag)
|
|
: m_status(status)
|
|
, m_tag(tag)
|
|
, m_data(ResponseData())
|
|
{
|
|
}
|
|
|
|
private:
|
|
ResponseStatus m_status;
|
|
ByteString m_response_text;
|
|
unsigned m_tag;
|
|
|
|
ResponseData m_data;
|
|
};
|
|
|
|
struct ContinueRequest {
|
|
ByteString data;
|
|
};
|
|
|
|
using Response = Variant<SolidResponse, ContinueRequest>;
|
|
}
|
|
|
|
// An RFC 2822 message
|
|
// https://datatracker.ietf.org/doc/html/rfc2822
|
|
struct Message {
|
|
ByteString data;
|
|
};
|