Skip to content

Commit 095ab7b

Browse files
committed
imap: replace dir_tree backing by std::map
Fixes: gromox-0~666
1 parent b7a8696 commit 095ab7b

File tree

2 files changed

+46
-128
lines changed

2 files changed

+46
-128
lines changed

mra/imap/cmd.cpp

Lines changed: 46 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <cstdio>
1515
#include <cstring>
1616
#include <fcntl.h>
17+
#include <map>
1718
#include <memory>
1819
#include <string>
1920
#include <unistd.h>
@@ -62,19 +63,38 @@ using mdi_list = std::vector<std::string>; /* message data item (RFC 3501 §6.4.
6263
namespace {
6364

6465
struct dir_tree {
66+
struct cmp {
67+
inline bool operator()(const std::string &a, const std::string &b) const { return strcasecmp(a.c_str(), b.c_str()) < 0; }
68+
};
69+
6570
dir_tree() = default;
66-
~dir_tree();
67-
NOMOVE(dir_tree);
6871

69-
void load_from_memfile(const std::vector<enum_folder_t> &);
70-
DIR_NODE *match(const char *path);
71-
static DIR_NODE *get_child(DIR_NODE *);
72-
bool has_children(DIR_NODE *x) const { return get_child(x) != nullptr; }
72+
template<typename Vec> void load_from_memfile(Vec &&pfile) try
73+
{
74+
for (auto &&[id, orig] : std::forward<Vec>(pfile)) {
75+
auto curr = this;
76+
constexpr bool inplace_edit = std::is_rvalue_reference<Vec>::value;
77+
using ref_or_copy = typename std::conditional<inplace_edit, std::string &, std::string>::type;
78+
ref_or_copy name{orig};
79+
char *saveptr = nullptr;
80+
81+
for (auto token = strtok_r(name.data(), "/", &saveptr);
82+
token != nullptr;
83+
token = strtok_r(nullptr, "/", &saveptr)) {
84+
auto [it, added] = curr->entries.try_emplace(token);
85+
curr = &it->second;
86+
}
87+
}
88+
} catch (const std::bad_alloc &) {
89+
mlog(LV_ERR, "E-2903: ENOMEM");
90+
}
91+
92+
const dir_tree *match(const char *path) const;
93+
dir_tree *match(const char *path) { return const_cast<dir_tree *>(const_cast<const dir_tree *>(this)->match(path)); }
94+
bool has_children() const { return entries.size() > 0; }
7395

74-
SIMPLE_TREE stree{};
96+
std::map<std::string, dir_tree, cmp> entries;
7597
};
76-
using DIR_TREE = dir_tree;
77-
using DIR_TREE_ENUM = void (*)(DIR_NODE *, void*);
7898

7999
enum {
80100
TYPE_WILDS = 1,
@@ -98,121 +118,25 @@ static constexpr const builtin_folder g_folder_list[] = {
98118
{PRIVATE_FID_JUNK, "\\Junk \\Spam"},
99119
};
100120

101-
void dir_tree::load_from_memfile(const std::vector<enum_folder_t> &pfile) try
102-
{
103-
auto ptree = this;
104-
char *ptr1, *ptr2;
105-
char temp_path[4096 + 1];
106-
SIMPLE_TREE_NODE *pnode, *pnode_parent;
107-
108-
auto proot = ptree->stree.get_root();
109-
if (NULL == proot) {
110-
auto pdir = std::make_unique<DIR_NODE>();
111-
pdir->stree.pdata = pdir.get();
112-
pdir->name[0] = '\0';
113-
pdir->b_loaded = TRUE;
114-
proot = &pdir->stree;
115-
ptree->stree.set_root(std::move(pdir));
116-
}
117-
118-
for (const auto &pfile_path : pfile) {
119-
gx_strlcpy(temp_path, pfile_path.second.c_str(), std::size(temp_path));
120-
auto len = strlen(temp_path);
121-
pnode = proot;
122-
if (len == 0 || temp_path[len-1] != '/') {
123-
temp_path[len++] = '/';
124-
temp_path[len] = '\0';
125-
}
126-
ptr1 = temp_path;
127-
while ((ptr2 = strchr(ptr1, '/')) != NULL) {
128-
*ptr2 = '\0';
129-
pnode_parent = pnode;
130-
pnode = pnode->get_child();
131-
if (NULL != pnode) {
132-
do {
133-
auto pdir = static_cast<DIR_NODE *>(pnode->pdata);
134-
if (strcasecmp(pdir->name, ptr1) == 0)
135-
break;
136-
} while ((pnode = pnode->get_sibling()) != nullptr);
137-
}
138-
139-
if (NULL == pnode) {
140-
auto pdir = std::make_unique<DIR_NODE>();
141-
pdir->stree.pdata = pdir.get();
142-
gx_strlcpy(pdir->name, ptr1, std::size(pdir->name));
143-
pdir->b_loaded = FALSE;
144-
pnode = &pdir->stree;
145-
ptree->stree.add_child(pnode_parent,
146-
std::move(pdir), SIMPLE_TREE_ADD_LAST);
147-
}
148-
ptr1 = ptr2 + 1;
149-
}
150-
static_cast<DIR_NODE *>(pnode->pdata)->b_loaded = TRUE;
151-
}
152-
} catch (const std::bad_alloc &) {
153-
mlog(LV_ERR, "E-2903: ENOMEM");
154-
}
155-
156-
static void dir_tree_clear(DIR_TREE *ptree)
157-
{
158-
auto pnode = ptree->stree.get_root();
159-
if (pnode != nullptr)
160-
ptree->stree.destroy_node(pnode, [](tree_node *p) { delete static_cast<DIR_NODE *>(p->pdata); });
161-
}
162-
163-
DIR_NODE *dir_tree::match(const char *path)
121+
const dir_tree *dir_tree::match(const char *path) const
164122
{
165-
auto ptree = this;
166-
int len;
167-
DIR_NODE *pdir = nullptr;
168-
char *ptr1, *ptr2;
169-
char temp_path[4096 + 1];
170-
171-
auto pnode = ptree->stree.get_root();
172-
if (pnode == nullptr)
173-
return NULL;
123+
auto curr = this;
174124
if (*path == '\0')
175-
return static_cast<DIR_NODE *>(pnode->pdata);
176-
len = strlen(path);
125+
return curr;
126+
auto len = strlen(path);
177127
if (len >= 4096)
178128
return NULL;
179-
memcpy(temp_path, path, len);
180-
if (temp_path[len-1] != '/')
181-
temp_path[len++] = '/';
182-
temp_path[len] = '\0';
183-
184-
ptr1 = temp_path;
185-
for (unsigned int level = 0; (ptr2 = strchr(ptr1, '/')) != nullptr; ++level) {
186-
*ptr2 = '\0';
187-
pnode = pnode->get_child();
188-
if (pnode == nullptr)
189-
return NULL;
190-
do {
191-
pdir = static_cast<DIR_NODE *>(pnode->pdata);
192-
if (strcasecmp(pdir->name, ptr1) == 0)
193-
break;
194-
if (level == 0 && strcasecmp(pdir->name, "INBOX") == 0 &&
195-
strcasecmp(ptr1, "inbox") == 0)
196-
break;
197-
} while ((pnode = pnode->get_sibling()) != nullptr);
198-
if (pnode == nullptr)
129+
std::string temp_path(path, len);
130+
char *saveptr = nullptr;
131+
for (auto token = strtok_r(temp_path.data(), "/", &saveptr);
132+
token != nullptr;
133+
token = strtok_r(nullptr, "/", &saveptr)) {
134+
auto it = curr->entries.find(token);
135+
if (it == curr->entries.cend())
199136
return NULL;
200-
ptr1 = ptr2 + 1;
137+
curr = &it->second;
201138
}
202-
return pdir;
203-
}
204-
205-
DIR_NODE *dir_tree::get_child(DIR_NODE* pdir)
206-
{
207-
auto pnode = pdir->stree.get_child();
208-
return pnode != nullptr ? static_cast<DIR_NODE *>(pnode->pdata) : nullptr;
209-
}
210-
211-
dir_tree::~dir_tree()
212-
{
213-
auto ptree = this;
214-
dir_tree_clear(ptree);
215-
ptree->stree.clear();
139+
return curr;
216140
}
217141

218142
static const builtin_folder *special_folder(uint64_t fid)
@@ -1621,7 +1545,7 @@ int icp_delete(int argc, char **argv, imap_context &ctx)
16211545
auto dh = folder_tree.match(argv[2]);
16221546
if (dh == nullptr)
16231547
return 1925;
1624-
if (folder_tree.has_children(dh))
1548+
if (dh->has_children())
16251549
return 1924;
16261550
}
16271551

@@ -1763,7 +1687,7 @@ int icp_list(int argc, char **argv, imap_context &ctx) try
17631687
if (!icp_wildcard_match(sys_name.c_str(), search_pattern.c_str()))
17641688
continue;
17651689
auto pdir = folder_tree.match(sys_name.c_str());
1766-
auto have_cld = pdir != nullptr && folder_tree.has_children(pdir);
1690+
auto have_cld = pdir != nullptr && pdir->has_children();
17671691
auto buf = fmt::format("* LIST (\\Has{}Children{}{}) \"/\" {}\r\n",
17681692
have_cld ? "" : "No",
17691693
return_special && special != nullptr ? " " : "",
@@ -1816,7 +1740,7 @@ int icp_xlist(int argc, char **argv, imap_context &ctx) try
18161740
continue;
18171741
auto special = special_folder(fentry.first);
18181742
auto pdir = folder_tree.match(sys_name.c_str());
1819-
auto have = pdir != nullptr && folder_tree.has_children(pdir);
1743+
auto have = pdir != nullptr && pdir->has_children();
18201744
auto buf = fmt::format("* XLIST (\\Has{}Children{}{}) \"/\" {}\r\n",
18211745
have ? "" : "No",
18221746
special != nullptr ? " " : "",
@@ -1880,7 +1804,7 @@ int icp_lsub(int argc, char **argv, imap_context &ctx) try
18801804
if (!icp_wildcard_match(sys_name.c_str(), search_pattern.c_str()))
18811805
continue;
18821806
auto pdir = folder_tree.match(sys_name.c_str());
1883-
auto have = pdir != nullptr && folder_tree.has_children(pdir);
1807+
auto have = pdir != nullptr && pdir->has_children();
18841808
auto buf = fmt::format("* LSUB (\\Has{}Children) \"/\" {}\r\n",
18851809
have ? "" : "No", quote_encode(sys_name));
18861810
if (pcontext->stream.write(buf.c_str(), buf.size()) != STREAM_WRITE_OK)

mra/imap/imap.hpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,6 @@ struct MJSON_MIME;
6363
struct XARRAY;
6464
struct XARRAY_UNIT;
6565

66-
struct DIR_NODE {
67-
SIMPLE_TREE_NODE stree;
68-
BOOL b_loaded;
69-
char name[256];
70-
};
71-
7266
struct imap_context;
7367
struct content_array final : public XARRAY {
7468
using XARRAY::XARRAY;

0 commit comments

Comments
 (0)