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:
parent
16995dc3d9
commit
9174fabf05
4 changed files with 93 additions and 0 deletions
|
@ -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 } };
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {};
|
||||||
|
|
|
@ -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); });
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue