void load_helper_modules (void)
{
    SCIM_DEBUG_MAIN (1) << "load_helper_modules ()\n";

    std::vector <String> mod_list;

    scim_get_helper_module_list (mod_list);

    if (mod_list.size ()) {
        HelperModule module;

        for (size_t i = 0; i < mod_list.size (); ++i) {

            SCIM_DEBUG_MAIN (2) << " Load module: " << mod_list [i] << "\n";

            if (module.load (mod_list [i]) && module.valid ()) {
                HelperInfo info;
                size_t num = module.number_of_helpers ();

                SCIM_DEBUG_MAIN (2) << " Find " << num << " Helpers:\n";

                for (size_t j = 0; j < num; ++j) {
                    if (module.get_helper_info (j, info)) {
                        SCIM_DEBUG_MAIN (3) << "  " << info.uuid << ": " << info.name << "\n";
                        __helpers.push_back ( std::make_pair (info, mod_list [i]) );
                    }
                }
            }

            module.unload ();
        }
    }
}
void get_helper_list (const Socket &client)
{
    HelperRepository::iterator it = __helpers.begin ();

    __send_trans.clear ();
    __send_trans.put_command (SCIM_TRANS_CMD_REPLY);
    __send_trans.put_data ((uint32)__helpers.size ());

    for (; it != __helpers.end (); ++it) {
        __send_trans.put_data (it->first.uuid);
        __send_trans.put_data (it->first.name);
        __send_trans.put_data (it->first.icon);
        __send_trans.put_data (it->first.description);
        __send_trans.put_data (it->first.option);
    }

    __send_trans.write_to_socket (client);
}
void load_helper_modules (void)
{
    SCIM_DEBUG_MAIN (1) << "load_helper_modules ()\n";

    std::vector <String> mod_list;

    scim_get_helper_module_list (mod_list);

    // NOTE on FreeBSD if some module is loaded and unloaded right away here the following module crashes for some unknown reason
    //      seems like some damage is being done by module.unload();
    //      so I added a workaround: have an array of modules and unload them all together in the end only.
    //      TODO Need to figure out what's going on with this issue.

    if (mod_list.size ()) {

        HelperModule *module = new HelperModule[mod_list.size ()];

        for (size_t i = 0; i < mod_list.size (); ++i) {

            SCIM_DEBUG_MAIN (2) << " Load module: " << mod_list [i] << "\n";

            if (module[i].load (mod_list [i]) && module[i].valid ()) {
                HelperInfo info;
                size_t num = module[i].number_of_helpers ();

                SCIM_DEBUG_MAIN (2) << " Find " << num << " Helpers:\n";

                for (size_t j = 0; j < num; ++j) {
                    if (module[i].get_helper_info (j, info)) {
                        SCIM_DEBUG_MAIN (3) << "  " << info.uuid << ": " << info.name << "\n";
                        __helpers.push_back ( std::make_pair (info, mod_list [i]) );
                    }
                }
            }
        }
        for (size_t i = 0; i < mod_list.size (); ++i) {
            module[i].unload ();
        }
        delete[] module;
    }
}
void run_helper (const String &uuid, const String &config, const String &display)
{
    SCIM_DEBUG_MAIN(1) << "run_helper (" << uuid << "," << config << "," << display << ")\n";

    for (size_t i = 0; i < __helpers.size (); ++i) {
        if (__helpers [i].first.uuid == uuid && __helpers [i].second.length ()) {

            int pid;

            pid = fork ();

            if (pid < 0) return;

            if (pid == 0) {
                char * argv [] = { SCIM_HELPER_LAUNCHER_PROGRAM,
                                   "--daemon",
                                   "--config", const_cast<char*> (config.c_str ()),
                                   "--display", const_cast<char*> (display.c_str ()),
                                   const_cast<char*> (__helpers [i].second.c_str ()),
                                   const_cast<char*> (__helpers [i].first.uuid.c_str ()),
                                   0};

                SCIM_DEBUG_MAIN(2) << " Call scim-helper-launcher.\n";

                execv (SCIM_HELPER_LAUNCHER_PROGRAM, argv);
                exit (-1);
            }

            int status;
            waitpid (pid, &status, 0);

            break;
        }
    }

    SCIM_DEBUG_MAIN(2) << " exit run_helper ().\n";
}