@@ -397,8 +397,6 @@ static constexpr HXoption g_options_table[] = {
397397 HXOPT_AUTOHELP,
398398 HXOPT_TABLEEND,
399399};
400- static constexpr static_module g_dfl_svc_plugins[] =
401- {{" libgxs_mysql_adaptor.so" , SVC_mysql_adaptor}};
402400
403401static int main (int argc, char **argv)
404402{
@@ -411,12 +409,6 @@ static int main(int argc, char **argv)
411409 return EXIT_PARAM;
412410 }
413411 textmaps_init ();
414- service_init ({nullptr , g_dfl_svc_plugins, 1 });
415- auto cl_0 = make_scope_exit (service_stop);
416- if (service_run_early () != 0 || service_run () != 0 ) {
417- fprintf (stderr, " service_run: failed\n " );
418- return EXIT_FAILURE;
419- }
420412 if (!mysql_adaptor_set_user_lang (g_dstuser.c_str (), g_language)) {
421413 fprintf (stderr, " Update of UI language rejected\n " );
422414 return EXIT_FAILURE;
@@ -640,7 +632,7 @@ static int main(int argc, char **argv)
640632
641633}
642634
643- namespace for_all_wrap {
635+ namespace foreach_wrap {
644636
645637static unsigned int g_numthreads = 1 ;
646638static constexpr HXoption g_options_table[] = {
@@ -651,29 +643,81 @@ static constexpr HXoption g_options_table[] = {
651643
652644static int help ()
653645{
654- fprintf (stderr, " Usage: for-all-users [-j jobs] command [args...]\n " );
646+ fprintf (stderr, " Usage: foreach[.filter]* [-j jobs] command [args...]\n " );
647+ fprintf (stderr, " filter := secobj | user | mlist | sharedmb | contact |\n " );
648+ fprintf (stderr, " active | susp | deleted | mb\n " );
655649 global::command_overview ();
656650 return EXIT_PARAM;
657651}
658652
653+ static int filter_users (const char *mode, std::vector<sql_user> &ul)
654+ {
655+ if (strcmp (mode, " for-all-users" ) == 0 )
656+ return 0 ;
657+ if (strncmp (mode, " foreach." , 8 ) != 0 ) {
658+ mlog (LV_ERR, " Unknown command: %s" , mode);
659+ return -1 ;
660+ }
661+ std::string this_server;
662+ auto err = canonical_hostname (this_server);
663+ if (err != 0 ) {
664+ mlog (LV_ERR, " canonical_hostname: %s" , strerror (err));
665+ return err;
666+ }
667+
668+ const char *dot = " " ;
669+ for (mode += 8 ; dot != nullptr ; mode = dot + 1 ) {
670+ dot = strchr (mode, ' .' );
671+ auto filter = dot != nullptr ? std::string_view{mode, static_cast <size_t >(dot - mode)} :
672+ std::string_view{mode};
673+ if (filter == " secobj" )
674+ continue ;
675+ else if (filter == " user" )
676+ std::erase_if (ul, [](const sql_user &u) { return (u.dtypx & DTE_MASK_LOCAL) != DT_MAILUSER; });
677+ else if (filter == " dl" )
678+ std::erase_if (ul, [](const sql_user &u) { return (u.dtypx & DTE_MASK_LOCAL) != DT_DISTLIST; });
679+ else if (filter == " sharedmb" )
680+ std::erase_if (ul, [](const sql_user &u) { return (u.addr_status & AF_USER__MASK) != AF_USER_SHAREDMBOX; });
681+ else if (filter == " contact" )
682+ std::erase_if (ul, [](const sql_user &u) { return (u.addr_status & AF_USER__MASK) != AF_USER_CONTACT || (u.dtypx & DTE_MASK_LOCAL) != DT_REMOTE_MAILUSER; });
683+ else if (filter == " active" )
684+ std::erase_if (ul, [](const sql_user &u) { return (u.addr_status & AF_USER__MASK) != AF_USER_NORMAL; });
685+ else if (filter == " susp" )
686+ std::erase_if (ul, [](const sql_user &u) { return (u.addr_status & AF_USER__MASK) != AF_USER_SUSPENDED; });
687+ else if (filter == " deleted" )
688+ std::erase_if (ul, [](const sql_user &u) { return (u.addr_status & AF_USER__MASK) != AF_USER_DELETED; });
689+ else if (filter == " mb" )
690+ std::erase_if (ul, [](const sql_user &u) { return u.maildir .empty (); });
691+ else if (filter == " local" )
692+ std::erase_if (ul, [&](const sql_user &u) { return strcasecmp (u.homeserver .c_str (), this_server.c_str ()) != 0 ; });
693+ else {
694+ mlog (LV_ERR, " Unknown filter: %.*s\n " , static_cast <int >(filter.size ()), filter.data ());
695+ return -1 ;
696+ }
697+ }
698+ return 0 ;
699+ }
700+
659701static int main (int argc, char **argv)
660702{
661703 if (HX_getopt5 (g_options_table, argv, &argc, &argv,
662704 HXOPT_RQ_ORDER | HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS)
663705 return EXIT_PARAM;
664706 auto cl_0 = make_scope_exit ([=]() { HX_zvecfree (argv); });
665707 if (global::g_arg_username != nullptr || global::g_arg_userdir != nullptr ) {
666- fprintf (stderr, " Cannot use -d/-u with for-all-users \n " );
708+ fprintf (stderr, " Cannot use -d/-u with foreach.* \n " );
667709 return EXIT_PARAM;
668710 } else if (g_numthreads == 0 ) {
669711 g_numthreads = gx_concurrency ();
670712 }
713+ auto fe_mode = argv[0 ];
671714 --argc;
672715 ++argv;
673716 if (argc == 0 )
674717 return help ();
675- gi_user_list_t ul;
676- if (gi_get_users (ul) != 0 )
718+
719+ std::vector<sql_user> ul;
720+ if (mysql_adaptor_mbop_userlist (ul) != 0 || filter_users (fe_mode, ul) != 0 )
677721 return EXIT_FAILURE;
678722 auto ret = gi_startup_client (g_numthreads);
679723 if (ret != 0 )
@@ -688,49 +732,49 @@ static int main(int argc, char **argv)
688732 if (HX_getopt5 (empty_options_table, argv, nullptr , nullptr ,
689733 HXOPT_RQ_ORDER | HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS)
690734 return EXIT_PARAM;
691- for (auto &&[username, maildir] : ul) {
735+ for (const auto &user : ul) {
692736 sem.acquire ();
693737 if (ret != EXIT_SUCCESS && !global::g_continuous_mode)
694738 break ;
695- futs.emplace_back (std::async ([](std::string *maildir, Sem *sem, int *ret) {
739+ futs.emplace_back (std::async ([](const std::string *maildir, Sem *sem, int *ret) {
696740 if (!exmdb_client::ping_store (maildir->c_str ()))
697741 *ret = EXIT_FAILURE;
698742 sem->release ();
699- }, &maildir, &sem, &ret));
743+ }, &user. maildir , &sem, &ret));
700744 }
701745 } else if (strcmp (argv[0 ], " unload" ) == 0 ) {
702746 if (HX_getopt5 (empty_options_table, argv, nullptr , nullptr ,
703747 HXOPT_RQ_ORDER | HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS)
704748 return EXIT_PARAM;
705- for (auto &&[username, maildir] : ul) {
749+ for (const auto &user : ul) {
706750 sem.acquire ();
707751 if (ret != EXIT_SUCCESS && !global::g_continuous_mode)
708752 return ret;
709- futs.emplace_back (std::async ([](std::string *maildir, Sem *sem, int *ret) {
753+ futs.emplace_back (std::async ([](const std::string *maildir, Sem *sem, int *ret) {
710754 if (!exmdb_client::unload_store (maildir->c_str ()))
711755 *ret = EXIT_FAILURE;
712756 sem->release ();
713- }, &maildir, &sem, &ret));
757+ }, &user. maildir , &sem, &ret));
714758 }
715759 } else if (strcmp (argv[0 ], " vacuum" ) == 0 ) {
716760 if (HX_getopt5 (empty_options_table, argv, nullptr , nullptr ,
717761 HXOPT_RQ_ORDER | HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS)
718762 return EXIT_PARAM;
719- for (auto &&[username, maildir] : ul) {
763+ for (const auto &user : ul) {
720764 sem.acquire ();
721765 if (ret != EXIT_SUCCESS && !global::g_continuous_mode)
722766 return ret;
723- futs.emplace_back (std::async ([](std::string *maildir, Sem *sem, int *ret) {
767+ futs.emplace_back (std::async ([](const std::string *maildir, Sem *sem, int *ret) {
724768 if (!exmdb_client::vacuum (maildir->c_str ()))
725769 *ret = EXIT_FAILURE;
726770 sem->release ();
727- }, &maildir, &sem, &ret));
771+ }, &user. maildir , &sem, &ret));
728772 }
729773 } else {
730- for (auto &&[username, maildir] : ul) {
774+ for (auto &&user : ul) {
731775 /* cmd_parser is not thread-safe (global state), cannot parallelize */
732- g_dstuser = std::move (username);
733- g_storedir_s = std::move (maildir);
776+ g_dstuser = std::move (user. username );
777+ g_storedir_s = std::move (user. maildir );
734778 g_storedir = g_storedir_s.c_str ();
735779 ret = global::cmd_parser (argc, argv);
736780 if (ret == EXIT_PARAM)
@@ -962,6 +1006,9 @@ static int single_user_wrap(int argc, char **argv)
9621006 return ret;
9631007}
9641008
1009+ static constexpr static_module g_dfl_svc_plugins[] =
1010+ {{" libgxs_mysql_adaptor.so" , SVC_mysql_adaptor}};
1011+
9651012int main (int argc, char **argv)
9661013{
9671014 setvbuf (stdout, nullptr , _IOLBF, 0 );
@@ -973,8 +1020,15 @@ int main(int argc, char **argv)
9731020 ++argv;
9741021 if (argc == 0 )
9751022 return global::help ();
976- if (strcmp (argv[0 ], " for-all-users" ) == 0 )
977- return for_all_wrap::main (argc, argv);
1023+ service_init ({nullptr , g_dfl_svc_plugins, 1 });
1024+ auto cl_1 = make_scope_exit (service_stop);
1025+ if (service_run_early () != 0 || service_run () != 0 ) {
1026+ fprintf (stderr, " service_run: failed\n " );
1027+ return EXIT_FAILURE;
1028+ }
1029+ if (strncmp (argv[0 ], " foreach." , 8 ) == 0 ||
1030+ strncmp (argv[0 ], " for-all-" , 8 ) == 0 )
1031+ return foreach_wrap::main (argc, argv);
9781032 else
9791033 return single_user_wrap (argc, argv);
9801034}
0 commit comments