Objects.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /*
  2. * Copyright (c) 2021, Kyle Pereira <hey@xylepereira.me>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/CharacterTypes.h>
  7. #include <LibIMAP/Objects.h>
  8. namespace IMAP {
  9. ByteString Sequence::serialize() const
  10. {
  11. if (start == end) {
  12. return AK::ByteString::formatted("{}", start);
  13. } else {
  14. auto start_char = start != -1 ? ByteString::formatted("{}", start) : "*";
  15. auto end_char = end != -1 ? ByteString::formatted("{}", end) : "*";
  16. return ByteString::formatted("{}:{}", start_char, end_char);
  17. }
  18. }
  19. ByteString FetchCommand::DataItem::Section::serialize() const
  20. {
  21. StringBuilder headers_builder;
  22. switch (type) {
  23. case SectionType::Header:
  24. return "HEADER";
  25. case SectionType::HeaderFields:
  26. case SectionType::HeaderFieldsNot: {
  27. if (type == SectionType::HeaderFields)
  28. headers_builder.append("HEADER.FIELDS ("sv);
  29. else
  30. headers_builder.append("HEADERS.FIELDS.NOT ("sv);
  31. bool first = true;
  32. for (auto& field : headers.value()) {
  33. if (!first)
  34. headers_builder.append(' ');
  35. headers_builder.append(field);
  36. first = false;
  37. }
  38. headers_builder.append(')');
  39. return headers_builder.to_byte_string();
  40. }
  41. case SectionType::Text:
  42. return "TEXT";
  43. case SectionType::Parts: {
  44. StringBuilder sb;
  45. bool first = true;
  46. for (int part : parts.value()) {
  47. if (!first)
  48. sb.append('.');
  49. sb.appendff("{}", part);
  50. first = false;
  51. }
  52. if (ends_with_mime) {
  53. sb.append(".MIME"sv);
  54. }
  55. return sb.to_byte_string();
  56. }
  57. }
  58. VERIFY_NOT_REACHED();
  59. }
  60. ByteString FetchCommand::DataItem::serialize() const
  61. {
  62. switch (type) {
  63. case DataItemType::Envelope:
  64. return "ENVELOPE";
  65. case DataItemType::Flags:
  66. return "FLAGS";
  67. case DataItemType::InternalDate:
  68. return "INTERNALDATE";
  69. case DataItemType::UID:
  70. return "UID";
  71. case DataItemType::PeekBody:
  72. case DataItemType::BodySection: {
  73. StringBuilder sb;
  74. if (type == DataItemType::BodySection)
  75. sb.appendff("BODY[{}]", section.value().serialize());
  76. else
  77. sb.appendff("BODY.PEEK[{}]", section.value().serialize());
  78. if (partial_fetch) {
  79. sb.appendff("<{}.{}>", start, octets);
  80. }
  81. return sb.to_byte_string();
  82. }
  83. case DataItemType::BodyStructure:
  84. return "BODYSTRUCTURE";
  85. }
  86. VERIFY_NOT_REACHED();
  87. }
  88. ByteString FetchCommand::serialize()
  89. {
  90. StringBuilder sequence_builder;
  91. bool first = true;
  92. for (auto& sequence : sequence_set) {
  93. if (!first) {
  94. sequence_builder.append(',');
  95. }
  96. sequence_builder.append(sequence.serialize());
  97. first = false;
  98. }
  99. StringBuilder data_items_builder;
  100. first = true;
  101. for (auto& data_item : data_items) {
  102. if (!first) {
  103. data_items_builder.append(' ');
  104. }
  105. data_items_builder.append(data_item.serialize());
  106. first = false;
  107. }
  108. return AK::ByteString::formatted("{} ({})", sequence_builder.to_byte_string(), data_items_builder.to_byte_string());
  109. }
  110. ByteString serialize_astring(StringView string)
  111. {
  112. // Try to send an atom
  113. auto is_non_atom_char = [](char x) {
  114. auto non_atom_chars = { '(', ')', '{', ' ', '%', '*', '"', '\\', ']' };
  115. return AK::find(non_atom_chars.begin(), non_atom_chars.end(), x) != non_atom_chars.end();
  116. };
  117. auto is_atom = all_of(string, [&](auto ch) { return is_ascii_control(ch) && !is_non_atom_char(ch); });
  118. if (is_atom) {
  119. return string;
  120. }
  121. // Try to quote
  122. auto can_be_quoted = !(string.contains('\n') || string.contains('\r'));
  123. if (can_be_quoted) {
  124. auto escaped_str = string.replace("\\"sv, "\\\\"sv, ReplaceMode::All).replace("\""sv, "\\\""sv, ReplaceMode::All);
  125. return ByteString::formatted("\"{}\"", escaped_str);
  126. }
  127. // Just send a literal
  128. return ByteString::formatted("{{{}}}\r\n{}", string.length(), string);
  129. }
  130. ByteString SearchKey::serialize() const
  131. {
  132. return data.visit(
  133. [&](All const&) { return ByteString("ALL"); },
  134. [&](Answered const&) { return ByteString("ANSWERED"); },
  135. [&](Bcc const& x) { return ByteString::formatted("BCC {}", serialize_astring(x.bcc)); },
  136. [&](Cc const& x) { return ByteString::formatted("CC {}", serialize_astring(x.cc)); },
  137. [&](Deleted const&) { return ByteString("DELETED"); },
  138. [&](Draft const&) { return ByteString("DRAFT"); },
  139. [&](From const& x) { return ByteString::formatted("FROM {}", serialize_astring(x.from)); },
  140. [&](Header const& x) { return ByteString::formatted("HEADER {} {}", serialize_astring(x.header), serialize_astring(x.value)); },
  141. [&](Keyword const& x) { return ByteString::formatted("KEYWORD {}", x.keyword); },
  142. [&](Larger const& x) { return ByteString::formatted("LARGER {}", x.number); },
  143. [&](New const&) { return ByteString("NEW"); },
  144. [&](Not const& x) { return ByteString::formatted("NOT {}", x.operand->serialize()); },
  145. [&](Old const&) { return ByteString("OLD"); },
  146. [&](On const& x) { return ByteString::formatted("ON {}", x.date.to_byte_string("%d-%b-%Y"sv)); },
  147. [&](Or const& x) { return ByteString::formatted("OR {} {}", x.lhs->serialize(), x.rhs->serialize()); },
  148. [&](Recent const&) { return ByteString("RECENT"); },
  149. [&](SearchKeys const& x) {
  150. StringBuilder sb;
  151. sb.append('(');
  152. bool first = true;
  153. for (const auto& item : x.keys) {
  154. if (!first)
  155. sb.append(", "sv);
  156. sb.append(item->serialize());
  157. first = false;
  158. }
  159. return sb.to_byte_string();
  160. },
  161. [&](Seen const&) { return ByteString("SEEN"); },
  162. [&](SentBefore const& x) { return ByteString::formatted("SENTBEFORE {}", x.date.to_byte_string("%d-%b-%Y"sv)); },
  163. [&](SentOn const& x) { return ByteString::formatted("SENTON {}", x.date.to_byte_string("%d-%b-%Y"sv)); },
  164. [&](SentSince const& x) { return ByteString::formatted("SENTSINCE {}", x.date.to_byte_string("%d-%b-%Y"sv)); },
  165. [&](SequenceSet const& x) { return x.sequence.serialize(); },
  166. [&](Since const& x) { return ByteString::formatted("SINCE {}", x.date.to_byte_string("%d-%b-%Y"sv)); },
  167. [&](Smaller const& x) { return ByteString::formatted("SMALLER {}", x.number); },
  168. [&](Subject const& x) { return ByteString::formatted("SUBJECT {}", serialize_astring(x.subject)); },
  169. [&](Text const& x) { return ByteString::formatted("TEXT {}", serialize_astring(x.text)); },
  170. [&](To const& x) { return ByteString::formatted("TO {}", serialize_astring(x.to)); },
  171. [&](UID const& x) { return ByteString::formatted("UID {}", x.uid); },
  172. [&](Unanswered const&) { return ByteString("UNANSWERED"); },
  173. [&](Undeleted const&) { return ByteString("UNDELETED"); },
  174. [&](Undraft const&) { return ByteString("UNDRAFT"); },
  175. [&](Unkeyword const& x) { return ByteString::formatted("UNKEYWORD {}", serialize_astring(x.flag_keyword)); },
  176. [&](Unseen const&) { return ByteString("UNSEEN"); });
  177. }
  178. }