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 @@ -92,7 +92,7 @@ How to Configure @command{wydawca}. * Syntax:: Configuration file syntax. * syslog:: * sql:: -* access methods:: +* dictionaries:: * archivation:: * spool:: * statistics:: @@ -105,13 +105,13 @@ Configuration file syntax * Statements:: * Preprocessor:: -Access Methods +Dictionaries * sql type:: * builtin type:: * external type:: -SQL Access Methods +SQL Dictionary * project-owner-sql:: * project-uploader-sql:: @@ -130,13 +130,13 @@ Mail Notification @chapter Introduction to Wydawca @cindex introduction 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 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 @ref{Automated FTP Uploads, Automated FTP Uploads, Automated FTP Uploads, maintain, Information for maintainers of GNU software}. @@ -157,16 +157,17 @@ corresponding to a certain distribution @acronym{URL}. For example, @item @file{/incoming/ftp} @tab @indicateurl{ftp.gnu.org} @item @file{/incoming/alpha} @tab @indicateurl{alpha.gnu.org} @end multitable +@* @cindex @acronym{PGP} @cindex detached signature @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 (a @dfn{triplet}) to the upload site, storing them into the directory @file{/incoming/ftp}. @@ -179,9 +180,9 @@ their distribution sites. @command{Wydawca} is such a release submission daemon. It is able to 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. @command{Wydawca} supports version 1.1 of directory file, as described in @@ -224,7 +225,7 @@ that case. upload and corresponding distribution directories. In @command{wydawca} terminology, upload directories are also called @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. When started, @command{wydawca} scans each source directory and @@ -235,9 +236,9 @@ supplied with each upload and that contains directive regarding the placement of the uploaded files. A @dfn{triplet} is a standard 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 @ref{FTP Upload Directive File - v1.1, Standalone directives, Standalone directives, @@ -248,26 +249,38 @@ maintain, Information for maintainers of GNU software}. Standalone directives}. @end ifhtml - 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 their destination directories, requested symbolic links are created, etc. @@ -387,7 +400,7 @@ directives any time by running @command{wydawca --config-help}. * Syntax:: Configuration file syntax. * syslog:: * sql:: -* access methods:: +* dictionaries:: * archivation:: * spool:: * statistics:: @@ -860,7 +873,7 @@ sql @var{id} @{ Here, @var{id} is a string uniquely identifying this 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. @end deffn @@ -904,21 +917,21 @@ sql default @{ @end group @end smallexample -@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 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}; query @var{string}; params (@var{param1},@var{param2},...); @@ -926,14 +939,14 @@ access-method @var{method-name} @{ @end smallexample @end deffn - 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 (@pxref{spool}). Global definitions affect all directory pairs in the configuration file, and ones inside a @code{directory} 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: @table @asis @kwindex project-owner @@ -949,10 +962,10 @@ order. the users that are allowed to make uploads for the project. @end table -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: @table @asis @kwindex builtin @@ -966,14 +979,14 @@ Defines the type of this method. @var{Name} is one of the following: @kwindex external @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 subject to meta-variable interpretation (@pxref{meta-interpretation}). The following meta-variables are defined: @@ -1012,12 +1025,12 @@ Spool source directory (@pxref{spool, source}). @itemx user @itemx user:name 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 @end deffn -@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 @menu @@ -1027,9 +1040,9 @@ Supplies additional parameters for the method. @end menu @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 @samp{MySQL} databases are supported). @@ -1042,8 +1055,7 @@ which determines database name and user credentials needed to access it. @cindex Savane 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}. @menu @@ -1059,7 +1071,7 @@ on the database structure used in consisting of two columns: an email address and a user name, in this order. @smallexample -access-method project-owner @{ +dictionary project-owner @{ type sql; params (default); query "SELECT user.email, user.realname " @@ -1077,7 +1089,7 @@ access-method project-owner @{ @UNREVISED @smallexample -access-method project-owner @{ +dictionary project-owner @{ type sql; params (default); query "SELECT user.email, user.realname " @@ -1090,15 +1102,15 @@ access-method project-owner @{ @end smallexample @node builtin type -@subsection Built-in access methods -@cindex builtin access type +@subsection Built-in Dictionary +@cindex builtin dictionary @WRITEME @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. @node archivation @@ -1275,7 +1287,7 @@ archive-signatures no; A @dfn{distribution spool} defines the location of the source directory 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. Distribution spool is defined in the configuration file by the @@ -1289,7 +1301,7 @@ spool @var{tag} @{ source @var{dir}; destination @var{dir}; file-sweep-time @var{interval}; - access-method @{ @dots{} @} + dictionary @{ @dots{} @} archive @{ @dots{} @} notify-event @{ @dots{} @} @} @@ -1338,9 +1350,9 @@ Configure spool-specific archivation. @xref{archivation}, for its description. @end deffn -@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 @deffn {Config: spool} notify-event @{ @dots{} @} @@ -1364,7 +1376,7 @@ spool ftp @{ @end smallexample @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 configuration. @@ -1885,13 +1897,12 @@ The system administrator, as defined in @code{admin-address} statement @kwindex owner @item owner 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}). @kwindex user @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 @end deffn @@ -2202,15 +2213,15 @@ notify-event @{ message @var{text-or-id:@i{<string>}}; @} -# Define access method -access-method @var{ident} @{ - # Method type +# Define a dictionary +dictionary @var{ident} @{ + # Dictionary type type @var{type:@i{<string>}}; # Query template query @var{string:@i{<string>}}; - # Set method parameters + # Set dictionary parameters params @var{arg:@i{<list of string>}}; @} @@ -2231,15 +2242,15 @@ spool @var{tag:@i{<string>}} @{ # Define file sweep time file-sweep-time @var{interval:@i{<string>}}; - # Define access method - access-method @var{ident} @{ - # Method type + # Define a dictionary + dictionary @var{ident} @{ + # Dictionary type type @var{type:@i{<string>}}; # Query template query @var{string:@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 @@ -20,6 +20,7 @@ wydawca_SOURCES=\ builtin.h\ cmdline.h\ config.c\ + dictionary.c\ directive.c\ diskio.c\ exec.c\ @@ -28,7 +29,6 @@ wydawca_SOURCES=\ job.c\ lock.c\ meta.c\ - method.c\ net.c\ pidfile.c\ process.c\ diff --git a/src/builtin.c b/src/builtin.c index 73b1d23..5588fd6 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -20,21 +20,21 @@ #include "regex.h" int -builtin_init (struct access_method *meth) +builtin_init (struct dictionary *dict) { return 0; } int -builtin_done (struct access_method *meth) +builtin_done (struct dictionary *dict) { return 0; } void * -builtin_open (struct access_method *meth) +builtin_open (struct dictionary *dict) { - return meth; + return dict; } #define CMP_EXACT 0 @@ -159,7 +159,7 @@ 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) { int i; int rc; @@ -168,19 +168,19 @@ builtin_run (struct access_method *meth, void *handle, const char *req) int flags = 0; strcmp_fn cmpfn = cmp_exact; 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; } obstack_init (&stk); - for (i = 0; i < meth->parmc; i++) + for (i = 0; i < dict->parmc; i++) { - char *pat = meth->parmv[i]; + char *pat = dict->parmv[i]; if (pat[0] == '/') { @@ -189,7 +189,7 @@ builtin_run (struct access_method *meth, void *handle, const char *req) continue; } - if (i + ncol >= meth->parmc) + if (i + ncol >= dict->parmc) break; if (cmpfn (pat, req, flags)) @@ -197,7 +197,7 @@ builtin_run (struct access_method *meth, void *handle, const char *req) size_t j; for (j = 1; j <= ncol; j++) { - char *val = meth->parmv[i + j]; + char *val = dict->parmv[i + j]; obstack_grow (&stk, val, strlen (val) + 1); } count++; @@ -206,8 +206,8 @@ builtin_run (struct access_method *meth, void *handle, const char *req) i += ncol; } - meth->nrow = count; - meth->ncol = ncol; + dict->nrow = count; + dict->ncol = ncol; if (count == 0) { @@ -234,32 +234,32 @@ builtin_run (struct access_method *meth, void *handle, const char *req) rc = 0; } - meth->storage = bds; + dict->storage = bds; return rc; } 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); free (bds->wp); free (bds); - method->storage = NULL; + dict->storage = NULL; } return 0; } 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 @@ -14,9 +14,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -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 @@ -26,7 +26,7 @@ static struct archive_descr default_archive_descr = { no_backups }; -static struct access_method *default_access_method[access_method_count]; +static struct dictionary *default_dictionary[dictionary_count]; static struct notification *default_notification = NULL; @@ -953,44 +953,44 @@ 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; } static int -cb_access_method_type (enum grecs_callback_command cmd, +cb_dictionary_type (enum grecs_callback_command cmd, grecs_locus_t *locus, void *varptr, grecs_value_t *value, void *cb_data) { - enum access_method_type *ptype = varptr; + enum dictionary_type *ptype = varptr; if (assert_string_arg (locus, cmd, value)) 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; } static int -cb_access_method_params (enum grecs_callback_command cmd, +cb_dictionary_params (enum grecs_callback_command cmd, grecs_locus_t *locus, void *varptr, grecs_value_t *value, void *cb_data) { - struct access_method *meth = varptr; + struct dictionary *meth = varptr; size_t size; if (cmd != grecs_callback_set_value) @@ -1034,21 +1034,21 @@ cb_access_method_params (enum grecs_callback_command cmd, return 0; } -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 } }; 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) { static const char *id_str[] = { "project-uploader", @@ -1056,13 +1056,13 @@ string_to_access_method_id (grecs_locus_t *locus, NULL }; static int id_num[] = { - project_uploader_method, - project_owner_method + project_uploader_dict, + project_owner_dict }; ARGMATCH_VERIFY (id_str, id_num); int rc, res; - rc = string_to ("access method", str, + rc = string_to ("dictionary", str, id_str, id_num, &res, locus); @@ -1071,15 +1071,15 @@ 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; switch (cmd) { case grecs_callback_section_begin: @@ -1088,10 +1088,10 @@ cb_access_method (enum grecs_callback_command cmd, grecs_error(locus, 0, _("tag must be a string")); return 0; } - 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; break; @@ -1099,17 +1099,17 @@ cb_access_method (enum grecs_callback_command cmd, meth = *pdata; switch (meth->type) { - case method_sql: + case dictionary_sql: if (meth->parmc == 0 || !meth->parmv[0]) { grecs_error (locus, 0, _("SQL connection is not declared")); - meth->type = method_none; + meth->type = dictionary_none; } else if (!sql_connection_exists_p (meth->parmv[0])) { grecs_error (locus, 0, _("SQL connection `%s' not declared"), meth->parmv[0]); - meth->type = method_none; + meth->type = dictionary_none; } break; @@ -1171,9 +1171,9 @@ static struct grecs_keyword spool_kw[] = { { "file-sweep-time", N_("interval"), N_("Define file sweep time"), grecs_type_string, NULL, offsetof(struct spool, file_sweep_time), 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"), grecs_type_section, NULL, offsetof(struct spool, archive), cb_archive, NULL, archive_kw }, @@ -1208,8 +1208,8 @@ cb_spool (enum grecs_callback_command cmd, spool = xzalloc (sizeof (*spool)); spool->tag = xstrdup (value->v.string); 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; *pdata = spool; break; @@ -1247,11 +1247,11 @@ cb_spool (enum grecs_callback_command cmd, && spool->vtab.test_url (spool->dest_url, locus)) rc = 1; - 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; } @@ -1452,9 +1452,9 @@ static struct grecs_keyword wydawca_kw[] = { grecs_type_section, &default_notification, 0, cb_notify_event, NULL, notify_event_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 }, { "spool", N_("tag: string"), N_("Define distribution spool"), grecs_type_section, NULL, 0, @@ -1495,6 +1495,6 @@ config_init() if (serv != NULL) grecs_default_port = serv->s_port; - 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 (LO |