aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/wydawca.texi177
-rw-r--r--src/Makefile.am2
-rw-r--r--src/builtin.c46
-rw-r--r--src/builtin.h12
-rw-r--r--src/config.c104
-rw-r--r--src/dictionary.c228
-rw-r--r--src/mail.c28
-rw-r--r--src/meta.c10
-rw-r--r--src/method.c226
-rw-r--r--src/process.c14
-rw-r--r--src/sql.c44
-rw-r--r--src/sql.h20
-rw-r--r--src/triplet.c8
-rw-r--r--src/verify.c32
-rw-r--r--src/wydawca.h60
-rw-r--r--tests/etc/wydawca.rcin4
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, &quote);
+ output = xmalloc (size + 1);
+ wordsplit_quote_copy (output, input, 0);
+ output[size] = 0;
+
+ *poutput = output;
+ if (psize)
+ *psize = size;
+ return 0;
+}
+
diff --git a/src/mail.c b/src/mail.c
index 15c2937..98f6c4a 100644
--- a/src/mail.c
+++ b/src/mail.c
@@ -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