}
}
}
+}
+
+gsize
+rspamd_strip_smtp_comments_inplace (gchar *input, gsize len)
+{
+ enum parser_state {
+ parse_normal,
+ parse_obrace,
+ parse_comment,
+ parse_quoted_copy,
+ parse_quoted_ignore,
+ } state = parse_normal, next_state = parse_normal;
+ gchar *d = input, *end = input + len, *start = input;
+ gchar t;
+ int obraces = 0, ebraces = 0;
+
+ while (input < end) {
+ t = *input;
+ switch (state) {
+ case parse_normal:
+ if (t == '(') {
+ state = parse_obrace;
+ }
+ else if (t == '\\') {
+ state = parse_quoted_copy;
+ next_state = parse_normal;
+ }
+ else {
+ *d++ = t;
+ }
+ input ++;
+ break;
+ case parse_obrace:
+ obraces ++;
+ if (t == '(') {
+ obraces ++;
+ }
+ else if (t == ')') {
+ ebraces ++;
+
+ if (obraces == ebraces) {
+ obraces = 0;
+ ebraces = 0;
+ state = parse_normal;
+ }
+ }
+ else if (t == '\\') {
+ state = parse_quoted_ignore;
+ next_state = parse_comment;
+ }
+ else {
+ state = parse_comment;
+ }
+ input ++;
+ break;
+ case parse_comment:
+ if (t == '(') {
+ state = parse_obrace;
+ }
+ else if (t == ')') {
+ ebraces ++;
+
+ if (obraces == ebraces) {
+ obraces = 0;
+ ebraces = 0;
+ state = parse_normal;
+ }
+ }
+ else if (t == '\\') {
+ state = parse_quoted_ignore;
+ next_state = parse_comment;
+ }
+ input ++;
+ break;
+ case parse_quoted_copy:
+ *d++ = t;
+ state = next_state;
+ input ++;
+ break;
+ case parse_quoted_ignore:
+ state = next_state;
+ input ++;
+ break;
+ }
+ }
+
+ return (d - start);
}
\ No newline at end of file
--- /dev/null
+/*-
+ * Copyright 2021 Vsevolod Stakhov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Detached unit tests for the utils */
+
+#ifndef RSPAMD_RSPAMD_CXX_UNIT_UTILS_HXX
+#define RSPAMD_RSPAMD_CXX_UNIT_UTILS_HXX
+
+#define DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL
+#include "doctest/doctest.h"
+
+#include "libmime/mime_headers.h"
+#include <vector>
+#include <utility>
+#include <string>
+
+TEST_CASE("rspamd_strip_smtp_comments_inplace") {
+ std::vector<std::pair<std::string, std::string>> cases{
+ {"abc", "abc"},
+ {"abc(foo)", "abc"},
+ {"abc(foo()", "abc"},
+ {"abc(foo))", "abc)"},
+ {"abc(foo(bar))", "abc"},
+ {"(bar)abc(foo)", "abc"},
+ {"ab(ololo)c(foo)", "abc"},
+ {"ab(trol\\\1lo)c(foo)", "abc"},
+ {"\\ab(trol\\\1lo)c(foo)", "abc"},
+ };
+
+ for (const auto &c : cases) {
+ auto *cpy = new char[c.first.size()];
+ memcpy(cpy, c.first.data(), c.first.size());
+ auto nlen = rspamd_strip_smtp_comments_inplace(cpy, c.first.size());
+ CHECK(std::string{cpy,nlen} == c.second);
+ }
+}
+
+#endif