Skip to content

Commit fd55ae6

Browse files
committed
mbop: add sync_mailbox operation
Use a trivial connect+write and eschew midb_agent. References: GXH-192, GXL-630, DESK-3819
1 parent e38d485 commit fd55ae6

File tree

8 files changed

+132
-5
lines changed

8 files changed

+132
-5
lines changed

Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ gromox_mbck_SOURCES = tools/mbck.cpp
199199
gromox_mbck_LDADD = ${libHX_LIBS} ${fmt_LIBS} ${sqlite_LIBS} libgromox_common.la
200200
gromox_mbop_SOURCES = tools/genimport.cpp tools/genimport.hpp tools/mbop.hpp tools/mbop.cpp
201201
EXTRA_DIST += tools/mbop_delmsg.cpp tools/mbop_emptyfld.cpp tools/mbop_foreach.cpp tools/mbop_freebusy.cpp tools/mbop_locale.cpp tools/mbop_main.cpp tools/mbop_purge.cpp tools/staticnpmap.cpp
202-
gromox_mbop_LDADD = ${libHX_LIBS} ${mysql_LIBS} libgromox_common.la libgromox_exrpc.la libgromox_mapi.la libgxs_mysql_adaptor.la
202+
gromox_mbop_LDADD = ${libHX_LIBS} ${mysql_LIBS} libgromox_common.la libgromox_exrpc.la libgromox_mapi.la libgxs_mysql_adaptor.la libgxs_midb_agent.la
203203
gromox_mbsize_SOURCES = tools/mbsize.cpp
204204
gromox_mbsize_LDADD = ${sqlite_LIBS} libgromox_common.la
205205
gromox_mkmidb_SOURCES = tools/mkmidb.cpp tools/mkshared.cpp tools/mkshared.hpp

doc/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Enhancements:
3939
* dscli: try all oxdisco URLs until one succeeds
4040
* exmdb: support repeated import of permission data (e.g. from kdb2mt)
4141
* ews: create calendar item after accepting a MR with MacMail
42+
* mbop: new `sync-midb` subcommand to prebuild midb caches ahead of the first IMAP login
4243

4344
Fixes:
4445

doc/gromox-mbop.8

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ set\-photo: read user image from stdin and save to store
6969
set\-websettings, set\-websettings\-persistent, set\-websettings\-recipients:
7070
read new grommunio-web settings from stdin and save to store
7171
.IP \(bu 4
72+
sync\-midb: trigger a midb synchronization run
73+
.IP \(bu 4
7274
thaw: unfreeze a mailbox
7375
.IP \(bu 4
7476
unload: issue the "unload_store" RPC for a mailbox
@@ -323,6 +325,19 @@ Reads various grommunio-web settings from the store and dumps it to stdout.
323325
Causes the respective mailbox to be opened by the server. (Any request to the
324326
information storage server causes the respective mailbox to be opened; and ping
325327
is technically just a no-op request type.)
328+
.SH sync\-midb
329+
.SS Synopsis
330+
\fBsync-midb\fP [\fB\-f\fP \fIfolder_spec\fP]
331+
.SS Description
332+
Sends a request to midb for opening the mailbox and updating the midb-specific
333+
folder indices, as well as potentially building RFC5322 representations for
334+
newly-appeared messages. (Once the mailbox is open in midb, it uses
335+
asynchronous notifications to stay up to date.)
336+
.SS Options
337+
.TP
338+
\fB\-f\fP \fIfolder_spec\fP
339+
Forcibly rerun the sync routine for a single specific folder. See section
340+
"Folder specification". In addition, the special keyword "all" is recognized.
326341
.SH purge\-datafiles
327342
The "purge\-datafiles" RPC makes exmdb_provider remove attachment and content
328343
files from disk that are no longer referenced by any message.

exch/midb/mail_engine.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3550,12 +3550,20 @@ static int me_xunld(int argc, char **argv, int sockd)
35503550
* Request:
35513551
* X-RSYM <store-dir>
35523552
* Response:
3553-
* TRUE <0|1|2>
3553+
* TRUE 0: synchro failure
3554+
* TRUE 1: was loaded before (tracking changes live), now is synchronized
3555+
* TRUE 2: was unloaded before (not tracking), now is synchronized
35543556
*/
35553557
static int me_xrsym(int argc, char **argv, int sockd)
35563558
{
35573559
auto idb = me_peek_idb(argv[1]);
35583560
if (idb == nullptr) {
3561+
/*
3562+
* There is a time between me_peek_idb and me_get_idb that
3563+
* another thread may have invoked me_get_idb and already
3564+
* triggered an initial sync. Therefore, we are passing `true`
3565+
* here to force resync in any case.
3566+
*/
35593567
me_get_idb(argv[1], true);
35603568
return cmd_write(sockd, "TRUE 2\r\n");
35613569
} else if (!me_sync_mailbox(idb.get(), true)) {

include/gromox/midb_agent.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ extern GX_EXPORT int summary_folder(const char *path, const std::string &folder,
4646
extern GX_EXPORT int make_folder(const char *path, const std::string &folder, int *perrno);
4747
extern GX_EXPORT int remove_folder(const char *path, const std::string &folder, int *perrno);
4848
extern GX_EXPORT int ping_mailbox(const char *path, int *perrno);
49+
extern GX_EXPORT int sync_mailbox(const char *path, uint64_t folder_id, int *err);
4950
extern GX_EXPORT int rename_folder(const char *path, const std::string &src_name, const std::string &dst_name, int *perrno);
5051
extern GX_EXPORT int subscribe_folder(const char *path, const std::string &folder, int *perrno);
5152
extern GX_EXPORT int unsubscribe_folder(const char *path, const std::string &folder, int *perrno);

mra/midb_agent.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,33 @@ int ping_mailbox(const char *path, int *perrno)
745745
return MIDB_RDWR_ERROR;
746746
}
747747

748+
int sync_mailbox(const char *path, uint64_t folder_id, int *err)
749+
{
750+
auto conn = get_connection(path);
751+
if (conn == nullptr)
752+
return MIDB_NO_SERVER;
753+
char buf[1024];
754+
int len;
755+
if (folder_id == 0)
756+
len = gx_snprintf(buf, std::size(buf), "X-RSYM %s\r\n", path);
757+
else
758+
len = gx_snprintf(buf, std::size(buf), "X-RSYF %s %llu\r\n",
759+
path, static_cast<unsigned long long>(folder_id));
760+
auto ret = rw_command(conn->sockd, buf, len, std::size(buf));
761+
if (ret != 0)
762+
return ret;
763+
if (strncmp(buf, "TRUE", 4) == 0) {
764+
conn.reset();
765+
return MIDB_RESULT_OK;
766+
} else if (strncmp(buf, "FALSE ", 6) == 0) {
767+
conn.reset();
768+
if (err != nullptr)
769+
*err = strtol(&buf[6], nullptr, 0);
770+
return MIDB_RESULT_ERROR;
771+
}
772+
return MIDB_RDWR_ERROR;
773+
}
774+
748775
int rename_folder(const char *path, const std::string &src_name,
749776
const std::string &dst_name, int *perrno)
750777
{

tools/mbop.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ namespace foreach_wrap { extern int main(int, char **); }
2121
namespace getfreebusy { extern int main(int, char **); }
2222
namespace purgesoftdel { extern int main(int, char **); }
2323
namespace set_locale { extern int main(int, char **); }
24+
namespace sync_midb { extern int main(int, char **); }
2425

2526
namespace global {
2627

tools/mbop_main.cpp

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
#include <libHX/io.h>
1313
#include <libHX/option.h>
1414
#include <libHX/scope.hpp>
15+
#include <libHX/socket.h>
1516
#include <libHX/string.h>
1617
#include <gromox/exmdb_client.hpp>
1718
#include <gromox/exmdb_rpc.hpp>
19+
#include <gromox/fileio.h>
1820
#include <gromox/freebusy.hpp>
1921
#include <gromox/mapidefs.h>
2022
#include <gromox/mysql_adaptor.hpp>
@@ -211,6 +213,75 @@ static int freeze_main(int argc, char **argv)
211213

212214
}
213215

216+
namespace sync_midb {
217+
218+
static const char *g_folder_spec;
219+
static constexpr HXoption g_options_table[] = {
220+
{{}, 'f', HXTYPE_STRP, &g_folder_spec, {}, {}, {}, "Forcibly rescan this folder", "SPEC"},
221+
MBOP_AUTOHELP,
222+
HXOPT_TABLEEND,
223+
};
224+
225+
static int send_cmd(const char *host, uint16_t port, const std::string &cmd)
226+
{
227+
int fd = HX_inet_connect(host, port, 0);
228+
if (fd < 0) {
229+
fprintf(stderr, "connect [%s]:%hu: %s", host, port, strerror(errno));
230+
return -1;
231+
}
232+
std::unique_ptr<FILE, file_deleter> fp(fdopen(fd, "r+"));
233+
if (fp == nullptr) {
234+
perror("fdopen");
235+
return -1;
236+
}
237+
setvbuf(fp.get(), nullptr, _IOLBF, 0);
238+
hxmc_t *line = nullptr;
239+
auto cl_0 = HX::make_scope_exit([&]() { HXmc_free(line); });
240+
if (HX_getl(&line, fp.get()) == nullptr)
241+
return -1;
242+
if (strcmp(line, "OK\r\n") != 0) {
243+
fprintf(stderr, "No MIDB intro line received\n");
244+
return -1;
245+
}
246+
fprintf(fp.get(), "%s", cmd.c_str());
247+
if (HX_getl(&line, fp.get()) == nullptr) {
248+
fprintf(stderr, "MIDB connection aborted?!\n");
249+
return -1;
250+
}
251+
if (strncasecmp(line, "true", 4) == 0 && HX_isspace(line[4]))
252+
return 0;
253+
mbop_fprintf(stderr, "MIDB command unsuccessful\n");
254+
return 1;
255+
}
256+
257+
int main(int argc, char **argv)
258+
{
259+
HXopt6_auto_result argp;
260+
const char *host = "localhost";
261+
uint16_t port = 5555;
262+
263+
if (HX_getopt6(g_options_table, argc, argv, nullptr,
264+
HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS || g_exit_after_optparse)
265+
return EXIT_PARAM;
266+
267+
int ret;
268+
if (g_folder_spec == nullptr) {
269+
ret = send_cmd(host, port, "M-PING " + g_storedir_s + "\r\n");
270+
} else if (strcasecmp(g_folder_spec, "all") == 0) {
271+
ret = send_cmd(host, port, "X-RSYM " + g_storedir_s + "\r\n");
272+
} else {
273+
eid_t eid = gi_lookup_eid_by_name(g_storedir, g_folder_spec);
274+
if (eid == 0) {
275+
mbop_fprintf(stderr, "Not recognized/found: \"%s\"\n", g_folder_spec);
276+
return EXIT_FAILURE;
277+
}
278+
ret = send_cmd(host, port, "X-RSYF " + g_storedir_s + " " + std::to_string(eid.gcv()) + "\r\n");
279+
}
280+
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
281+
}
282+
283+
}
284+
214285
static errno_t resolvename(const GUID &guid, const char *name, bool create,
215286
uint16_t *out)
216287
{
@@ -426,8 +497,9 @@ static int single_user_wrap(int argc, char **argv)
426497
return ret;
427498
}
428499

429-
static constexpr generic_module g_dfl_svc_plugins[] =
430-
{{"libgxs_mysql_adaptor.so", SVC_mysql_adaptor}};
500+
static constexpr generic_module g_dfl_svc_plugins[] = {
501+
{"libgxs_mysql_adaptor.so", SVC_mysql_adaptor},
502+
};
431503

432504
int main(int argc, char **argv)
433505
{
@@ -447,7 +519,7 @@ int main(int argc, char **argv)
447519
argv = result.uarg;
448520
if (argc == 0)
449521
return global::help();
450-
service_init({nullptr, g_dfl_svc_plugins, 1});
522+
service_init({nullptr, g_dfl_svc_plugins, 2});
451523
auto cl_1 = HX::make_scope_exit(service_stop);
452524
if (service_run_early() != 0 || service_run() != 0) {
453525
fprintf(stderr, "service_run: failed\n");
@@ -535,6 +607,8 @@ int cmd_parser(int argc, char **argv)
535607
return set_locale::main(argc, argv);
536608
else if (strcmp(argv[0], "get-freebusy") == 0 || strcmp(argv[0], "gfb") == 0)
537609
return getfreebusy::main(argc, argv);
610+
else if (strcmp(argv[0], "sync-midb") == 0)
611+
return sync_midb::main(argc, argv);
538612

539613
if (strcmp(argv[0], "clear-profile") == 0) {
540614
auto ret = delstoreprop(argc, argv, PSETID_Gromox, "zcore_profsect", PT_BINARY);

0 commit comments

Comments
 (0)