aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-09-05 12:42:28 +0300
committerSergey Poznyakoff <gray@gnu.org>2018-09-05 14:41:26 +0300
commit954d267b9de7abdfe9e73ce3372bbade918ebe1a (patch)
treed30b979408c0510e5b87fc0c0b2a1ac7eb75ffab
parentaff3433b89e2fbeaddacf0e65ee105ba5a572ab7 (diff)
downloaddico-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--NEWS25
-rw-r--r--configure.boot2
-rw-r--r--dicod/Makefile.am3
-rw-r--r--dicod/database.c8
-rw-r--r--dicod/dicod.h38
-rw-r--r--dicod/loader.c139
-rw-r--r--dicod/main.c262
-rw-r--r--dicod/ostream.c2
-rw-r--r--dicod/tests/echo.c2
-rw-r--r--dicod/virtual.c290
-rw-r--r--doc/dico.texi148
-rw-r--r--include/dico/types.h3
-rw-r--r--modules/template/module.c12
13 files changed, 776 insertions, 158 deletions
diff --git a/NEWS b/NEWS
index f093de6..698385a 100644
--- a/NEWS
+++ b/NEWS
@@ -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)) {