1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 14:57:35 +00:00

LibIMAP: Support for remaining IMAP commands

These include APPEND, AUTHENTICATE, CHECK, CLOSE, EXAMINE, EXPUNGE,
LSUB, SUBSCRIBE, UNSUBSCRIBE
This commit is contained in:
x-yl 2021-06-02 18:53:08 +04:00 committed by Ali Mohammad Pur
parent 16995dc3d9
commit 9174fabf05
4 changed files with 93 additions and 0 deletions

View file

@ -146,6 +146,22 @@ static ReadonlyBytes command_byte_buffer(CommandType command)
return "UID SEARCH"sv.bytes(); return "UID SEARCH"sv.bytes();
case CommandType::Append: case CommandType::Append:
return "APPEND"sv.bytes(); return "APPEND"sv.bytes();
case CommandType::Examine:
return "EXAMINE"sv.bytes();
case CommandType::ListSub:
return "LSUB"sv.bytes();
case CommandType::Expunge:
return "EXPUNGE"sv.bytes();
case CommandType::Subscribe:
return "SUBSCRIBE"sv.bytes();
case CommandType::Unsubscribe:
return "UNSUBSCRIBE"sv.bytes();
case CommandType::Authenticate:
return "AUTHENTICATE"sv.bytes();
case CommandType::Check:
return "CHECK"sv.bytes();
case CommandType::Close:
return "CLOSE"sv.bytes();
case CommandType::Rename: case CommandType::Rename:
return "RENAME"sv.bytes(); return "RENAME"sv.bytes();
case CommandType::Status: case CommandType::Status:
@ -203,6 +219,14 @@ RefPtr<Promise<Optional<SolidResponse>>> Client::list(StringView reference_name,
return cast_promise<SolidResponse>(send_command(move(command))); return cast_promise<SolidResponse>(send_command(move(command)));
} }
RefPtr<Promise<Optional<SolidResponse>>> Client::lsub(StringView reference_name, StringView mailbox)
{
auto command = Command { CommandType::ListSub, m_current_command,
{ String::formatted("\"{}\"", reference_name),
String::formatted("\"{}\"", mailbox) } };
return cast_promise<SolidResponse>(send_command(move(command)));
}
RefPtr<Promise<Optional<SolidResponse>>> Client::fetch(FetchCommand request, bool uid) RefPtr<Promise<Optional<SolidResponse>>> Client::fetch(FetchCommand request, bool uid)
{ {
auto command = Command { uid ? CommandType::UIDFetch : CommandType::Fetch, m_current_command, { request.serialize() } }; auto command = Command { uid ? CommandType::UIDFetch : CommandType::Fetch, m_current_command, { request.serialize() } };
@ -266,6 +290,13 @@ void Client::send_next_command()
send_raw(buffer); send_raw(buffer);
m_expecting_response = true; m_expecting_response = true;
} }
RefPtr<Promise<Optional<SolidResponse>>> Client::examine(StringView string)
{
auto command = Command { CommandType::Examine, m_current_command, { string } };
return cast_promise<SolidResponse>(send_command(move(command)));
}
RefPtr<Promise<Optional<SolidResponse>>> Client::create_mailbox(StringView name) RefPtr<Promise<Optional<SolidResponse>>> Client::create_mailbox(StringView name)
{ {
auto command = Command { CommandType::Create, m_current_command, { name } }; auto command = Command { CommandType::Create, m_current_command, { name } };
@ -393,6 +424,21 @@ RefPtr<Promise<Optional<SolidResponse>>> Client::append(StringView mailbox, Mess
return cast_promise<SolidResponse>(response_promise); return cast_promise<SolidResponse>(response_promise);
} }
RefPtr<Promise<Optional<SolidResponse>>> Client::subscribe(StringView mailbox)
{
auto command = Command { CommandType::Subscribe, m_current_command, { mailbox } };
return cast_promise<SolidResponse>(send_command(move(command)));
}
RefPtr<Promise<Optional<SolidResponse>>> Client::unsubscribe(StringView mailbox)
{
auto command = Command { CommandType::Unsubscribe, m_current_command, { mailbox } };
return cast_promise<SolidResponse>(send_command(move(command)));
}
RefPtr<Promise<Optional<Response>>> Client::authenticate(StringView method)
{
auto command = Command { CommandType::Authenticate, m_current_command, { method } };
return send_command(move(command));
}
RefPtr<Promise<Optional<SolidResponse>>> Client::rename(StringView from, StringView to) RefPtr<Promise<Optional<SolidResponse>>> Client::rename(StringView from, StringView to)
{ {
auto command = Command { CommandType::Rename, m_current_command, { from, to } }; auto command = Command { CommandType::Rename, m_current_command, { from, to } };

View file

@ -23,14 +23,19 @@ public:
void send_raw(StringView data); void send_raw(StringView data);
RefPtr<Promise<Optional<SolidResponse>>> login(StringView username, StringView password); RefPtr<Promise<Optional<SolidResponse>>> login(StringView username, StringView password);
RefPtr<Promise<Optional<SolidResponse>>> list(StringView reference_name, StringView mailbox_name); RefPtr<Promise<Optional<SolidResponse>>> list(StringView reference_name, StringView mailbox_name);
RefPtr<Promise<Optional<SolidResponse>>> lsub(StringView reference_name, StringView mailbox_name);
RefPtr<Promise<Optional<SolidResponse>>> select(StringView string); RefPtr<Promise<Optional<SolidResponse>>> select(StringView string);
RefPtr<Promise<Optional<SolidResponse>>> examine(StringView string);
RefPtr<Promise<Optional<SolidResponse>>> search(Optional<String> charset, Vector<SearchKey>&& search_keys, bool uid); RefPtr<Promise<Optional<SolidResponse>>> search(Optional<String> charset, Vector<SearchKey>&& search_keys, bool uid);
RefPtr<Promise<Optional<SolidResponse>>> fetch(FetchCommand request, bool uid); RefPtr<Promise<Optional<SolidResponse>>> fetch(FetchCommand request, bool uid);
RefPtr<Promise<Optional<SolidResponse>>> store(StoreMethod, Sequence, bool silent, Vector<String> const& flags, bool uid); RefPtr<Promise<Optional<SolidResponse>>> store(StoreMethod, Sequence, bool silent, Vector<String> const& flags, bool uid);
RefPtr<Promise<Optional<SolidResponse>>> copy(Sequence sequence_set, StringView name, bool uid); RefPtr<Promise<Optional<SolidResponse>>> copy(Sequence sequence_set, StringView name, bool uid);
RefPtr<Promise<Optional<SolidResponse>>> create_mailbox(StringView name); RefPtr<Promise<Optional<SolidResponse>>> create_mailbox(StringView name);
RefPtr<Promise<Optional<SolidResponse>>> delete_mailbox(StringView name); RefPtr<Promise<Optional<SolidResponse>>> delete_mailbox(StringView name);
RefPtr<Promise<Optional<SolidResponse>>> subscribe(StringView mailbox);
RefPtr<Promise<Optional<SolidResponse>>> unsubscribe(StringView mailbox);
RefPtr<Promise<Optional<SolidResponse>>> rename(StringView from, StringView to); RefPtr<Promise<Optional<SolidResponse>>> rename(StringView from, StringView to);
RefPtr<Promise<Optional<Response>>> authenticate(StringView method);
RefPtr<Promise<Optional<ContinueRequest>>> idle(); RefPtr<Promise<Optional<ContinueRequest>>> idle();
RefPtr<Promise<Optional<SolidResponse>>> finish_idle(); RefPtr<Promise<Optional<SolidResponse>>> finish_idle();
RefPtr<Promise<Optional<SolidResponse>>> status(StringView mailbox, Vector<StatusItemType> const& types); RefPtr<Promise<Optional<SolidResponse>>> status(StringView mailbox, Vector<StatusItemType> const& types);

View file

@ -18,13 +18,19 @@
namespace IMAP { namespace IMAP {
enum class CommandType { enum class CommandType {
Append, Append,
Authenticate,
Capability, Capability,
Copy, Copy,
Check,
Close,
Create, Create,
Delete, Delete,
Examine,
Expunge,
Fetch, Fetch,
Idle, Idle,
List, List,
ListSub,
Login, Login,
Logout, Logout,
Noop, Noop,
@ -33,10 +39,12 @@ enum class CommandType {
Select, Select,
Status, Status,
Store, Store,
Subscribe,
UIDCopy, UIDCopy,
UIDFetch, UIDFetch,
UIDSearch, UIDSearch,
UIDStore, UIDStore,
Unsubscribe,
}; };
enum class MailboxFlag : unsigned { enum class MailboxFlag : unsigned {
@ -68,6 +76,8 @@ enum class ResponseType : unsigned {
PermanentFlags = 1u << 8, PermanentFlags = 1u << 8,
Fetch = 1u << 9, Fetch = 1u << 9,
Search = 1u << 10, Search = 1u << 10,
ListSub = 1u << 11,
Expunged = 1u << 12,
Bye = 1u << 13, Bye = 1u << 13,
Status = 1u << 14 Status = 1u << 14
}; };
@ -532,6 +542,18 @@ public:
return m_list_items; 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) void set_exists(unsigned exists)
{ {
add_response_type(ResponseType::Exists); add_response_type(ResponseType::Exists);
@ -640,6 +662,18 @@ public:
return m_search_results; 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<String> message) void set_bye(Optional<String> message)
{ {
add_response_type(ResponseType::Bye); add_response_type(ResponseType::Bye);
@ -668,6 +702,8 @@ private:
Vector<String> m_capabilities; Vector<String> m_capabilities;
Vector<ListItem> m_list_items; Vector<ListItem> m_list_items;
Vector<ListItem> m_lsub_items;
Vector<unsigned> m_expunged;
unsigned m_recent {}; unsigned m_recent {};
unsigned m_exists {}; unsigned m_exists {};

View file

@ -140,6 +140,9 @@ void Parser::parse_untagged()
} else if (data_type.matches("FETCH")) { } else if (data_type.matches("FETCH")) {
auto fetch_response = parse_fetch_response(); auto fetch_response = parse_fetch_response();
m_response.data().add_fetch_response(number.value(), move(fetch_response)); m_response.data().add_fetch_response(number.value(), move(fetch_response));
} else if (data_type.matches("EXPUNGE")) {
m_response.data().add_expunged(number.value());
consume("\r\n");
} }
return; return;
} }
@ -149,6 +152,9 @@ void Parser::parse_untagged()
} else if (try_consume("LIST")) { } else if (try_consume("LIST")) {
auto item = parse_list_item(); auto item = parse_list_item();
m_response.data().add_list_item(move(item)); m_response.data().add_list_item(move(item));
} else if (try_consume("LSUB")) {
auto item = parse_list_item();
m_response.data().add_lsub_item(move(item));
} else if (try_consume("FLAGS")) { } else if (try_consume("FLAGS")) {
consume(" "); consume(" ");
auto flags = parse_list(+[](StringView x) { return String(x); }); auto flags = parse_list(+[](StringView x) { return String(x); });