mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 11:38:11 +00:00
LibIMAP: Support for the LIST and SELECT commands
This commit is contained in:
parent
0f42ea6770
commit
2f04d24b66
5 changed files with 343 additions and 1 deletions
|
@ -125,8 +125,60 @@ void Parser::parse_untagged()
|
|||
{
|
||||
consume(" ");
|
||||
|
||||
// Certain messages begin with a number like:
|
||||
// * 15 EXISTS
|
||||
auto number = try_parse_number();
|
||||
if (number.has_value()) {
|
||||
consume(" ");
|
||||
auto data_type = parse_atom().to_string();
|
||||
if (data_type.matches("EXISTS")) {
|
||||
m_response.data().set_exists(number.value());
|
||||
consume("\r\n");
|
||||
} else if (data_type.matches("RECENT")) {
|
||||
m_response.data().set_recent(number.value());
|
||||
consume("\r\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (try_consume("CAPABILITY")) {
|
||||
parse_capability_response();
|
||||
} else if (try_consume("LIST")) {
|
||||
auto item = parse_list_item();
|
||||
m_response.data().add_list_item(move(item));
|
||||
} else if (try_consume("FLAGS")) {
|
||||
consume(" ");
|
||||
auto flags = parse_list(+[](StringView x) { return String(x); });
|
||||
m_response.data().set_flags(move(flags));
|
||||
consume("\r\n");
|
||||
} else if (try_consume("OK")) {
|
||||
consume(" ");
|
||||
if (try_consume("[")) {
|
||||
auto actual_type = parse_atom();
|
||||
consume(" ");
|
||||
if (actual_type.matches("UIDNEXT")) {
|
||||
auto n = parse_number();
|
||||
m_response.data().set_uid_next(n);
|
||||
} else if (actual_type.matches("UIDVALIDITY")) {
|
||||
auto n = parse_number();
|
||||
m_response.data().set_uid_validity(n);
|
||||
} else if (actual_type.matches("UNSEEN")) {
|
||||
auto n = parse_number();
|
||||
m_response.data().set_unseen(n);
|
||||
} else if (actual_type.matches("PERMANENTFLAGS")) {
|
||||
auto flags = parse_list(+[](StringView x) { return String(x); });
|
||||
m_response.data().set_permanent_flags(move(flags));
|
||||
} else {
|
||||
dbgln("Unknown: {}", actual_type);
|
||||
parse_while([](u8 x) { return x != ']'; });
|
||||
}
|
||||
consume("]");
|
||||
parse_while([](u8 x) { return x != '\r'; });
|
||||
consume("\r\n");
|
||||
} else {
|
||||
parse_while([](u8 x) { return x != '\r'; });
|
||||
consume("\r\n");
|
||||
}
|
||||
} else {
|
||||
auto x = parse_while([](u8 x) { return x != '\r'; });
|
||||
consume("\r\n");
|
||||
|
@ -134,6 +186,61 @@ void Parser::parse_untagged()
|
|||
}
|
||||
}
|
||||
|
||||
StringView Parser::parse_quoted_string()
|
||||
{
|
||||
auto str = parse_while([](u8 x) { return x != '"'; });
|
||||
consume("\"");
|
||||
return str;
|
||||
}
|
||||
|
||||
StringView Parser::parse_string()
|
||||
{
|
||||
if (try_consume("\"")) {
|
||||
return parse_quoted_string();
|
||||
} else {
|
||||
return parse_literal_string();
|
||||
}
|
||||
}
|
||||
|
||||
Optional<StringView> Parser::parse_nstring()
|
||||
{
|
||||
if (try_consume("NIL"))
|
||||
return {};
|
||||
else
|
||||
return { parse_string() };
|
||||
}
|
||||
|
||||
StringView Parser::parse_literal_string()
|
||||
{
|
||||
consume("{");
|
||||
auto num_bytes = parse_number();
|
||||
consume("}\r\n");
|
||||
|
||||
if (m_buffer.size() < position + num_bytes) {
|
||||
m_parsing_failed = true;
|
||||
return "";
|
||||
}
|
||||
|
||||
position += num_bytes;
|
||||
return StringView(m_buffer.data() + position - num_bytes, num_bytes);
|
||||
}
|
||||
|
||||
ListItem Parser::parse_list_item()
|
||||
{
|
||||
consume(" ");
|
||||
auto flags_vec = parse_list(parse_mailbox_flag);
|
||||
unsigned flags = 0;
|
||||
for (auto flag : flags_vec) {
|
||||
flags |= static_cast<unsigned>(flag);
|
||||
}
|
||||
consume(" \"");
|
||||
auto reference = parse_while([](u8 x) { return x != '"'; });
|
||||
consume("\" ");
|
||||
auto mailbox = parse_astring();
|
||||
consume("\r\n");
|
||||
return ListItem { flags, String(reference), String(mailbox) };
|
||||
}
|
||||
|
||||
void Parser::parse_capability_response()
|
||||
{
|
||||
auto capability = AK::Vector<String>();
|
||||
|
@ -178,6 +285,58 @@ ResponseStatus Parser::parse_status()
|
|||
return ResponseStatus::Bad;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector<T> Parser::parse_list(T converter(StringView))
|
||||
{
|
||||
consume("(");
|
||||
Vector<T> x;
|
||||
bool first = true;
|
||||
while (!try_consume(")")) {
|
||||
if (!first)
|
||||
consume(" ");
|
||||
auto item = parse_while([](u8 x) {
|
||||
return x != ' ' && x != ')';
|
||||
});
|
||||
x.append(converter(item));
|
||||
first = false;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
MailboxFlag Parser::parse_mailbox_flag(StringView s)
|
||||
{
|
||||
if (s.matches("\\All"))
|
||||
return MailboxFlag::All;
|
||||
if (s.matches("\\Drafts"))
|
||||
return MailboxFlag::Drafts;
|
||||
if (s.matches("\\Flagged"))
|
||||
return MailboxFlag::Flagged;
|
||||
if (s.matches("\\HasChildren"))
|
||||
return MailboxFlag::HasChildren;
|
||||
if (s.matches("\\HasNoChildren"))
|
||||
return MailboxFlag::HasNoChildren;
|
||||
if (s.matches("\\Important"))
|
||||
return MailboxFlag::Important;
|
||||
if (s.matches("\\Junk"))
|
||||
return MailboxFlag::Junk;
|
||||
if (s.matches("\\Marked"))
|
||||
return MailboxFlag::Marked;
|
||||
if (s.matches("\\Noinferiors"))
|
||||
return MailboxFlag::NoInferiors;
|
||||
if (s.matches("\\Noselect"))
|
||||
return MailboxFlag::NoSelect;
|
||||
if (s.matches("\\Sent"))
|
||||
return MailboxFlag::Sent;
|
||||
if (s.matches("\\Trash"))
|
||||
return MailboxFlag::Trash;
|
||||
if (s.matches("\\Unmarked"))
|
||||
return MailboxFlag::Unmarked;
|
||||
|
||||
dbgln("Unrecognized mailbox flag {}", s);
|
||||
return MailboxFlag::Unknown;
|
||||
}
|
||||
|
||||
StringView Parser::parse_while(Function<bool(u8)> should_consume)
|
||||
{
|
||||
int chars = 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue