123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778 |
- /*
- * Copyright (c) 2021, Kyle Pereira <hey@xylepereira.me>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #pragma once
- #include <AK/Format.h>
- #include <AK/Function.h>
- #include <AK/Tuple.h>
- #include <AK/Variant.h>
- #include <LibCore/DateTime.h>
- #include <LibCore/EventLoop.h>
- #include <LibCore/Object.h>
- #include <utility>
- namespace IMAP {
- enum class CommandType {
- Append,
- Capability,
- Copy,
- Create,
- Delete,
- Fetch,
- Idle,
- List,
- Login,
- Logout,
- Noop,
- Rename,
- Search,
- Select,
- Status,
- Store,
- UIDCopy,
- UIDFetch,
- UIDSearch,
- UIDStore,
- };
- 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,
- 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(String&& mailbox) { m_mailbox = move(mailbox); }
- String& 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 };
- String m_mailbox;
- };
- struct Address {
- Optional<String> name;
- Optional<String> source_route;
- Optional<String> mailbox;
- Optional<String> host;
- };
- struct Envelope {
- Optional<String> date; // Format of date not specified.
- Optional<String> subject;
- Optional<Vector<Address>> from;
- Optional<Vector<Address>> sender;
- Optional<Vector<Address>> reply_to;
- Optional<Vector<Address>> to;
- Optional<Vector<Address>> cc;
- Optional<Vector<Address>> bcc;
- Optional<String> in_reply_to;
- Optional<String> message_id;
- };
- class BodyStructure;
- struct BodyExtension {
- AK::Variant<Optional<String>, unsigned, Vector<OwnPtr<BodyExtension>>> data;
- };
- struct MultiPartBodyStructureData {
- Optional<Tuple<String, HashMap<String, String>>> disposition;
- Vector<OwnPtr<BodyStructure>> bodies;
- Vector<String> langs;
- String media_type;
- Optional<HashMap<String, String>> params;
- Optional<String> location;
- Optional<Vector<BodyExtension>> extensions;
- };
- struct BodyStructureData {
- String type;
- String subtype;
- Optional<String> id {};
- Optional<String> desc {};
- String encoding;
- HashMap<String, String> fields;
- unsigned bytes { 0 };
- unsigned lines { 0 };
- Optional<Envelope> envelope;
- Optional<String> md5 {};
- Optional<Tuple<String, HashMap<String, String>>> disposition {};
- Optional<Vector<String>> langs {};
- Optional<String> location {};
- Optional<Vector<BodyExtension>> extensions {};
- };
- class BodyStructure {
- friend Parser;
- public:
- explicit BodyStructure(BodyStructureData&& data)
- : m_data(move(data))
- {
- }
- explicit BodyStructure(MultiPartBodyStructureData&& data)
- : m_data(move(data))
- {
- }
- private:
- AK::Variant<BodyStructureData, MultiPartBodyStructureData> m_data;
- };
- // Set -1 for '*' i.e highest possible value.
- struct Sequence {
- int start;
- int end;
- [[nodiscard]] String 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<int>> parts {};
- bool ends_with_mime {};
- Optional<Vector<String>> headers {};
- [[nodiscard]] String serialize() const;
- };
- DataItemType type;
- Optional<Section> section {};
- bool partial_fetch { false };
- int start { 0 };
- int octets { 0 };
- [[nodiscard]] String serialize() const;
- };
- Vector<Sequence> sequence_set;
- Vector<DataItem> data_items;
- String serialize();
- };
- struct Command {
- public:
- CommandType type;
- int tag;
- Vector<String> args;
- };
- enum class ResponseStatus {
- Bad,
- No,
- OK,
- };
- struct ListItem {
- unsigned flags;
- String reference;
- String 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, Optional<String>&& body)
- {
- add_response_type(FetchResponseType::Body);
- m_bodies.append({ move(data_item), move(body) });
- }
- Vector<Tuple<FetchCommand::DataItem, Optional<String>>>& 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<String>&& flags)
- {
- add_response_type(FetchResponseType::Flags);
- m_flags = move(flags);
- }
- Vector<String>& 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<String> m_flags;
- Vector<Tuple<FetchCommand::DataItem, Optional<String>>> m_bodies;
- Core::DateTime m_internal_date;
- Envelope m_envelope;
- unsigned m_uid { 0 };
- unsigned m_response_type { 0 };
- BodyStructure m_body_structure;
- };
- String serialize_astring(StringView string);
- struct SearchKey {
- public:
- // clang-format off
- struct All { };
- struct Answered { };
- struct Bcc { String bcc; };
- struct Cc { String cc; };
- struct Deleted { };
- struct Draft { };
- struct From { String from; };
- struct Header { String header; String value; };
- struct Keyword { String 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 { String subject; };
- struct Text { String text; };
- struct To { String to; };
- struct UID { unsigned uid; };
- struct Unanswered { };
- struct Undeleted { };
- struct Undraft { };
- struct Unkeyword { String flag_keyword; };
- struct Unseen { };
- // clang-format on
- Variant<Empty, 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(std::forward<T>(t))
- {
- }
- SearchKey& operator=(SearchKey&& other) noexcept
- {
- if (this == &other) {
- return *this;
- }
- this->data = move(other.data);
- return *this;
- }
- [[nodiscard]] String 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=(const ResponseData&) = 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<String>&& capabilities)
- {
- m_capabilities = move(capabilities);
- add_response_type(ResponseType::Capability);
- }
- Vector<String>& 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 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<String>&& flags)
- {
- m_response_type |= static_cast<unsigned>(ResponseType::Flags);
- m_flags = move(flags);
- }
- Vector<String>& flags()
- {
- VERIFY(contains_response_type(ResponseType::Flags));
- return m_flags;
- }
- void set_permanent_flags(Vector<String>&& flags)
- {
- add_response_type(ResponseType::PermanentFlags);
- m_permanent_flags = move(flags);
- }
- Vector<String>& 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 set_bye(Optional<String> message)
- {
- add_response_type(ResponseType::Bye);
- m_bye_message = move(message);
- }
- Optional<String>& 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<String> m_capabilities;
- Vector<ListItem> m_list_items;
- unsigned m_recent {};
- unsigned m_exists {};
- unsigned m_uid_next {};
- unsigned m_uid_validity {};
- unsigned m_unseen {};
- Vector<String> m_permanent_flags;
- Vector<String> m_flags;
- Vector<Tuple<unsigned, FetchResponseData>> m_fetch_responses;
- Vector<unsigned> m_search_results;
- Optional<String> 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; }
- String 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;
- String m_response_text;
- unsigned m_tag;
- ResponseData m_data;
- };
- struct ContinueRequest {
- String data;
- };
- template<typename Result>
- class Promise : public Core::Object {
- C_OBJECT(Promise);
- private:
- Optional<Result> m_pending;
- public:
- Function<void(Result&)> on_resolved;
- void resolve(Result&& result)
- {
- m_pending = move(result);
- if (on_resolved)
- on_resolved(m_pending.value());
- }
- bool is_resolved()
- {
- return m_pending.has_value();
- };
- Result await()
- {
- while (!is_resolved()) {
- Core::EventLoop::current().pump();
- }
- return m_pending.release_value();
- }
- // Converts a Promise<A> to a Promise<B> using a function func: A -> B
- template<typename T>
- RefPtr<Promise<T>> map(T func(Result&))
- {
- RefPtr<Promise<T>> new_promise = Promise<T>::construct();
- on_resolved = [new_promise, func](Result& result) mutable {
- auto t = func(result);
- new_promise->resolve(move(t));
- };
- return new_promise;
- }
- };
- using Response = Variant<SolidResponse, ContinueRequest>;
- }
- // An RFC 2822 message
- // https://datatracker.ietf.org/doc/html/rfc2822
- struct Message {
- String data;
- };
|