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

LibIMAP+Userland: Convert LibIMAP::Client to the Serenity Stream APIs

You now cannot get an unconnected LibIMAP::Client, but you can still
close it. This makes for a nicer API where we don't have a Client object
in a limbo state between being constructed and being connected.

This code still isn't as nice as it should be, as TLS::TLSv12 is still
not a Core::Stream::Socket subclass, which would allow for consolidating
most of the TLS/non-TLS code into a single implementation.
This commit is contained in:
sin-ack 2021-12-18 12:38:44 +00:00 committed by Ali Mohammad Pur
parent 53e9d757fe
commit aedb013ee3
4 changed files with 162 additions and 94 deletions

View file

@ -43,21 +43,21 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
}
Core::EventLoop loop;
auto client = IMAP::Client(host, port, tls);
client.connect()->await();
auto client = TRY(tls ? IMAP::Client::connect_tls(host, port) : IMAP::Client::connect_plaintext(host, port));
client->connection_promise()->await();
auto response = client.login(username, password.view())->await().release_value();
auto response = client->login(username, password.view())->await().release_value();
outln("[LOGIN] Login response: {}", response.response_text());
response = move(client.send_simple_command(IMAP::CommandType::Capability)->await().value().get<IMAP::SolidResponse>());
response = move(client->send_simple_command(IMAP::CommandType::Capability)->await().value().get<IMAP::SolidResponse>());
outln("[CAPABILITY] First capability: {}", response.data().capabilities().first());
bool idle_supported = !response.data().capabilities().find_if([](auto capability) { return capability.equals_ignoring_case("IDLE"); }).is_end();
response = client.list("", "*")->await().release_value();
response = client->list("", "*")->await().release_value();
outln("[LIST] First mailbox: {}", response.data().list_items().first().name);
auto mailbox = "Inbox";
response = client.select(mailbox)->await().release_value();
auto mailbox = "Inbox"sv;
response = client->select(mailbox)->await().release_value();
outln("[SELECT] Select response: {}", response.response_text());
auto message = Message {
@ -70,7 +70,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
"This is a message just to say hello.\r\n"
"So, \"Hello\"."
};
auto promise = client.append("INBOX", move(message));
auto promise = client->append("INBOX", move(message));
response = promise->await().release_value();
outln("[APPEND] Response: {}", response.response_text());
@ -79,13 +79,13 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
IMAP::SearchKey::From { "jdoe@machine.example" } });
keys.append(IMAP::SearchKey {
IMAP::SearchKey::Subject { "Saying Hello" } });
response = client.search({}, move(keys), false)->await().release_value();
response = client->search({}, move(keys), false)->await().release_value();
Vector<unsigned> search_results = move(response.data().search_results());
int added_message = search_results.first();
auto added_message = search_results.first();
outln("[SEARCH] Number of results: {}", search_results.size());
response = client.status("INBOX", { IMAP::StatusItemType::Recent, IMAP::StatusItemType::Messages })->await().release_value();
response = client->status("INBOX", { IMAP::StatusItemType::Recent, IMAP::StatusItemType::Messages })->await().release_value();
outln("[STATUS] Recent items: {}", response.data().status_item().get(IMAP::StatusItemType::Recent));
for (auto item : search_results) {
@ -118,7 +118,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
};
// clang-format on
auto fetch_response = client.fetch(fetch_command, false)->await().release_value();
auto fetch_response = client->fetch(fetch_command, false)->await().release_value();
outln("[FETCH] Subject of search result: {}",
fetch_response.data()
.fetch_data()
@ -133,25 +133,28 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
.value());
}
response = client.store(IMAP::StoreMethod::Add, { added_message, added_message }, false, { "\\Deleted" }, false)->await().release_value();
// FIXME: There is a discrepancy between IMAP::Sequence wanting signed ints
// and IMAP search results returning unsigned ones. Find which one is
// more correct and fix this.
response = client->store(IMAP::StoreMethod::Add, { static_cast<int>(added_message), static_cast<int>(added_message) }, false, { "\\Deleted" }, false)->await().release_value();
outln("[STORE] Store response: {}", response.response_text());
response = move(client.send_simple_command(IMAP::CommandType::Expunge)->await().release_value().get<IMAP::SolidResponse>());
response = move(client->send_simple_command(IMAP::CommandType::Expunge)->await().release_value().get<IMAP::SolidResponse>());
outln("[EXPUNGE] Number of expunged entries: {}", response.data().expunged().size());
if (idle_supported) {
VERIFY(client.idle()->await().has_value());
VERIFY(client->idle()->await().has_value());
sleep(3);
response = client.finish_idle()->await().release_value();
response = client->finish_idle()->await().release_value();
outln("[IDLE] Idle response: {}", response.response_text());
} else {
outln("[IDLE] Skipped. No IDLE support.");
}
response = move(client.send_simple_command(IMAP::CommandType::Logout)->await().release_value().get<IMAP::SolidResponse>());
response = move(client->send_simple_command(IMAP::CommandType::Logout)->await().release_value().get<IMAP::SolidResponse>());
outln("[LOGOUT] Bye: {}", response.data().bye_message().value());
client.close();
client->close();
return 0;
}