mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:57:35 +00:00
LibIMAP: Support for the SEARCH command
This commit is contained in:
parent
318709c8ca
commit
a6339297ec
5 changed files with 188 additions and 0 deletions
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/CharacterTypes.h>
|
||||
#include <LibIMAP/Objects.h>
|
||||
|
||||
namespace IMAP {
|
||||
|
@ -112,4 +113,77 @@ String FetchCommand::serialize()
|
|||
|
||||
return AK::String::formatted("{} ({})", sequence_builder.build(), data_items_builder.build());
|
||||
}
|
||||
String serialize_astring(StringView string)
|
||||
{
|
||||
// Try to send an atom
|
||||
auto is_non_atom_char = [](char x) {
|
||||
auto non_atom_chars = { '(', ')', '{', ' ', '%', '*', '"', '\\', ']' };
|
||||
return AK::find(non_atom_chars.begin(), non_atom_chars.end(), x) != non_atom_chars.end();
|
||||
};
|
||||
auto is_atom = all_of(string.begin(), string.end(), [&](auto ch) { return is_ascii_control(ch) && !is_non_atom_char(ch); });
|
||||
if (is_atom) {
|
||||
return string;
|
||||
}
|
||||
|
||||
// Try to quote
|
||||
auto can_be_quoted = !(string.contains('\n') || string.contains('\r'));
|
||||
if (can_be_quoted) {
|
||||
auto escaped_str = string.to_string();
|
||||
escaped_str.replace("\\", "\\\\");
|
||||
escaped_str.replace("\"", "\\\"");
|
||||
return String::formatted("\"{}\"", escaped_str);
|
||||
}
|
||||
|
||||
// Just send a literal
|
||||
return String::formatted("{{{}}}\r\n{}", string.length(), string);
|
||||
}
|
||||
String SearchKey::serialize() const
|
||||
{
|
||||
return data.visit(
|
||||
[&](Empty const&) { VERIFY_NOT_REACHED(); return String("The compiler complains if you remove this."); },
|
||||
[&](All const&) { return String("ALL"); },
|
||||
[&](Answered const&) { return String("ANSWERED"); },
|
||||
[&](Bcc const& x) { return String::formatted("BCC {}", serialize_astring(x.bcc)); },
|
||||
[&](Cc const& x) { return String::formatted("CC {}", serialize_astring(x.cc)); },
|
||||
[&](Deleted const&) { return String("DELETED"); },
|
||||
[&](Draft const&) { return String("DRAFT"); },
|
||||
[&](From const& x) { return String::formatted("FROM {}", serialize_astring(x.from)); },
|
||||
[&](Header const& x) { return String::formatted("HEADER {} {}", serialize_astring(x.header), serialize_astring(x.value)); },
|
||||
[&](Keyword const& x) { return String::formatted("KEYWORD {}", x.keyword); },
|
||||
[&](Larger const& x) { return String::formatted("LARGER {}", x.number); },
|
||||
[&](New const&) { return String("NEW"); },
|
||||
[&](Not const& x) { return String::formatted("NOT {}", x.operand->serialize()); },
|
||||
[&](Old const&) { return String("OLD"); },
|
||||
[&](On const& x) { return String::formatted("ON {}", x.date.to_string("%d-%b-%Y")); },
|
||||
[&](Or const& x) { return String::formatted("OR {} {}", x.lhs->serialize(), x.rhs->serialize()); },
|
||||
[&](Recent const&) { return String("RECENT"); },
|
||||
[&](SearchKeys const& x) {
|
||||
StringBuilder sb;
|
||||
sb.append("(");
|
||||
bool first = true;
|
||||
for (const auto& item : x.keys) {
|
||||
if (!first)
|
||||
sb.append(", ");
|
||||
sb.append(item->serialize());
|
||||
first = false;
|
||||
}
|
||||
return sb.build();
|
||||
},
|
||||
[&](Seen const&) { return String("SEEN"); },
|
||||
[&](SentBefore const& x) { return String::formatted("SENTBEFORE {}", x.date.to_string("%d-%b-%Y")); },
|
||||
[&](SentOn const& x) { return String::formatted("SENTON {}", x.date.to_string("%d-%b-%Y")); },
|
||||
[&](SentSince const& x) { return String::formatted("SENTSINCE {}", x.date.to_string("%d-%b-%Y")); },
|
||||
[&](SequenceSet const& x) { return x.sequence.serialize(); },
|
||||
[&](Since const& x) { return String::formatted("SINCE {}", x.date.to_string("%d-%b-%Y")); },
|
||||
[&](Smaller const& x) { return String::formatted("SMALLER {}", x.number); },
|
||||
[&](Subject const& x) { return String::formatted("SUBJECT {}", serialize_astring(x.subject)); },
|
||||
[&](Text const& x) { return String::formatted("TEXT {}", serialize_astring(x.text)); },
|
||||
[&](To const& x) { return String::formatted("TO {}", serialize_astring(x.to)); },
|
||||
[&](UID const& x) { return String::formatted("UID {}", x.uid); },
|
||||
[&](Unanswered const&) { return String("UNANSWERED"); },
|
||||
[&](Undeleted const&) { return String("UNDELETED"); },
|
||||
[&](Undraft const&) { return String("UNDRAFT"); },
|
||||
[&](Unkeyword const& x) { return String::formatted("UNKEYWORD {}", serialize_astring(x.flag_keyword)); },
|
||||
[&](Unseen const&) { return String("UNSEEN"); });
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue