diff options
-rw-r--r-- | doc/wydawca.texi | 177 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/builtin.c | 46 | ||||
-rw-r--r-- | src/builtin.h | 12 | ||||
-rw-r--r-- | src/config.c | 104 | ||||
-rw-r--r-- | src/dictionary.c | 228 | ||||
-rw-r--r-- | src/mail.c | 28 | ||||
-rw-r--r-- | src/meta.c | 10 | ||||
-rw-r--r-- | src/method.c | 226 | ||||
-rw-r--r-- | src/process.c | 14 | ||||
-rw-r--r-- | src/sql.c | 44 | ||||
-rw-r--r-- | src/sql.h | 20 | ||||
-rw-r--r-- | src/triplet.c | 8 | ||||
-rw-r--r-- | src/verify.c | 32 | ||||
-rw-r--r-- | src/wydawca.h | 60 | ||||
-rw-r--r-- | tests/etc/wydawca.rcin | 4 |
16 files changed, 514 insertions, 501 deletions
diff --git a/doc/wydawca.texi b/doc/wydawca.texi index a136fd6..04b599f 100644 --- a/doc/wydawca.texi +++ b/doc/wydawca.texi @@ -94,3 +94,3 @@ How to Configure @command{wydawca}. * sql:: -* access methods:: +* dictionaries:: * archivation:: @@ -107,3 +107,3 @@ Configuration file syntax -Access Methods +Dictionaries @@ -113,3 +113,3 @@ Access Methods -SQL Access Methods +SQL Dictionary @@ -132,3 +132,3 @@ Mail Notification Let's begin with a short synopsis. Suppose you run a developer's -site, like, e.g. @indicateurl{gnu.org}. You have at least two +site, like, e.g. @indicateurl{gnu.org}. You have two @dfn{distribution @acronym{URL}s}: @indicateurl{ftp.gnu.org}, which @@ -136,5 +136,5 @@ distributes stable versions of the software, and @indicateurl{alpha.gnu.org}, which distributes alpha and pre-test -versions. Now, package maintainers should have a way of uploading -their packages to one of these sites. The currently accepted scheme -is described in +versions. Now, package maintainers need to have a way of uploading +their packages to one of these sites. This is done using the +@dfn{Automated FTP Upload} method, as described in @ifnothtml @@ -159,2 +159,3 @@ corresponding to a certain distribution @acronym{URL}. For example, @end multitable +@* @@ -163,8 +164,8 @@ corresponding to a certain distribution @acronym{URL}. For example, @cindex signature, detached - Now, if the maintainer of the project @samp{foo} wishes to make a release + Now, if maintainer of the project @samp{foo} wishes to make a release of the stable version @file{foo-1.0.tar.gz}, he first creates a detached signature @file{foo-1.0.tar.gz.sig}. Then he creates a special -@dfn{directive} file, that contains information about where the +@dfn{directive} file, which contains information about where the distributed tarball must be placed, and clear-signs it using his -@acronym{PGP} key, thus obtaining file +@acronym{PGP} key, thus obtaining the file @file{foo-1.0.tar.gz.directive.asc}. Finally, he uploads these three files @@ -181,5 +182,5 @@ their distribution sites. handle any number of @samp{source/destination} pairs (called -@dfn{spools}, offers an extensible logging and mail notification -mechanism, allowing both package maintainers and site administrators -to be immediately notified about any occurring problems. +@dfn{spools}) in real time, and offers an extensible logging and mail +notification mechanism, allowing both package maintainers and site +administrators to be immediately notified about any occurring problems. @@ -226,3 +227,3 @@ upload and corresponding distribution directories. In @dfn{source}, and distribution directories -- @dfn{destination} -directories. The file also supplies all the information +directories. The configuration file also supplies all the information necessary to access user and project databases. @@ -237,5 +238,5 @@ entity, consisting of three files: a clear-signed directive file, a file to be distributed, and a detached signature of the latter. -In some special cases, a clear-signed directive file alone is valid, -namely when it contains only @dfn{standalone directives}, as described -in +In some special cases, a clear-signed directive file alone is valid. +This happens when it contains only @dfn{standalone directives}, as +described in @ifnothtml @@ -250,22 +251,34 @@ Standalone directives}. - Each @dfn{incomplete} triplet, i.e. such that misses one or more +@cindex triplet, incomplete +@cindex incomplete triplet +@cindex triplet, expired +@cindex expired triplet + Each @dfn{incomplete} triplet, i.e. a triplet missing one or more necessary files, is then verified by checking if the modification date of its oldest file is older than a predefined amount of time -(@FIXME-pxref{file-sweep-time}), and if so, all files from this triplet are -removed (an @dfn{expired triplet}). This gives users the possibility -to restart interrupted or otherwise broken uploads later. - - Then, the utility ensures that each of the remaining triplets is -created by a single person. Any triplets that do not are immediately -removed. +(@FIXME-pxref{file-sweep-time}). If so, the triplet is considered +@dfn{expired}, and all its files are removed. This gives users the +possibility to restart interrupted or otherwise broken uploads later. +@cindex dictionary @cindex @acronym{PGP} + After completing these preliminary stages, @command{wydawca} +analyzes the directive file and extracts the project name +from it. Using this name as a key, it looks up in the @dfn{project +dictionary} a list of users authorized to make uploads for this +project. This list contains user names and their corresponding public +@acronym{PGP} keys. @command{Wydawca} tries to verify the directive +file using each @acronym{PGP} key from this list, until a matching +key is found, or the list in exhausted. In the latter case, the +triplet is rejected. Otherwise, the key and its owner are remembered +for the next step. + +@cindex detached signature @cindex detached signature @cindex signature, detached - Then, @acronym{PGP} signatures of directive files and any detached -signatures (if available) are verified. If they do not match public -keys of the user who uploaded the triplet, such a triplet is -discarded. + In this step, the uploaded file and its detached signature +are verified. If they do not match the public key obtained in the +previous step, the triplet is rejected. - Finally, the directives from each directive file are executed. On + Finally, directives from the directive file are executed. On this stage of the processing, the uploaded files are actually moved to @@ -389,3 +402,3 @@ directives any time by running @command{wydawca --config-help}. * sql:: -* access methods:: +* dictionaries:: * archivation:: @@ -862,3 +875,3 @@ sql @var{id} @{ database. It is used by another configuration statements (e.g. by -access methods, see the next section) to refer to this +dictionaries, see the next section) to refer to this database. @@ -906,8 +919,8 @@ sql default @{ -@node access methods -@section Access Methods -@cindex Access method +@node dictionaries +@section Dictionaries +@cindex dictionaries @cindex @acronym{PGP} key - -An @dfn{access method} defines the ways to retrieve user information +@UNREVISED +A @dfn{dictionary} defines the ways to retrieve user information necessary to verify the submission. This information can be, for @@ -915,8 +928,8 @@ example, the user's @acronym{PGP} key or his permissions on a project. - Access methods are defined in configuration file using the + Dictionary is defined in configuration file using the following syntax: -@deffn {Config} access-method +@deffn {Config} dictionary @smallexample -access-method @var{method-name} @{ +dictionary @var{dict-id} @{ type @var{type}; @@ -928,3 +941,3 @@ access-method @var{method-name} @{ - Access method statements can appear either in the global scope of + A @code{dictionary} statement can appear either in the global scope of the configuration file, or inside a @code{spool} statement @@ -934,4 +947,4 @@ statement override them for that particular directory pair. -There are two access methods, identified by the value of -@var{method-name} tag: +There are two dictionaries, identified by the value of +@var{dict-id} tag: @@ -951,6 +964,6 @@ the users that are allowed to make uploads for the project. -The sub-statements of @code{access-method} are: +The sub-statements of @code{dictionary} are: -@deffn {Config: access-method} type @var{name} -Defines the type of this method. @var{Name} is one of the following: +@deffn {Config: dictionary} type @var{name} +Defines the type of this dictionary. @var{Name} is one of the following: @@ -968,10 +981,10 @@ Defines the type of this method. @var{Name} is one of the following: @item external - Retrieve data using an external program. This method is reserved for -future use. + Retrieve data using an external program. This dictionary type is +reserved for future use. @end table -See below for a detailed description of these access methods. +See below for a detailed description of these dictionary types. @end deffn -@deffn {Config: access-method} query @var{string} +@deffn {Config: dictionary} query @var{string} Sets the query used for retrieving the data. The @var{string} is @@ -1014,3 +1027,3 @@ Spool source directory (@pxref{spool, source}). The system name of the user that submitted the triplet. This is -defined only in @samp{project-owner} access method. +defined only for @samp{project-owner} dictionaries. @end table @@ -1018,4 +1031,4 @@ defined only in @samp{project-owner} access method. -@deffn {Config: access-method} params (@var{param1}, @var{param2}, ...) -Supplies additional parameters for the method. +@deffn {Config: dictionary} params (@var{param1}, @var{param2}, ...) +Supplies additional parameters. @end deffn @@ -1029,5 +1042,5 @@ Supplies additional parameters for the method. @node sql type -@subsection SQL Access Methods -@cindex sql access type -Access methods of @samp{sql} type retrieve information from an +@subsection SQL Dictionary +@cindex sql dictionary +Dictionaries of @samp{sql} type retrieve information from an @acronym{SQL} database (as of version @value{VERSION}, only @@ -1044,4 +1057,3 @@ which determines database name and user credentials needed to access it. The following sub-nodes contain sample definitions for the -access methods using the @code{sql} type. They are based -on the database structure used in +@code{sql} dictionaries. They are based on the database structure used in @uref{http://gna.org/projects/savane, @command{Savane} system}. @@ -1061,3 +1073,3 @@ consisting of two columns: an email address and a user name, in this order. @smallexample -access-method project-owner @{ +dictionary project-owner @{ type sql; @@ -1079,3 +1091,3 @@ access-method project-owner @{ @smallexample -access-method project-owner @{ +dictionary project-owner @{ type sql; @@ -1092,4 +1104,4 @@ access-method project-owner @{ @node builtin type -@subsection Built-in access methods -@cindex builtin access type +@subsection Built-in Dictionary +@cindex builtin dictionary @WRITEME @@ -1097,6 +1109,6 @@ access-method project-owner @{ @node external type -@subsection External access methods -@cindex external access type +@subsection External Dictionary +@cindex external dictionary -As of version @value{VERSION} this access type is not yet +As of version @value{VERSION} this dictionary is not yet implemented. @@ -1277,3 +1289,3 @@ and the corresponding distribution (or @dfn{destination}) directory. It may also set archivation type, -various access methods and notifications for that directory, thus overriding +various dictionaries and notifications for that directory, thus overriding global settings. @@ -1291,3 +1303,3 @@ spool @var{tag} @{ file-sweep-time @var{interval}; - access-method @{ @dots{} @} + dictionary @{ @dots{} @} archive @{ @dots{} @} @@ -1340,5 +1352,5 @@ description. -@deffn {Config: spool} access-method @var{tag} @{ @dots{} @} -Configure spool-specific access-method. @xref{access -methods}, for a detailed discussion of this statement. +@deffn {Config: spool} dictionary @var{tag} @{ @dots{} @} +Configure spool-specific dictionary. @xref{dictionaries}, for a +detailed discussion of this statement. @end deffn @@ -1366,3 +1378,3 @@ spool ftp @{ @noindent -This spool defines no particular archivation type, access method or +This spool defines no particular archivation type, dictionary or notifications, so it will inherit these settings from the global @@ -1887,4 +1899,4 @@ The system administrator, as defined in @code{admin-address} statement Administrators of the project for which the files where -uploaded. Their addresses are retrieved using the @samp{project-owner} -access method (@pxref{access methods}). +uploaded. Their addresses are retrieved from the @samp{project-owner} +dictionary (@pxref{dictionaries}). @@ -1892,4 +1904,3 @@ access method (@pxref{access methods}). @item user -The user who uploaded files. The user address is returned by -@samp{user-data} access method (@pxref{access methods}). +The user who uploaded files. @end table @@ -2204,5 +2215,5 @@ notify-event @{ -# Define access method -access-method @var{ident} @{ - # Method type +# Define a dictionary +dictionary @var{ident} @{ + # Dictionary type type @var{type:@i{<string>}}; @@ -2212,3 +2223,3 @@ access-method @var{ident} @{ - # Set method parameters + # Set dictionary parameters params @var{arg:@i{<list of string>}}; @@ -2233,5 +2244,5 @@ spool @var{tag:@i{<string>}} @{ - # Define access method - access-method @var{ident} @{ - # Method type + # Define a dictionary + dictionary @var{ident} @{ + # Dictionary type type @var{type:@i{<string>}}; @@ -2241,3 +2252,3 @@ spool @var{tag:@i{<string>}} @{ - # Set method parameters + # Set dictionary parameters params @var{arg:@i{<list of string>}}; diff --git a/src/Makefile.am b/src/Makefile.am index c96fbcb..a599118 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,2 +22,3 @@ wydawca_SOURCES=\ config.c\ + dictionary.c\ directive.c\ @@ -30,3 +31,2 @@ wydawca_SOURCES=\ meta.c\ - method.c\ net.c\ diff --git a/src/builtin.c b/src/builtin.c index 73b1d23..5588fd6 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -22,3 +22,3 @@ int -builtin_init (struct access_method *meth) +builtin_init (struct dictionary *dict) { @@ -28,3 +28,3 @@ builtin_init (struct access_method *meth) int -builtin_done (struct access_method *meth) +builtin_done (struct dictionary *dict) { @@ -34,5 +34,5 @@ builtin_done (struct access_method *meth) void * -builtin_open (struct access_method *meth) +builtin_open (struct dictionary *dict) { - return meth; + return dict; } @@ -161,3 +161,3 @@ static int default_ncol[] = { int -builtin_run (struct access_method *meth, void *handle, const char *req) +builtin_lookup (struct dictionary *dict, void *handle, const char *req) { @@ -170,7 +170,7 @@ builtin_run (struct access_method *meth, void *handle, const char *req) struct builtin_data_storage *bds; - int ncol = default_ncol[meth->id]; + int ncol = default_ncol[dict->id]; - if (meth->parmc == 0) + if (dict->parmc == 0) { - meth->nrow = meth->ncol = 0; + dict->nrow = dict->ncol = 0; return 0; @@ -180,5 +180,5 @@ builtin_run (struct access_method *meth, void *handle, const char *req) - for (i = 0; i < meth->parmc; i++) + for (i = 0; i < dict->parmc; i++) { - char *pat = meth->parmv[i]; + char *pat = dict->parmv[i]; @@ -191,3 +191,3 @@ builtin_run (struct access_method *meth, void *handle, const char *req) - if (i + ncol >= meth->parmc) + if (i + ncol >= dict->parmc) break; @@ -199,3 +199,3 @@ builtin_run (struct access_method *meth, void *handle, const char *req) { - char *val = meth->parmv[i + j]; + char *val = dict->parmv[i + j]; obstack_grow (&stk, val, strlen (val) + 1); @@ -208,4 +208,4 @@ builtin_run (struct access_method *meth, void *handle, const char *req) - meth->nrow = count; - meth->ncol = ncol; + dict->nrow = count; + dict->ncol = ncol; @@ -236,3 +236,3 @@ builtin_run (struct access_method *meth, void *handle, const char *req) - meth->storage = bds; + dict->storage = bds; @@ -242,7 +242,7 @@ builtin_run (struct access_method *meth, void *handle, const char *req) int -builtin_free_result (struct access_method *method, void *handle) +builtin_free_result (struct dictionary *dict, void *handle) { - if (method->storage) + if (dict->storage) { - struct builtin_data_storage *bds = method->storage; + struct builtin_data_storage *bds = dict->storage; obstack_free (&bds->stk, NULL); @@ -250,3 +250,3 @@ builtin_free_result (struct access_method *method, void *handle) free (bds); - method->storage = NULL; + dict->storage = NULL; } @@ -256,8 +256,8 @@ builtin_free_result (struct access_method *method, void *handle) int -builtin_get (struct access_method *method, void *handle, +builtin_get (struct dictionary *dict, void *handle, unsigned nrow, unsigned ncol) { - struct builtin_data_storage *bds = method->storage; - char *str = bds->wp[nrow * method->ncol + ncol]; - method_copy_result (method, str, strlen (str)); + struct builtin_data_storage *bds = dict->storage; + char *str = bds->wp[nrow * dict->ncol + ncol]; + dictionary_copy_result (dict, str, strlen (str)); return 0; diff --git a/src/builtin.h b/src/builtin.h index 500a6cb..dd52bce 100644 --- a/src/builtin.h +++ b/src/builtin.h @@ -16,7 +16,7 @@ -int builtin_init (struct access_method *); -int builtin_done (struct access_method *); -void *builtin_open (struct access_method *); -int builtin_get (struct access_method *, void *, unsigned, unsigned); -int builtin_run (struct access_method *, void *, const char *); -int builtin_free_result (struct access_method *, void *); +int builtin_init (struct dictionary *); +int builtin_done (struct dictionary *); +void *builtin_open (struct dictionary *); +int builtin_get (struct dictionary *, void *, unsigned, unsigned); +int builtin_lookup (struct dictionary *, void *, const char *); +int builtin_free_result (struct dictionary *, void *); diff --git a/src/config.c b/src/config.c index f0a7042..15c191c 100644 --- a/src/config.c +++ b/src/config.c @@ -28,3 +28,3 @@ static struct archive_descr default_archive_descr = { -static struct access_method *default_access_method[access_method_count]; +static struct dictionary *default_dictionary[dictionary_count]; static struct notification *default_notification = NULL; @@ -955,13 +955,13 @@ cb_notify_event (enum grecs_callback_command cmd, -static enum access_method_type -string_to_access_method_type (const char *str) +static enum dictionary_type +string_to_dictionary_type (const char *str) { if (strcmp (str, "sql") == 0) - return method_sql; + return dictionary_sql; else if (strcmp (str, "builtin") == 0) - return method_builtin; + return dictionary_builtin; else if (strcmp (str, "external") == 0) - return method_external; + return dictionary_external; else - return method_none; + return dictionary_none; } @@ -969,3 +969,3 @@ string_to_access_method_type (const char *str) static int -cb_access_method_type (enum grecs_callback_command cmd, +cb_dictionary_type (enum grecs_callback_command cmd, grecs_locus_t *locus, @@ -975,3 +975,3 @@ cb_access_method_type (enum grecs_callback_command cmd, { - enum access_method_type *ptype = varptr; + enum dictionary_type *ptype = varptr; @@ -979,5 +979,5 @@ cb_access_method_type (enum grecs_callback_command cmd, return 1; - *ptype = string_to_access_method_type (value->v.string); - if (*ptype == method_none) - grecs_error (locus, 0, _("unknown access method: %s"), value->v.string); + *ptype = string_to_dictionary_type (value->v.string); + if (*ptype == dictionary_none) + grecs_error (locus, 0, _("unknown dictionary type: %s"), value->v.string); return 0; @@ -986,3 +986,3 @@ cb_access_method_type (enum grecs_callback_command cmd, static int -cb_access_method_params (enum grecs_callback_command cmd, +cb_dictionary_params (enum grecs_callback_command cmd, grecs_locus_t *locus, @@ -992,3 +992,3 @@ cb_access_method_params (enum grecs_callback_command cmd, { - struct access_method *meth = varptr; + struct dictionary *meth = varptr; size_t size; @@ -1036,11 +1036,11 @@ cb_access_method_params (enum grecs_callback_command cmd, -static struct grecs_keyword access_method_kw[] = { - { "type", N_("type"), N_("Method type"), - grecs_type_string, NULL, offsetof(struct access_method, type), - cb_access_method_type }, +static struct grecs_keyword dictionary_kw[] = { + { "type", N_("type"), N_("Dictionary type"), + grecs_type_string, NULL, offsetof(struct dictionary, type), + cb_dictionary_type }, { "query", N_("string"), N_("Query template"), - grecs_type_string, NULL, offsetof(struct access_method, query) }, - { "params", N_("arg"), N_("Set method parameters"), + grecs_type_string, NULL, offsetof(struct dictionary, query) }, + { "params", N_("arg"), N_("Set dictionary parameters"), grecs_type_string|GRECS_LIST, NULL, 0, - cb_access_method_params }, + cb_dictionary_params }, { NULL } @@ -1049,4 +1049,4 @@ static struct grecs_keyword access_method_kw[] = { int -string_to_access_method_id (grecs_locus_t *locus, - const char *str, enum access_method_id *idp) +string_to_dictionary_id (grecs_locus_t *locus, + const char *str, enum dictionary_id *idp) { @@ -1058,4 +1058,4 @@ string_to_access_method_id (grecs_locus_t *locus, static int id_num[] = { - project_uploader_method, - project_owner_method + project_uploader_dict, + project_owner_dict }; @@ -1064,3 +1064,3 @@ string_to_access_method_id (grecs_locus_t *locus, int rc, res; - rc = string_to ("access method", str, + rc = string_to ("dictionary", str, id_str, id_num, @@ -1073,11 +1073,11 @@ string_to_access_method_id (grecs_locus_t *locus, static int -cb_access_method (enum grecs_callback_command cmd, - grecs_locus_t *locus, - void *varptr, - grecs_value_t *value, - void *cb_data) +cb_dictionary (enum grecs_callback_command cmd, + grecs_locus_t *locus, + void *varptr, + grecs_value_t *value, + void *cb_data) { - struct access_method **pmeth, *meth; + struct dictionary **pmeth, *meth; void **pdata = cb_data; - enum access_method_id id; + enum dictionary_id id; @@ -1090,6 +1090,6 @@ cb_access_method (enum grecs_callback_command cmd, } - if (string_to_access_method_id (locus, value->v.string, &id)) + if (string_to_dictionary_id (locus, value->v.string, &id)) return 1; - pmeth = (struct access_method **) varptr + id; - *pmeth = method_new (id, method_builtin); + pmeth = (struct dictionary **) varptr + id; + *pmeth = dictionary_new (id, dictionary_builtin); *pdata = *pmeth; @@ -1101,3 +1101,3 @@ cb_access_method (enum grecs_callback_command cmd, { - case method_sql: + case dictionary_sql: if (meth->parmc == 0 || !meth->parmv[0]) @@ -1105,3 +1105,3 @@ cb_access_method (enum grecs_callback_command cmd, grecs_error (locus, 0, _("SQL connection is not declared")); - meth->type = method_none; + meth->type = dictionary_none; } @@ -1111,3 +1111,3 @@ cb_access_method (enum grecs_callback_command cmd, meth->parmv[0]); - meth->type = method_none; + meth->type = dictionary_none; } @@ -1173,5 +1173,5 @@ static struct grecs_keyword spool_kw[] = { cb_interval }, - { "access-method", N_("ident"), N_("Define access method"), - grecs_type_section, NULL, offsetof(struct spool, access_method), - cb_access_method, NULL, access_method_kw }, + { "dictionary", N_("ident"), N_("Define data dictionary"), + grecs_type_section, NULL, offsetof(struct spool, dictionary), + cb_dictionary, NULL, dictionary_kw }, { "archive", N_("type: string"), N_("Set up archivation"), @@ -1210,4 +1210,4 @@ cb_spool (enum grecs_callback_command cmd, spool->file_sweep_time = file_sweep_time; - for (i = 0; i < NITEMS (spool->access_method); i++) - spool->access_method[i] = default_access_method[i]; + for (i = 0; i < NITEMS (spool->dictionary); i++) + spool->dictionary[i] = default_dictionary[i]; spool->archive = default_archive_descr; @@ -1249,7 +1249,7 @@ cb_spool (enum grecs_callback_command cmd, - for (i = 0; i < access_method_count; i++) - if (spool->access_method[i]->type == method_external) + for (i = 0; i < dictionary_count; i++) + if (spool->dictionary[i]->type == dictionary_external) { grecs_error (locus, 0, - _("Sorry, method type `external' is not yet supported")); + _("Sorry, the dictionary type `external' is not yet supported")); rc = 1; @@ -1454,5 +1454,5 @@ static struct grecs_keyword wydawca_kw[] = { - { "access-method", N_("ident"), N_("Define access method"), - grecs_type_section, default_access_method, 0, - cb_access_method, NULL, access_method_kw }, + { "dictionary", N_("ident"), N_("Define data dictionary"), + grecs_type_section, default_dictionary, 0, + cb_dictionary, NULL, dictionary_kw }, @@ -1497,4 +1497,4 @@ config_init() - for (i = 0; i < access_method_count; i++) - default_access_method[i] = method_new (i, method_builtin); + for (i = 0; i < dictionary_count; i++) + default_dictionary[i] = dictionary_new (i, dictionary_builtin); } diff --git a/src/dictionary.c b/src/dictionary.c new file mode 100644 index 0000000..c31baf8 --- /dev/null +++ b/src/dictionary.c @@ -0,0 +1,228 @@ +/* wydawca - automatic release submission daemon + Copyright (C) 2007 Sergey Poznyakoff + + Wydawca is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + Wydawca is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with wydawca. If not, see <http://www.gnu.org/licenses/>. */ + +#include "wydawca.h" +#include "sql.h" +#include "builtin.h" + +struct dictionary_descr +{ + const char *name; + + int (*init) (struct dictionary *); + int (*done) (struct dictionary *); + int (*free) (struct dictionary *, void *); + + void *(*open) (struct dictionary *); + int (*close) (struct dictionary *, void *); + + int (*get) (struct dictionary *, void *, unsigned, unsigned); + int (*lookup) (struct dictionary *, void *, const char *); + int (*quote) (struct dictionary *, void *, const char *, char **, size_t *); +}; + +static struct dictionary_descr dictionary_tab[] = { + { "none", NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + { "sql", sql_init_dictionary, sql_done_dictionary, sql_free_result, + sql_open, NULL, sql_get_dictionary, sql_lookup_dictionary, sql_quote }, + { "builtin", builtin_init, builtin_done, builtin_free_result, + builtin_open, NULL, + builtin_get, + builtin_lookup }, + { "external", NULL, NULL, NULL, NULL, NULL, NULL, NULL } +}; + +struct dictionary * +dictionary_new (enum dictionary_id id, enum dictionary_type type) +{ + struct dictionary *mp = xmalloc (sizeof mp[0]); + memset (mp, 0, sizeof mp[0]); + mp->id = id; + mp->type = type; + return mp; +} + +int +dictionary_init (struct dictionary *dict) +{ + struct dictionary_descr *mp = dictionary_tab + dict->type; + int rc = 0; + + if (dict->init_passed++) + return 0; + if (debug_level > 1) + { + int i; + logmsg (LOG_DEBUG, _("initializing dictionary: %s \"%s\""), + mp->name, SP (dict->query)); + for (i = 0; i < dict->parmc; i++) + logmsg (LOG_DEBUG, " parmv[%d]=%s", i, dict->parmv[i]); + } + if (mp->init) + rc = mp->init (dict); + if (rc == 0) + dict->init_passed = 1; + return rc; +} + +void * +dictionary_open (struct dictionary *dict) +{ + struct dictionary_descr *mp = dictionary_tab + dict->type; + + if (!mp->open) + return NULL; + return mp->open (dict); +} + +int +dictionary_close (struct dictionary *dict, void *handle) +{ + struct dictionary_descr *mp = dictionary_tab + dict->type; + if (!mp->close) + return 0; + return mp->close (dict, handle); +} + +int +dictionary_done (struct dictionary *dict) +{ + struct dictionary_descr *mp = dictionary_tab + dict->type; + int rc = 0; + + if (dict->init_passed == 0) + return 0; + if (--dict->init_passed) + return 0; + if (debug_level > 1) + { + int i; + logmsg (LOG_DEBUG, _("closing dictionary: %s \"%s\""), + mp->name, SP (dict->query)); + for (i = 0; i < dict->parmc; i++) + logmsg (LOG_DEBUG, " parmv[%d]=%s", i, dict->parmv[i]); + } + if (mp->done) + rc = mp->done (dict); + free (dict->result); + dict->result = NULL; + dict->result_size = 0; + return rc; +} + +int +dictionary_lookup (struct dictionary *dict, void *handle, const char *cmd) +{ + struct dictionary_descr *mp = dictionary_tab + dict->type; + + if (debug_level > 1) + { + if (cmd) + logmsg (LOG_DEBUG, _("dictionary lookup: %s \"%s\""), + mp->name, cmd); + else + logmsg (LOG_DEBUG, _("dictionary lookup: %s"), mp->name); + } + + if (!dict->init_passed) + { + logmsg (LOG_CRIT, + _("INTERNAL ERROR: dictionary %s \"%s\" not initialized"), + mp->name, SP (dict->query)); + return 1; + } + if (!mp->lookup) + { + logmsg (LOG_CRIT, + _("INTERNAL ERROR: no lookup function for dictionary %s \"%s\""), + mp->name, SP (dict->query)); + return 1; + } + if (mp->free) + mp->free (dict, handle); + return mp->lookup (dict, handle, cmd); +} + +unsigned +dictionary_num_rows (struct dictionary *dict) +{ + return dict->nrow; +} + +unsigned +dictionary_num_cols (struct dictionary *dict) +{ + return dict->ncol; +} + +const char * +dictionary_result (struct dictionary *dict, void *handle, + unsigned nrow, unsigned ncol) +{ + struct dictionary_descr *mp = dictionary_tab + dict->type; + + if (nrow >= dict->nrow || ncol >= dict->ncol + || mp->get (dict, handle, nrow, ncol)) + return NULL; + return dict->result; +} + +void +dictionary_copy_result (struct dictionary *dict, const char *res, size_t size) +{ + if (dict->result_size < size + 1) + { + dict->result_size = size + 1; + dict->result = x2realloc (dict->result, &dict->result_size); + } + memcpy (dict->result, res, size); + dict->result[size] = 0; +} + +/* Quote non-printable characters in INPUT. Point *OUTPUT to the malloc'ed + quoted string. Return its length. */ +int +dictionary_quote_string (struct dictionary *dict, void *handle, + const char *input, + char **poutput, size_t *psize) +{ + struct dictionary_descr *mp = dictionary_tab + dict->type; + size_t size; + int quote; + char *output; + + if (!input) + { + *poutput = xmalloc (1); + (*poutput)[0] = 0; + *psize = 1; + return 0; + } + + if (mp->quote) + return mp->quote (dict, handle, input, poutput, psize); + + size = wordsplit_quoted_length (input, 0, "e); + output = xmalloc (size + 1); + wordsplit_quote_copy (output, input, 0); + output[size] = 0; + + *poutput = output; + if (psize) + *psize = size; + return 0; +} + @@ -500,3 +500,3 @@ get_uploader_email (struct uploader_info *info, struct file_triplet *trp, mu_address_t -get_recipient (struct access_method *method, struct file_triplet *trp, +get_recipient (struct dictionary *dict, struct file_triplet *trp, const char **errp) @@ -509,5 +509,5 @@ get_recipient (struct access_method *method, struct file_triplet *trp, - if (method->type == method_none) + if (dict->type == dictionary_none) { - *errp = N_("access method is not configured"); + *errp = N_("dictionary is not configured"); return NULL; @@ -515,6 +515,6 @@ get_recipient (struct access_method *method, struct file_triplet *trp, - md = method_open (method); + md = dictionary_open (dict); if (!md) { - *errp = N_("failed to open access method"); + *errp = N_("failed to open dictionary"); return NULL; @@ -522,5 +522,5 @@ get_recipient (struct access_method *method, struct file_triplet *trp, - text = triplet_expand_method_query (method, md, trp); + text = triplet_expand_dictionary_query (dict, md, trp); - rc = method_run (method, md, text); + rc = dictionary_lookup (dict, md, text); free (text); @@ -529,3 +529,3 @@ get_recipient (struct access_method *method, struct file_triplet *trp, *errp = N_("cannot obtain recipient emails"); - method_close (method, md); + dictionary_close (dict, md); return NULL; @@ -533,4 +533,4 @@ get_recipient (struct access_method *method, struct file_triplet *trp, - nrows = method_num_rows (method); - ncols = method_num_cols (method); + nrows = dictionary_num_rows (dict); + ncols = dictionary_num_cols (dict); @@ -545,3 +545,3 @@ get_recipient (struct access_method *method, struct file_triplet *trp, mu_address_t addr; - const char *str = method_result (method, md, i, 0); + const char *str = dictionary_result (dict, md, i, 0); if (mu_address_create (&addr, str)) @@ -550,3 +550,3 @@ get_recipient (struct access_method *method, struct file_triplet *trp, { - str = method_result (method, md, i, 1); + str = dictionary_result (dict, md, i, 1); if (str) @@ -557,3 +557,3 @@ get_recipient (struct access_method *method, struct file_triplet *trp, } - method_close (method, md); + dictionary_close (dict, md); @@ -585,3 +585,3 @@ do_notify (struct file_triplet *trp, enum notification_event ev, case notify_owner |