diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-09-05 12:42:28 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-09-05 14:41:26 +0300 |
commit | 954d267b9de7abdfe9e73ce3372bbade918ebe1a (patch) | |
tree | d30b979408c0510e5b87fc0c0b2a1ac7eb75ffab | |
parent | aff3433b89e2fbeaddacf0e65ee105ba5a572ab7 (diff) | |
download | dico-954d267b9de7abdfe9e73ce3372bbade918ebe1a.tar.gz dico-954d267b9de7abdfe9e73ce3372bbade918ebe1a.tar.bz2 |
Implement virtual databases.
* dicod/virtual.c: New file.
* dicod/Makefile.am (dicod_SOURCES): Add virtual.c
* dicod/database.c (dicod_database_init): Pass db->extra to
dico_init_db method.
* dicod/dicod.h (option_mime): New extern.
(dicod_builtin_module_init)
(database_session_visibility): New protos.
(virtual_builtin_module): New extern.
* dicod/loader.c (dicod_builtin_module_init): New function.
* dicod/main.c: New database configuration setting: "database".
Configures component database for virtual databases.
* dicod/ostream.c (option_mime): Remove extern. Now defined in dicod.h
* dicod/tests/echo.c (echo_init_db): Change signature.
* include/dico/types.h (dico_init_db): Change signature. Takes an extra
argument now.
* modules/template/module.c: Update.
* doc/dico.texi: Document new features.
* NEWS: Version 2.6.90. Document changes.
* configure.boot: Version 2.6.90
-rw-r--r-- | NEWS | 25 | ||||
-rw-r--r-- | configure.boot | 2 | ||||
-rw-r--r-- | dicod/Makefile.am | 3 | ||||
-rw-r--r-- | dicod/database.c | 8 | ||||
-rw-r--r-- | dicod/dicod.h | 38 | ||||
-rw-r--r-- | dicod/loader.c | 139 | ||||
-rw-r--r-- | dicod/main.c | 262 | ||||
-rw-r--r-- | dicod/ostream.c | 2 | ||||
-rw-r--r-- | dicod/tests/echo.c | 2 | ||||
-rw-r--r-- | dicod/virtual.c | 290 | ||||
-rw-r--r-- | doc/dico.texi | 148 | ||||
-rw-r--r-- | include/dico/types.h | 3 | ||||
-rw-r--r-- | modules/template/module.c | 12 |
13 files changed, 776 insertions, 158 deletions
@@ -1,9 +1,32 @@ -GNU Dico NEWS -- history of user-visible changes. 2018-08-27 +GNU Dico NEWS -- history of user-visible changes. 2018-09-05 Copyright (C) 2008-2010, 2012-2018 Sergey Poznyakoff See the end of file for copying conditions. Please send Dico bug reports to <bug-dico@gnu.org.ua> +Version 2.6.90 (git) + +* Support for virtual databases + +Virtual databases include one or more of the regular databases defined +in the dicod configuration. They can be used to group databases by +languages, or to select the format of the DEFINE responses depending +on whether OPTION MIME has been requested. + +Example of defining a virtual database: + + database { + name "English Translating Database"; + info "Translations from English to other languages"; + handler "virtual"; + database "en-sw"; + database "en-no"; + database "en-pl"; + } + +See the GNU dico manual, subsection 4.3.12.2 "Virtual Databases" for a +detailed discussion. + Version 2.6, 2018-08-27 * Support for Guile 2.2.0 diff --git a/configure.boot b/configure.boot index 3ed63b8..5129ef7 100644 --- a/configure.boot +++ b/configure.boot @@ -28,7 +28,7 @@ dnl Process this file with -*- autoconf -*- to produce a configure script. # along with GNU Dico. If not, see <http://www.gnu.org/licenses/>. AC_PREREQ(2.63) -AC_INIT([GNU dico], 2.6, [bug-dico@gnu.org]) +AC_INIT([GNU dico], 2.6.90, [bug-dico@gnu.org]) AC_CONFIG_SRCDIR([dicod/main.c]) AM_CONFIG_HEADER(config.h) AC_CONFIG_AUX_DIR([build-aux]) diff --git a/dicod/Makefile.am b/dicod/Makefile.am index d21d2bc..462bcb8 100644 --- a/dicod/Makefile.am +++ b/dicod/Makefile.am @@ -43,7 +43,8 @@ dicod_SOURCES=\ stat.c\ stratcl.c\ xidle.c\ - xversion.c + xversion.c\ + virtual.c noinst_HEADERS=dicod.h diff --git a/dicod/database.c b/dicod/database.c index 0c9dc66..5231e78 100644 --- a/dicod/database.c +++ b/dicod/database.c @@ -30,8 +30,9 @@ dicod_database_init(dicod_database_t *db) if (inst->module->dico_init_db) { db->mod_handle = inst->module->dico_init_db(db->name, - db->argc, - db->argv); + db->argc, + db->argv, + db->extra); if (!db->mod_handle) { dico_log(L_ERR, 0, _("cannot initialize database `%s'"), db->command); @@ -48,8 +49,7 @@ dicod_database_open(dicod_database_t *db) if (inst->module->dico_open) { if (inst->module->dico_open(db->mod_handle)) { - dico_log(L_ERR, 0, _("cannot open database `%s'"), - db->command); + dico_log(L_ERR, 0, _("cannot open database `%s'"), db->command); return 1; } } diff --git a/dicod/dicod.h b/dicod/dicod.h index 90ff520..4c1e943 100644 --- a/dicod/dicod.h +++ b/dicod/dicod.h @@ -116,7 +116,7 @@ extern struct dico_stat current_stat, total_stat; #define DICTD_LOGGING_ENVAR "__DICTD_LOGGING__" -#define MODE_DAEMON 0 +#define MODE_DAEMON 0 #define MODE_INETD 1 #define MODE_PREPROC 2 #define MODE_TEST 3 @@ -148,7 +148,7 @@ extern dicod_acl_t connect_acl; typedef struct dicod_module_instance { char *ident; char *command; - struct dico_database_module *module; + struct dico_database_module *module; lt_dlhandle handle; } dicod_module_instance_t; @@ -156,28 +156,29 @@ typedef struct dicod_module_instance { typedef struct dicod_database { int flags; - + char *name; /* Dictionary name */ char *descr; /* Description (SHOW DB) */ char *info; /* Info (SHOW INFO) */ - + dico_list_t langlist[2]; /* List of "source/dest" languages */ - + dicod_acl_t acl; /* ACL for this database */ int visible; /* Is this database (administratively) visible */ int session_visible; /* Is this database visible in the current session. This depends on the value of visible and on the result of dicod_acl_check and dicod_lang_check */ - + dico_handle_t mod_handle; /* Dico module handle */ dico_assoc_list_t mime_headers; - + dicod_module_instance_t *instance; /* Pointer to the module instance structure */ int argc; /* Handler arguments: count */ char **argv; /* ... and pointers */ char *command; /* Handler command line (for diagnostics) */ + void *extra; } dicod_database_t; #define CONTENT_TRANSFER_ENCODING_HEADER "Content-transfer-encoding" @@ -243,6 +244,7 @@ void register_lang(void); int dicod_lang_check(dico_list_t list[2]); /* mime.c */ +extern int option_mime; void register_mime(void); /* markup.c */ @@ -288,6 +290,8 @@ void dicod_define_word_all(dico_stream_t stream, const char *word); int dicod_module_test(int argc, char **argv); +void dicod_builtin_module_init(void); + /* database.c */ int dicod_database_init(dicod_database_t *dp); int dicod_database_open(dicod_database_t *dp); @@ -307,7 +311,7 @@ size_t dicod_database_compare_count(dicod_database_t *db, dico_result_t res); void dicod_database_result_free(dicod_database_t *db, dico_result_t res); int dicod_database_result_output(dicod_database_t *db, dico_result_t res, size_t n, dico_stream_t str); - + dico_result_t dicod_database_match(dicod_database_t *db, const dico_strategy_t strat, const char *word); @@ -399,4 +403,22 @@ int dicod_check_password(const char *db_pass, const char *pass); /* main.c */ void config_help(void); +int database_session_visibility(dicod_database_t *db); + + +/* virtual.c */ +extern struct dico_database_module virtual_builtin_module; + +enum mime_cond { + cond_any = -1, + cond_mime, + cond_nomime +}; + +struct vdb_member { + char *name; + dicod_database_t *db; + int cond; +}; +dico_list_t vdb_list_create(void); diff --git a/dicod/loader.c b/dicod/loader.c index 89a40a1..459afbb 100644 --- a/dicod/loader.c +++ b/dicod/loader.c @@ -35,27 +35,56 @@ dicod_loader_init(void) #define MODULE_ASSERT(cond) \ if (!(cond)) { \ - lt_dlclose(handle); \ dico_log(L_ERR, 0, _("%s: faulty module: (%s) failed"), \ argv[0], \ - #cond); \ + #cond); \ return 1; \ } static int -dicod_load_module0(dicod_module_instance_t *inst, int argc, char **argv) +module_init(dicod_module_instance_t *inst, struct dico_database_module *pmod, + int argc, char **argv) +{ + MODULE_ASSERT(pmod); + MODULE_ASSERT(pmod->dico_version <= DICO_MODULE_VERSION); + if (pmod->dico_capabilities & DICO_CAPA_NODB) { + MODULE_ASSERT(pmod->dico_init); + } else { + MODULE_ASSERT(pmod->dico_init_db); + MODULE_ASSERT(pmod->dico_free_db); + MODULE_ASSERT(pmod->dico_match); + MODULE_ASSERT(pmod->dico_define); + MODULE_ASSERT(pmod->dico_output_result); + MODULE_ASSERT(pmod->dico_result_count); + MODULE_ASSERT(pmod->dico_free_result); + } + + if (pmod->dico_init && pmod->dico_init(argc, argv)) { + dico_log(L_ERR, 0, _("%s: initialization failed"), argv[0]); + return 1; + } + + inst->module = pmod; + return 0; +} + +static int +module_load(dicod_module_instance_t *inst, int argc, char **argv) { lt_dlhandle handle = NULL; lt_dladvise advise = NULL; - struct dico_database_module *pmod; + struct dico_database_module *pmod; if (inst->handle) { dico_log(L_ERR, 0, _("module %s already loaded"), argv[0]); return 1; } - + if (inst->module) + /* FIXME: Built-in module */ + return 0; + if (!lt_dladvise_init(&advise) && !lt_dladvise_ext(&advise) - && !lt_dladvise_global(&advise)) + && !lt_dladvise_global(&advise)) handle = lt_dlopenadvise(argv[0], advise); lt_dladvise_destroy(&advise); @@ -64,33 +93,16 @@ dicod_load_module0(dicod_module_instance_t *inst, int argc, char **argv) lt_dlerror()); return 1; } - + pmod = (struct dico_database_module *) lt_dlsym(handle, "module"); - MODULE_ASSERT(pmod); - MODULE_ASSERT(pmod->dico_version <= DICO_MODULE_VERSION); - if (pmod->dico_capabilities & DICO_CAPA_NODB) { - MODULE_ASSERT(pmod->dico_init); - } else { - MODULE_ASSERT(pmod->dico_init_db); - MODULE_ASSERT(pmod->dico_free_db); - MODULE_ASSERT(pmod->dico_match); - MODULE_ASSERT(pmod->dico_define); - MODULE_ASSERT(pmod->dico_output_result); - MODULE_ASSERT(pmod->dico_result_count); - MODULE_ASSERT(pmod->dico_free_result); - - if (pmod->dico_open || pmod->dico_close) - MODULE_ASSERT(pmod->dico_open && pmod->dico_close); - } - - if (pmod->dico_init && pmod->dico_init(argc, argv)) { + + if (module_init(inst, pmod, argc, argv)) { lt_dlclose(handle); - dico_log(L_ERR, 0, _("%s: initialization failed"), argv[0]); return 1; } inst->handle = handle; - inst->module = pmod; + return 0; } @@ -99,20 +111,43 @@ dicod_load_module(dicod_module_instance_t *inst) { struct wordsplit ws; int rc; - + if (wordsplit(inst->command, &ws, WRDSF_DEFFLAGS)) { dico_log(L_ERR, 0, _("cannot parse command line `%s': %s"), inst->command, wordsplit_strerror (&ws)); return 1; } - - rc = dicod_load_module0(inst, ws.ws_wordc, ws.ws_wordv); - + rc = module_load(inst, ws.ws_wordc, ws.ws_wordv); wordsplit_free(&ws); - return rc; } + +static void +builtin_module_load(char const *ident, struct dico_database_module *pmod) +{ + dicod_module_instance_t *inst = xzalloc(sizeof(*inst)); + char *argv[2]; + inst->ident = xstrdup(ident); + inst->command = xstrdup(ident); + argv[0] = inst->command; + argv[1] = NULL; + if (module_init(inst, pmod, 1, argv)) { + dico_log(L_CRIT, 0, + "INTERNAL ERROR: failed to load built-in module %s", + ident); + dico_log(L_CRIT, 0, "Please, report"); + abort(); + } + inst->handle = NULL; + xdico_list_append(modinst_list, inst); +} +void +dicod_builtin_module_init(void) +{ + builtin_module_load("virtual", &virtual_builtin_module); +} + static int _dup_lang_item(void *item, void *data) { @@ -173,11 +208,11 @@ dicod_word_first(dico_stream_t stream, const char *word, ? dicod_database_match(db, strat, word) : dicod_database_define(db, word); size_t count; - + if (!res) continue; count = dicod_database_result_count(db, res); - + if (count) { if (strat) current_stat.matches = count; @@ -220,7 +255,7 @@ dicod_word_all(dico_stream_t stream, const char *word, dico_list_t reslist = xdico_list_create(); size_t total = 0; struct dbres *rp; - + begin_timing(tid); if (strat && stratcl_check_word(strat->stratcl, word)) { @@ -236,7 +271,7 @@ dicod_word_all(dico_stream_t stream, const char *word, ? dicod_database_match(db, strat, word) : dicod_database_define(db, word); size_t count; - + if (!res) continue; count = dicod_database_result_count(db, res); @@ -262,7 +297,7 @@ dicod_word_all(dico_stream_t stream, const char *word, dico_stream_writeln(stream, nomatch, nomatch_len); } else { itr = xdico_list_iterator(reslist); - + if (strat) current_stat.matches = total; else @@ -289,7 +324,7 @@ print_matches(dicod_database_t *db, dico_result_t res, { size_t i; dico_stream_t ostr = data; - + for (i = 0; i < count; i++) { stream_writez(ostr, db->name); dico_stream_write(ostr, " \"", 2); @@ -304,11 +339,11 @@ dicod_match_word_db(dicod_database_t *db, dico_stream_t stream, { dico_result_t res; size_t count; - + begin_timing("match"); - + res = dicod_database_match(db, strat, word); - + if (!res) { access_log_status(nomatch, nomatch); dico_stream_writeln(stream, nomatch, nomatch_len); @@ -321,7 +356,7 @@ dicod_match_word_db(dicod_database_t *db, dico_stream_t stream, dico_stream_writeln(stream, nomatch, nomatch_len); } else { dico_stream_t ostr; - + current_stat.matches = count; current_stat.compares = dicod_database_compare_count(db, res); stream_printf(stream, "152 %lu matches found: list follows\n", @@ -337,7 +372,7 @@ dicod_match_word_db(dicod_database_t *db, dico_stream_t stream, dico_stream_write(stream, "\n", 1); access_log_status("152", "250"); } - + dicod_database_result_free(db, res); } @@ -368,8 +403,6 @@ dicod_match_word_all(dico_stream_t stream, dico_stream_close(ostr); dico_stream_destroy(&ostr); } - - static void print_definitions(dicod_database_t *db, dico_result_t res, @@ -382,7 +415,7 @@ print_definitions(dicod_database_t *db, dico_result_t res, for (i = 0; i < count; i++) { dico_stream_t ostr; dico_assoc_list_t hdr; - + stream_printf(stream, "151 \"%s\" %s \"%s\"\n", word, db->name, descr ? descr : ""); @@ -404,7 +437,7 @@ dicod_define_word_db(dicod_database_t *db, dico_stream_t stream, { dico_result_t res; size_t count; - + begin_timing("define"); res = dicod_database_define(db, word); @@ -429,7 +462,7 @@ dicod_define_word_db(dicod_database_t *db, dico_stream_t stream, dico_stream_write(stream, "\n", 1); access_log_status("150", "250"); } - + dicod_database_result_free(db, res); } @@ -456,8 +489,8 @@ dicod_module_test(int argc, char **argv) { int i; dicod_module_instance_t inst; - struct dico_database_module *pmod; - + struct dico_database_module *pmod; + /* Split arguments in two parts: unit test arguments and optional module initialization arguments */ for (i = 0; i < argc; i++) @@ -467,18 +500,18 @@ dicod_module_test(int argc, char **argv) if (i == 0) dico_die(EX_UNAVAILABLE, L_ERR, 0, _("no module name")); - + memset(&inst, 0, sizeof(inst)); if (i < argc) { argv[i] = argv[0]; - if (dicod_load_module0(&inst, argc - i, argv + i)) + if (module_load(&inst, argc - i, argv + i)) return 1; argv[i] = NULL; } else { char *null_argv[2]; null_argv[0] = argv[0]; null_argv[1] = NULL; - if (dicod_load_module0(&inst, 1, null_argv)) + if (module_load(&inst, 1, null_argv)) return 1; } diff --git a/dicod/main.c b/dicod/main.c index 341de5d..9c09b11 100644 --- a/dicod/main.c +++ b/dicod/main.c @@ -43,9 +43,9 @@ unsigned int shutdown_timeout = 5; /* Inactivity timeout */ unsigned int inactivity_timeout = 0; -/* Syslog parameters: */ +/* Syslog parameters: */ int log_to_stderr; /* Log to stderr */ -const char *log_tag; +const char *log_tag; int log_facility = LOG_FACILITY; int log_print_severity; int transcript; @@ -126,7 +126,7 @@ grecs_list_iterate(struct grecs_list *list, grecs_list_iterator_t fun, break; } } - + /* Configuration */ @@ -183,7 +183,7 @@ cb_dico_sockaddr_list(enum grecs_callback_command cmd, { dico_list_t *plist = varptr, list; struct grecs_sockaddr *sp; - + if (*plist) list = *plist; else { @@ -191,7 +191,7 @@ cb_dico_sockaddr_list(enum grecs_callback_command cmd, //FIXME dico_list_set_free_item(list, dicod_free_item, NULL); *plist = list; } - + switch (value->type) { case GRECS_TYPE_STRING: if (grecs_string_convert(&sp, grecs_type_sockaddr, @@ -278,10 +278,10 @@ acl_cb(enum grecs_callback_command cmd, { void **pdata = cb_data; dicod_acl_t acl; - + switch (cmd) { case grecs_callback_section_begin: - if (value->type != GRECS_TYPE_STRING) + if (value->type != GRECS_TYPE_STRING) grecs_error(locus, 0, _("ACL name must be a string")); else if (!value->v.string) grecs_error(locus, 0, _("missing ACL name")); @@ -303,7 +303,7 @@ acl_cb(enum grecs_callback_command cmd, case grecs_callback_section_end: case grecs_callback_set_value: break; - } + } return 0; } @@ -354,7 +354,7 @@ set_user(enum grecs_callback_command cmd, { struct passwd *pw; char *s; - + if (cmd != grecs_callback_set_value) { grecs_error(locus, 0, _("Unexpected block statement")); return 1; @@ -396,7 +396,7 @@ set_supp_group_iter(grecs_value_t *value, void *data) return set_supp_group(grecs_callback_set_value, &value->locus, NULL, value, NULL); } - + static int set_supp_group(enum grecs_callback_command cmd, grecs_locus_t *locus, @@ -413,13 +413,13 @@ set_supp_group(enum grecs_callback_command cmd, group_list = xdico_list_create(); dico_list_set_free_item(group_list, dicod_free_item, NULL); } - + if (value->type == GRECS_TYPE_LIST) grecs_list_iterate(value->v.list, set_supp_group_iter, NULL); else { char *s = value->v.string; gid_t gid, *gp; - + if (*s == '+') { char *q; unsigned long n = strtoul(s + 1, &q, 0); @@ -436,7 +436,7 @@ set_supp_group(enum grecs_callback_command cmd, } gid = group->gr_gid; } - + gp = xmalloc(sizeof(*gp)); *gp = gid; xdico_list_append(group_list, gp); @@ -456,7 +456,7 @@ set_mode(enum grecs_callback_command cmd, { "inetd", MODE_INETD }, { NULL } }; - + if (cmd != grecs_callback_set_value) { grecs_error(locus, 0, _("Unexpected block statement")); return 1; @@ -474,7 +474,7 @@ set_mode(enum grecs_callback_command cmd, } static struct xlat_tab syslog_facility_tab[] = { - { "USER", LOG_USER }, + { "USER", LOG_USER }, { "DAEMON", LOG_DAEMON }, { "AUTH", LOG_AUTH }, { "AUTHPRIV",LOG_AUTHPRIV }, @@ -530,9 +530,9 @@ cmp_modinst_ident(const void *item, void *data) static int _add_simple_module(grecs_value_t *value, void *unused_data) { - if (value->type != GRECS_TYPE_STRING) + if (value->type != GRECS_TYPE_STRING) grecs_error(&value->locus, 0, _("tag must be a string")); - else if (value->v.string == NULL) + else if (value->v.string == NULL) grecs_error(&value->locus, 0, _("missing tag")); else { dicod_module_instance_t *inst = xzalloc(sizeof(*inst)); @@ -552,30 +552,25 @@ load_module_cb(enum grecs_callback_command cmd, { dicod_module_instance_t *inst; void **pdata = cb_data; - - if (!modinst_list) { - modinst_list = xdico_list_create(); - dico_list_set_comparator(modinst_list, cmp_modinst_ident); - } - + switch (cmd) { case grecs_callback_section_begin: inst = xzalloc(sizeof(*inst)); - if (value->type != GRECS_TYPE_STRING) + if (value->type != GRECS_TYPE_STRING) grecs_error(locus, 0, _("tag must be a string")); - else if (value->v.string == NULL) + else if (value->v.string == NULL) grecs_error(locus, 0, _("missing tag")); else inst->ident = xstrdup(value->v.string); *pdata = inst; break; - + case grecs_callback_section_end: inst = *pdata; xdico_list_append(modinst_list, inst); *pdata = NULL; break; - + case grecs_callback_set_value: switch (value->type) { case GRECS_TYPE_STRING: @@ -598,14 +593,14 @@ cmp_database_name(const void *item, void *data) { const dicod_database_t *db = item; int rc; - + if (!db->name) return 1; rc = strcmp(db->name, (const char*)data); if (rc == 0 && !database_is_visible(db)) rc = 1; return rc; -} +} static int set_database(enum grecs_callback_command cmd, @@ -616,14 +611,14 @@ set_database(enum grecs_callback_command cmd, { dicod_database_t *dict; void **pdata = cb_data; - + switch (cmd) { case grecs_callback_section_begin: dict = xzalloc(sizeof(*dict)); dict->visible = 1; *pdata = dict; break; - + case grecs_callback_section_end: dict = *pdata; if (!dict->name) { @@ -631,6 +626,23 @@ set_database(enum grecs_callback_command cmd, break; } + if (!dict->instance) { + grecs_error(locus, 0, + _("no handler defined for the database")); + dicod_database_free(dict); + return 1; + } + + if (dict->extra) { + if (strcmp(dict->instance->ident, "virtual")) { + grecs_error(locus, 0, + _("expected handler \"virtual\", but found \"%s\""), + dict->instance->ident); + dicod_database_free(dict); + return 1; + } + } + if (!database_list) { database_list = xdico_list_create(); dico_list_set_comparator (database_list, cmp_database_name); @@ -638,11 +650,11 @@ set_database(enum grecs_callback_command cmd, if (dict->langlist[0] || dict->langlist[1]) /* Prevent dico_db_lang from being called */ dict->flags |= DICOD_DBF_LANG; - + xdico_list_append(database_list, dict); *pdata = NULL; break; - + case grecs_callback_set_value: grecs_error(locus, 0, _("invalid use of block statement")); } @@ -659,7 +671,7 @@ set_dict_handler(enum grecs_callback_command cmd, dicod_module_instance_t *inst; dicod_database_t *db = varptr; struct wordsplit ws; - + if (cmd != grecs_callback_set_value) { grecs_error(locus, 0, _("Unexpected block statement")); return 1; @@ -673,9 +685,9 @@ set_dict_handler(enum grecs_callback_command cmd, if (wordsplit(value->v.string, &ws, WRDSF_DEFFLAGS)) { grecs_error(locus, 0, _("cannot parse command line `%s': %s"), value->v.string, wordsplit_strerror (&ws)); - dicod_database_free(db); + dicod_database_free(db); return 1; - } + } db->argc = ws.ws_wordc; db->argv = ws.ws_wordv; @@ -692,7 +704,7 @@ set_dict_handler(enum grecs_callback_command cmd, return 1; } db->instance = inst; - + return 0; } @@ -722,7 +734,7 @@ enable_capability(enum grecs_callback_command cmd, } if (value->type == GRECS_TYPE_LIST) grecs_list_iterate(value->v.list, set_capability, locus); - else if (dicod_capa_add(value->v.string)) + else if (dicod_capa_add(value->v.string)) grecs_error(locus, 0, _("unknown capability: %s"), value->v.string); return 0; } @@ -736,7 +748,7 @@ mime_headers_cb (enum grecs_callback_command cmd, { dico_assoc_list_t *pasc = varptr; const char *enc; - + if (cmd != grecs_callback_set_value) { grecs_error(locus, 0, _("Unexpected block statement")); return 1; @@ -747,17 +759,17 @@ mime_headers_cb (enum grecs_callback_command cmd, return 1; } - if (dico_header_parse(pasc, value->v.string)) + if (dico_header_parse(pasc, value->v.string)) grecs_error(locus, 0, _("cannot parse headers: %s"), strerror(errno)); if ((enc = dico_assoc_find(*pasc, CONTENT_TRANSFER_ENCODING_HEADER))) { - if (!(strcmp(enc, "quoted-printable") == 0 + if (!(strcmp(enc, "quoted-printable") == 0 || strcmp(enc, "base64") == 0 || strcmp(enc, "8bit") == 0)) grecs_error(locus, 0, _("unknown encoding type: %s"), enc); } - + return 0; } @@ -768,6 +780,70 @@ struct grecs_keyword kwd_load_module[] = { { NULL } }; +int +member_database_cb(enum grecs_callback_command cmd, + grecs_locus_t *locus, + void *varptr, + grecs_value_t *value, + void *cb_data) +{ + dico_list_t *listptr = varptr; + char const *dbname; + enum mime_cond cond = cond_any; + grecs_value_t *vp; + struct vdb_member *memb; + + if (cmd != grecs_callback_set_value) { + grecs_error(locus, 0, _("Unexpected block statement")); + return 1; + } + + switch (value->type) { + case GRECS_TYPE_ARRAY: + if (value->v.arg.c != 2) { + grecs_error(locus, 0, _("too many arguments")); + return 1; + } + vp = value->v.arg.v[0]; + if (vp->type != GRECS_TYPE_STRING) { + grecs_error(locus, 0, _("first argument must be string")); + return 1; + } + dbname = vp->v.string; + vp = value->v.arg.v[1]; + if (vp->type != GRECS_TYPE_STRING) { + grecs_error(locus, 0, _("second argument must be string")); + return 1; + } + if (strcmp(vp->v.string, "mime") == 0) + cond = cond_mime; + else if (strcmp(vp->v.string, "nomime") == 0) + cond = cond_nomime; + else { + grecs_error(locus, 0, _("condition must be mime or nomime")); + return 1; + } + break; + + case GRECS_TYPE_STRING: + dbname = value->v.string; + break; + + default: + grecs_error(locus, 0, _("expected scalar value")); + return 1; + } + + if (!*listptr) + *listptr = vdb_list_create(); + + memb = xzalloc(sizeof(memb[0])); + memb->name = xstrdup(dbname); + memb->cond = cond; + xdico_list_append(*listptr, memb); + return 0; +} + struct grecs_keyword kwd_database[] = { { "name", N_("word"), N_("Dictionary name (a single word)."), grecs_type_string, GRECS_DFLT, @@ -805,6 +881,14 @@ struct grecs_keyword kwd_database[] = { N_("Set database visibility"), grecs_type_bool, GRECS_DFLT, NULL, offsetof(dicod_database_t, visible) }, + { "database", N_("<name: string> [mime|nomime]"), + N_("For virtual database only: name of the member database." + " Optional mime|nomime specifies the condition under which" + " the database is to be used."), + grecs_type_string, GRECS_DFLT, + NULL, offsetof(dicod_database_t, extra), + member_database_cb }, + { NULL } }; @@ -843,13 +927,13 @@ user_db_config(enum grecs_callback_command cmd, { struct user_db_conf *cfg = varptr; void **pdata = cb_data; - + switch (cmd) { case grecs_callback_section_begin: cfg->locus = *locus; cfg->locus.beg.file = xstrdup(cfg->locus.beg.file); cfg->locus.end.file = xstrdup(cfg->locus.end.file); - if (value->type != GRECS_TYPE_STRING) + if (value->type != GRECS_TYPE_STRING) grecs_error(locus, 0, _("URL must be a string")); else if (!value->v.string) grecs_error(locus, 0, _("empty URL")); @@ -857,15 +941,15 @@ user_db_config(enum grecs_callback_command cmd, cfg->url = xstrdup(value->v.string); *pdata = cfg; break; - + case grecs_callback_section_end: break; - + case grecs_callback_set_value: cfg->locus = *locus; cfg->locus.beg.file = xstrdup(cfg->locus.beg.file); cfg->locus.end.file = xstrdup(cfg->locus.end.file); - if (value->type != GRECS_TYPE_STRING) + if (value->type != GRECS_TYPE_STRING) grecs_error(locus, 0, _("URL must be a string")); else if (!value->v.string) grecs_error(locus, 0, _("empty URL")); @@ -931,7 +1015,7 @@ sasl_cb(enum grecs_callback_command cmd, void *cb_data) { if (cmd == grecs_callback_set_value) { - if (value->type != GRECS_TYPE_STRING) + if (value->type != GRECS_TYPE_STRING) grecs_error(locus, 0, _("expected boolean value but found list")); else grecs_string_convert(&sasl_enable, grecs_type_bool, @@ -992,7 +1076,7 @@ strategy_cb(enum grecs_callback_command cmd, switch (cmd) { case grecs_callback_section_begin: - if (value->type != GRECS_TYPE_STRING) + if (value->type != GRECS_TYPE_STRING) grecs_error(locus, 0, _("Section name must be a string")); else if (!value->v.string) grecs_error(locus, 0, _("missing section name")); @@ -1010,14 +1094,14 @@ strategy_cb(enum grecs_callback_command cmd, dico_strat_free, NULL); } xdico_list_append(strat_forward, strat); - } + } *pdata = strat; } break; - + case grecs_callback_section_end: break; - + case grecs_callback_set_value: grecs_error(locus, 0, _("Unexpected statement")); } @@ -1032,7 +1116,7 @@ strategy_deny_all_cb(enum grecs_callback_command cmd, void *cb_data) { int bool; - + if (cmd != grecs_callback_set_value) { grecs_error(locus, 0, _("Unexpected block statement")); return 1; @@ -1099,7 +1183,7 @@ strategy_deny_length(enum grecs_callback_command cmd, } if (value->type == GRECS_TYPE_STRING) { size_t val; - + if (grecs_string_convert(&val, grecs_type_size, value->v.string, locus)) return 0; @@ -1358,6 +1442,11 @@ config_init(void) grecs_log_to_stderr = 1; grecs_default_port = htons(DICO_DICT_PORT); grecs_parser_options = GRECS_OPTION_QUOTED_STRING_CONCAT; + + modinst_list = xdico_list_create(); + dico_list_set_comparator(modinst_list, cmp_modinst_ident); + + dicod_builtin_module_init(); } void @@ -1399,18 +1488,32 @@ reset_db_visibility(void) dico_iterator_t itr; itr = xdico_list_iterator(database_list); - for (db = dico_iterator_first(itr); db; db = dico_iterator_next(itr)) + for (db = dico_iterator_first(itr); db; db = dico_iterator_next(itr)) db->session_visible = db->visible; dico_iterator_destroy(&itr); } +int +database_session_visibility(dicod_database_t *db) +{ + if (!dicod_acl_check(db->acl, dicod_acl_check(global_acl, 1))) + return 0; + else { + dico_list_t list[2]; + dicod_database_get_languages(db, list); + if (!dicod_lang_check(list)) + return 0; + } + return 1; +} + void check_db_visibility(void) { dicod_database_t *db; dico_iterator_t itr; int global = dicod_acl_check(global_acl, 1); - + itr = xdico_list_iterator(database_list); for (db = dico_iterator_first(itr); db; db = dico_iterator_next(itr)) { if (!db->visible) @@ -1457,10 +1560,10 @@ database_iterate(dico_list_iterator_t fun, void *data) dico_iterator_t itr = xdico_list_iterator(database_list); dicod_database_t *db; int rc = 0; - + for (db = dico_iterator_first(itr); rc == 0 && db; db = dico_iterator_next(itr)) { |