diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-08-26 13:03:32 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-08-26 13:03:32 +0000 |
commit | 84f2d101da91c2f1469dcb997e0c0d5389090de1 (patch) | |
tree | ee8015b967cb49a6e65892cb2814d54bee2ab45c | |
parent | 6166fa6947a8cd6d89afb806d6548ee5d0f1e2d7 (diff) | |
download | gsc-84f2d101da91c2f1469dcb997e0c0d5389090de1.tar.gz gsc-84f2d101da91c2f1469dcb997e0c0d5389090de1.tar.bz2 |
Implement project owner notifications.
* wydawca/wydawca.c (syslog_printer): Reduce the number of memory
reallocations
(make_stat_expansion): Update
* wydawca/method.c: Implement a new framework: methods may return
2-dimensional arrays of strings.
* wydawca/sql.c, wydawca/sql.h: Implement the new method framework.
* wydawca/verify.c (expand_param): kw_expansion may provide
expansion functions. An additional argument supplies user-defined
data for expansions.
(escape_kwexp): Extern
(free_kwexp): Improve
(get_project_name): New function
(make_default_kwexp): New function
(check_access_rights): Call get_project_name. Use
make_default_kwexp to initialize expansions
(verify_directive_file): Use make_default_kwexp to initialize
expansions
* wydawca/wydawca.h (NITEMS): New macro
(enum access_method_type): New members: ncol, nrow
(struct directory_pair): New members url,project_owner_method,
user_data_method
(struct file_info): Replace mtime, uid with struct stat sb
(struct file_triplet): New members project, dpair, user_data
(TRIPLET_UID): Take into account the changes to struct file_info
(enum notification_event): New data type
(notify_project_owner, notify_admin, notify): New functions
(struct kw_expansion): New members static_p, expand and data.
(escape_kwexp,make_default_kwexp): New proto
(expand_param): Change signature
(triplet_expand_param): New function
(method_result): Change prototype
(method_num_rows,method_num_cols): New functions
* wydawca/config.c: New statements project-owner, user-data,
admin-address, mail-user, user-message
directory can take an optional argument specifying base URL for
notification messages
* wydawca/gpg.c (verify_directive_signature): Expand directives
even if the signature does not match. Useful for notifications.
Add notifications.
* wydawca/process.c: Add notifications.
* wydawca/directive.c: Add notifications
* wydawca/wydawca.rc: Update
* wydawca/mail.c, wydawca/mail.h: Implement project owner
notifications
* wydawca/triplet.c (triplet_expand_param): New function
* lib/cfg.c (read_cont_line): Fix counting of input lines.
git-svn-id: file:///svnroot/gsc/trunk@294 d2de0444-eb31-0410-8365-af798a554d48
-rw-r--r-- | ChangeLog | 52 | ||||
-rw-r--r-- | lib/cfg.c | 37 | ||||
-rw-r--r-- | wydawca/config.c | 162 | ||||
-rw-r--r-- | wydawca/directive.c | 1 | ||||
-rw-r--r-- | wydawca/gpg.c | 26 | ||||
-rw-r--r-- | wydawca/mail.c | 103 | ||||
-rw-r--r-- | wydawca/mail.h | 3 | ||||
-rw-r--r-- | wydawca/method.c | 36 | ||||
-rw-r--r-- | wydawca/process.c | 5 | ||||
-rw-r--r-- | wydawca/sql.c | 73 | ||||
-rw-r--r-- | wydawca/sql.h | 3 | ||||
-rw-r--r-- | wydawca/triplet.c | 324 | ||||
-rw-r--r-- | wydawca/verify.c | 145 | ||||
-rw-r--r-- | wydawca/wydawca.c | 34 | ||||
-rw-r--r-- | wydawca/wydawca.h | 55 | ||||
-rw-r--r-- | wydawca/wydawca.rc | 80 |
16 files changed, 987 insertions, 152 deletions
@@ -1,3 +1,55 @@ +2007-08-26 Sergey Poznyakoff <gray@gnu.org.ua> + + Implement project owner notifications. + + * wydawca/wydawca.c (syslog_printer): Reduce the number of memory + reallocations + (make_stat_expansion): Update + * wydawca/method.c: Implement a new framework: methods may return + 2-dimensional arrays of strings. + * wydawca/sql.c, wydawca/sql.h: Implement the new method framework. + * wydawca/verify.c (expand_param): kw_expansion may provide + expansion functions. An additional argument supplies user-defined + data for expansions. + (escape_kwexp): Extern + (free_kwexp): Improve + (get_project_name): New function + (make_default_kwexp): New function + (check_access_rights): Call get_project_name. Use + make_default_kwexp to initialize expansions + (verify_directive_file): Use make_default_kwexp to initialize + expansions + * wydawca/wydawca.h (NITEMS): New macro + (enum access_method_type): New members: ncol, nrow + (struct directory_pair): New members url,project_owner_method, + user_data_method + (struct file_info): Replace mtime, uid with struct stat sb + (struct file_triplet): New members project, dpair, user_data + (TRIPLET_UID): Take into account the changes to struct file_info + (enum notification_event): New data type + (notify_project_owner, notify_admin, notify): New functions + (struct kw_expansion): New members static_p, expand and data. + (escape_kwexp,make_default_kwexp): New proto + (expand_param): Change signature + (triplet_expand_param): New function + (method_result): Change prototype + (method_num_rows,method_num_cols): New functions + * wydawca/config.c: New statements project-owner, user-data, + admin-address, mail-user, user-message + directory can take an optional argument specifying base URL for + notification messages + * wydawca/gpg.c (verify_directive_signature): Expand directives + even if the signature does not match. Useful for notifications. + Add notifications. + * wydawca/process.c: Add notifications. + * wydawca/directive.c: Add notifications + * wydawca/wydawca.rc: Update + * wydawca/mail.c, wydawca/mail.h: Implement project owner + notifications + * wydawca/triplet.c (triplet_expand_param): New function + + * lib/cfg.c (read_cont_line): Fix counting of input lines. + 2007-08-25 Sergey Poznyakoff <gray@gnu.org.ua> * configure.ac: Require mailutils for wydawca @@ -40,29 +40,31 @@ find_cfg_fun (struct gsc_config_keyword *kwtab, char *kw) } ssize_t -read_cont_line (char **pbuf, size_t *psize, FILE *fp) +read_cont_line (gsc_config_file_t *file) { ssize_t rc; - char *buf = *pbuf; - size_t size = *psize; ssize_t len = rc; - len = getline (&buf, &size, fp); + len = getline (&file->buf, &file->size, file->fp); + file->line++; + if (len <= 0) return len; - buf[--len] = 0; - if (len > 0 && buf[len-1] == '\\') + file->buf[--len] = 0; + if (len > 0 && file->buf[len-1] == '\\') { - size_t newsize = size; + size_t newsize = file->size; char *newbuf = x2realloc (NULL, &newsize); - strcpy (newbuf, buf); + strcpy (newbuf, file->buf); do { - rc = getline (&buf, &size, fp); + rc = getline (&file->buf, &file->size, file->fp); if (rc <= 0) break; - buf[--rc] = 0; + file->line++; + + file->buf[--rc] = 0; newbuf[--len] = 0; len += rc; if (len + 1 > newsize) @@ -70,15 +72,13 @@ read_cont_line (char **pbuf, size_t *psize, FILE *fp) newsize = len + 1; newbuf = x2realloc (newbuf, &newsize); } - strcat (newbuf, buf); + strcat (newbuf, file->buf); } - while (rc > 0 && buf[rc-1] == '\\'); - free (buf); - buf = newbuf; - size = newsize; + while (rc > 0 && file->buf[rc-1] == '\\'); + free (file->buf); + file->buf = newbuf; + file->size = newsize; } - *pbuf = buf; - *psize = size; return len + 1; } @@ -86,13 +86,12 @@ void gsc_config_parse_block (gsc_config_file_t *file, void *data, struct gsc_config_keyword *kwtab, const char *end) { - while (read_cont_line (&file->buf, &file->size, file->fp) > 0) + while (read_cont_line (file) > 0) { size_t len; char *p, *kw, *val = NULL; gsc_config_fun fun; - file->line++; for (p = file->buf; *p && isspace (*p); p++) ; if (*p == '#' || *p == 0) diff --git a/wydawca/config.c b/wydawca/config.c index 559e995..81db423 100644 --- a/wydawca/config.c +++ b/wydawca/config.c @@ -27,9 +27,13 @@ static struct obstack cfg_stk; static struct access_method default_verify_method; static struct access_method default_gpg_key_method; +static struct access_method default_project_owner_method; +static struct access_method default_user_data_method; static struct archive_descr default_archive_descr; +#define ISHSPACE(c) ((c)==' ' || (c)=='\t') #define skip_ws(s) while (*(s) && isspace (*(s))) (s)++; +#define skip_hws(s) while (*(s) && ISHSPACE (*(s))) (s)++; #define skip_word(s) while (*(s) && !isspace (*(s))) (s)++; /* Return a pointer to the next word from *PSTR. Advanse *PSTR to the beginning @@ -40,6 +44,12 @@ get_word (char **pstr) char *word; char *str = *pstr; + if (!str) + { + *pstr = ""; + return *pstr; + } + skip_ws (str); word = str; @@ -319,6 +329,30 @@ cfg_gpg_key (gsc_config_file_t *file, char *kw, char *val, void *data) _cfg_access_method (file, kw, val, method); } +static void +cfg_project_owner (gsc_config_file_t *file, char *kw, char *val, void *data) +{ + struct directory_pair *dp = data; + struct access_method *method; + if (dp) + method = dp->project_owner_method = method_new (method_builtin); + else + method = &default_project_owner_method; + _cfg_access_method (file, kw, val, method); +} + +static void +cfg_user_data (gsc_config_file_t *file, char *kw, char *val, void *data) +{ + struct directory_pair *dp = data; + struct access_method *method; + if (dp) + method = dp->user_data_method = method_new (method_builtin); + else + method = &default_user_data_method; + _cfg_access_method (file, kw, val, method); +} + static char const * const backup_args[] = { /* In a series of synonyms, present the most meaningful first, so @@ -447,6 +481,7 @@ static void cfg_directory (gsc_config_file_t *file, char *kw, char *val, void *unused) { int ec; + char *word; struct directory_pair dpair; static struct gsc_config_keyword keywords[] = { { "source", cfg_source }, @@ -454,18 +489,27 @@ cfg_directory (gsc_config_file_t *file, char *kw, char *val, void *unused) { "file-sweep-time", cfg_file_sweep_time }, { "verify-user", cfg_verify_user }, { "gpg-key", cfg_gpg_key }, + { "project-owner", cfg_project_owner }, + { "user-data", cfg_user_data }, { "archive", cfg_archive }, { NULL } }; - if (val) + memset (&dpair, 0, sizeof dpair); + word = get_word (&val); + if (!word) + dpair.url = NULL; + else + dpair.url = xstrdup (word); + if (val && val[0]) file->error_msg (file->file_name, file->line, "warning: junk in line ignored"); - memset (&dpair, 0, sizeof dpair); dpair.file_sweep_time = file_sweep_time; dpair.verify_method = &default_verify_method; dpair.gpg_key_method = &default_gpg_key_method; + dpair.project_owner_method = &default_project_owner_method; + dpair.user_data_method = &default_user_data_method; dpair.archive = default_archive_descr; gsc_config_parse_block (file, &dpair, keywords, "end"); @@ -799,21 +843,32 @@ _cfg_raw_read (gsc_config_file_t *file, char *val, struct obstack *stk) char *word = val ? get_word (&val) : ""; size_t wlen; size_t start_line = file->line; - + int skip_initial_ws = 0; + if (word[0] == 0) word = "end"; + if (word[0] == '-') + { + skip_initial_ws = 1; + word++; + } wlen = strlen (word); while (getline (&buf, &size, file->fp) > 0) { + char *p = buf; + file->line++; - if (end_marker_p (buf, word, wlen)) + + if (skip_initial_ws) + skip_hws (p); + if (end_marker_p (p, word, wlen)) { obstack_1grow (stk, 0); free (buf); return 0; } - obstack_grow (stk, buf, strlen (buf)); + obstack_grow (stk, p, strlen (p)); } file->error_msg (file->file_name, start_line, "missing end marker"); @@ -831,6 +886,95 @@ cfg_admin_stat_message (gsc_config_file_t *file, char *kw, char *val, +static const char *event_args[] = { + "success", + "bad_ownership", + "bad-ownership", + "bad_directive_signature", + "bad-directive-signature", + "bad_detached_signature", + "bad-detached-signature", + NULL +}; + +static enum notification_event event_types[] = { + ev_success, + ev_bad_ownership, + ev_bad_ownership, + ev_bad_directive_signature, + ev_bad_directive_signature, + ev_bad_detached_signature, + ev_bad_detached_signature +}; + +ARGMATCH_VERIFY (event_args, event_types); + +int +string_to_notification_event (gsc_config_file_t *file, char *val, + enum notification_event *pret) +{ + ptrdiff_t x = ARGMATCH (val, event_args, event_types); + + if (x == (ptrdiff_t)-1) + { + file->error_msg (file->file_name, file->line, + "unknown notification type: %s", val); + file->error_count++; + return 1; + } + *pret = event_types[x]; + return 0; +} + +static void +cfg_mail_user (gsc_config_file_t *file, char *kw, char *val, void *unused) +{ + int i; + int argc; + char **argv; + + if (argcv_get (val, NULL, NULL, &argc, &argv)) + { + file->error_msg (file->file_name, file->line, + "cannot parse value: %s", strerror (errno)); + file->error_count++; + return; + } + + for (i = 0; i < argc; i++) + { + enum notification_event evt; + + if (string_to_notification_event (file, argv[i], &evt)) + break; + owner_notification_flags |= STAT_MASK (evt); + } + argcv_free (argc, argv); +} + +static void +cfg_user_message (gsc_config_file_t *file, char *kw, char *val, void *unused) +{ + enum notification_event evt; + char *word = get_word (&val); + + if (!*word) + { + file->error_msg (file->file_name, file->line, + "not enough arguments"); + file->error_count++; + return; + } + + if (string_to_notification_event (file, word, &evt)) + return; + + if (_cfg_raw_read (file, val, &cfg_stk) == 0) + user_message_template[evt] = obstack_finish (&cfg_stk); +} + + + static struct gsc_config_keyword kw_handler[] = { { "syslog-tag", cfg_syslog_tag }, { "syslog-facility", cfg_syslog_facility }, @@ -841,14 +985,18 @@ static struct gsc_config_keyword kw_handler[] = { { "sql", cfg_sql }, { "verify-user", cfg_verify_user }, { "gpg-key", cfg_gpg_key }, + { "project-owner", cfg_project_owner }, + { "user-data", cfg_user_data }, { "umask", cfg_umask }, { "tar-program", cfg_tar_program }, { "archive", cfg_archive }, { "mailer", cfg_mailer }, - { "admin-addres", cfg_admin_address }, + { "admin-address", cfg_admin_address }, { "from-address", cfg_from_address }, { "mail-admin-stat", cfg_mail_admin_stat }, { "admin-stat-message", cfg_admin_stat_message }, + { "mail-user", cfg_mail_user }, + { "user-message", cfg_user_message }, { NULL } }; @@ -857,6 +1005,8 @@ parse_config () { default_verify_method.type = method_builtin; default_gpg_key_method.type = method_builtin; + default_project_owner_method.type = method_none; + default_user_data_method.type = method_none; default_archive_descr.type = archive_none; default_archive_descr.backup_type = no_backups; diff --git a/wydawca/directive.c b/wydawca/directive.c index cc9ed1d..24e31f1 100644 --- a/wydawca/directive.c +++ b/wydawca/directive.c @@ -400,5 +400,6 @@ process_directives (struct file_triplet *trp, struct directory_pair *dpair) free (relative_dir); UPDATE_STATS (STAT_TRIPLET_SUCCESS); + notify (trp, ev_success); return 0; } diff --git a/wydawca/gpg.c b/wydawca/gpg.c index 3372c7b..eb2a64a 100644 --- a/wydawca/gpg.c +++ b/wydawca/gpg.c @@ -224,20 +224,22 @@ verify_directive_signature (struct file_triplet *trp, { gpgme_verify_result_t result; + size = gpgme_data_seek (plain, 0, SEEK_END); + gpgme_data_seek (plain, 0, SEEK_SET); + trp->blurb = xmalloc (size + 1); + gpgme_data_read (plain, trp->blurb, size); + trp->blurb[size] = 0; + gpgme_data_release (plain); + + rc = directive_parse (trp); + result = gpgme_op_verify_result (ctx); - if (gpg_sig_ok_p (ctx, result->signatures)) + if (!gpg_sig_ok_p (ctx, result->signatures)) { - size = gpgme_data_seek (plain, 0, SEEK_END); - gpgme_data_seek (plain, 0, SEEK_SET); - trp->blurb = xmalloc (size + 1); - gpgme_data_read (plain, trp->blurb, size); - trp->blurb[size] = 0; - gpgme_data_release (plain); - - rc = directive_parse (trp); + UPDATE_STATS (STAT_BAD_SIGNATURE); + notify (trp, ev_bad_directive_signature); + rc = 1; } - else - rc = 1; } else { @@ -245,7 +247,6 @@ verify_directive_signature (struct file_triplet *trp, UPDATE_STATS (STAT_BAD_SIGNATURE); logmsg (LOG_ERR, "%s: directive verification failed: %s", trp->name, gpgme_strerror (ec)); - /* FIXME: Send mail to the project maintainer */ } gpgme_data_release (directive_data); @@ -292,6 +293,7 @@ verify_detached_signature (struct file_triplet *trp, case exec_fail: UPDATE_STATS (STAT_BAD_SIGNATURE); logmsg (LOG_ERR, "BAD detached signature for %s", trp->name); + notify (trp, ev_bad_detached_signature); break; case exec_error: diff --git a/wydawca/mail.c b/wydawca/mail.c index 0f91ebd..81bf085 100644 --- a/wydawca/mail.c +++ b/wydawca/mail.c @@ -23,6 +23,8 @@ mu_address_t admin_address; mu_address_t from_address; unsigned long mail_admin_mask; char *admin_stat_message_template; +unsigned long owner_notification_flags; +char *user_message_template[MAX_EVENT]; void mail_init () @@ -49,6 +51,8 @@ mail_send_message (mu_address_t rcpt, const char *text) mu_header_t hdr; int mailer_flags = 0; static char *x_mailer = "wydawca (" PACKAGE_STRING ")"; + size_t size; + char *buf; mu_message_create (&msg, NULL); @@ -57,6 +61,13 @@ mail_send_message (mu_address_t rcpt, const char *text) mu_message_get_header (msg, &hdr); mu_header_append (hdr, "X-Mailer", x_mailer); + mu_address_to_string (rcpt, NULL, 0, &size); + buf = xmalloc (size + 1); + mu_address_to_string (rcpt, buf, size + 1, NULL); + + mu_header_set_value (hdr, "To", buf, 1); + free (buf); + if (debug_level > 1) { mu_debug_t debug; @@ -114,10 +125,12 @@ mail_stats () exp[0].kw = "date"; exp[0].value = xstrdup (ctime (&t)); exp[0].value [strlen (exp[0].value) - 1] = 0; + exp[0].expand = NULL; + make_stat_expansion (exp + 1); text = expand_param (admin_stat_message_template, - exp, sizeof (exp) / sizeof (exp[0])); + exp, sizeof (exp) / sizeof (exp[0]), NULL); mail_send_message (admin_address, text); @@ -131,3 +144,91 @@ mail_finish () if (mailer_opened) mu_mailer_close (mailer); } + +void +notify_owner (struct file_triplet *trp, enum notification_event ev) +{ + int rc; + struct access_method *method = trp->dpair->project_owner_method; + char *text; + mu_address_t rcpt = NULL; + unsigned nrows, ncols, i; + struct kw_expansion kwexp[4]; + + if (method->type == method_none) + { + logmsg (LOG_NOTICE, + "NOT notifying project admins: project-owner not configured in " + "[%s, %s]", trp->dpair->source_dir, trp->dpair->dest_dir); + return; + } + + if (method_init (method)) + { + logmsg (LOG_ERR, + "failed to initialize project-owner method: " + "NOT notifying project admins"); + return; + } + + make_default_kwexp (kwexp, NULL, trp->project); + escape_kwexp (method, kwexp, NITEMS (kwexp)); + text = expand_param (method->param[1], kwexp, NITEMS (kwexp), NULL); + + rc = method_run (method, text); + free (text); + if (rc) + { + logmsg (LOG_ERR, "cannot obtain owner emails for %s", + trp->project); + return; + } + + nrows = method_num_rows (method); + ncols = method_num_cols (method); + + for (i = 0; i < nrows; i++) + { + mu_address_t addr; + const char *str = method_result (method, i, 0); + if (mu_address_create (&addr, str)) + continue; + if (ncols > 0) + { + str = method_result (method, i, 1); + if (str) + mu_address_set_personal (addr, 1, str); + } + mu_address_union (&rcpt, addr); + mu_address_destroy (&addr); + } + + if (debug_level) + { + size_t size; + char *buf; + mu_address_to_string (rcpt, NULL, 0, &size); + buf = xmalloc (size + 1); + mu_address_to_string (rcpt, buf, size + 1, NULL); + logmsg (LOG_DEBUG, "Notifying admins of %s: %s", trp->project, + buf); + free (buf); + } + + if (!dry_run_mode) + { + text = triplet_expand_param (user_message_template[ev], trp); + mail_send_message (rcpt, text); + free (text); + } + + mu_address_destroy (&rcpt); +} + +void +notify (struct file_triplet *trp, enum notification_event ev) +{ + if (owner_notification_flags & STAT_MASK (ev)) + notify_owner (trp, ev); + /* FIXME */ +} diff --git a/wydawca/mail.h b/wydawca/mail.h index 7faedfb..02c95b7 100644 --- a/wydawca/mail.h +++ b/wydawca/mail.h @@ -21,7 +21,10 @@ extern mu_address_t admin_address; extern mu_address_t from_address; extern unsigned long mail_admin_mask; extern char *admin_stat_message_template; +extern unsigned long owner_notification_flags; +extern char *user_message_template[MAX_EVENT]; void mail_init (void); void mail_finish (void); void mail_stats (void); + diff --git a/wydawca/method.c b/wydawca/method.c index 114328f..d0fa2cb 100644 --- a/wydawca/method.c +++ b/wydawca/method.c @@ -21,15 +21,19 @@ struct method_descr { const char *name; int (*init) (struct access_method *); - int (*done) (struct access_method *); + int (*done) (struct access_method *); + int (*free) (struct access_method *); + int (*get) (struct access_method *method, unsigned nrow, unsigned ncol); + int (*run) (struct access_method *, const char *); }; static struct method_descr method_tab[] = { - { "none", NULL, NULL, NULL }, - { "sql", sql_init_method, sql_done_method, sql_run_method }, - { "builtin", NULL, NULL, NULL }, - { "external", NULL, NULL, NULL } + { "none", NULL, NULL, NULL, NULL, NULL }, + { "sql", sql_init_method, sql_done_method, sql_free_result, + sql_get_method, sql_run_method }, + { "builtin", NULL, NULL, NULL, NULL, NULL }, + { "external", NULL, NULL, NULL, NULL, NULL } }; struct access_method * @@ -101,13 +105,31 @@ method_run (struct access_method *method, const char *cmd) mp->name, method->param[0]); return 1; } - + if (mp->free) + mp->free (method); return mp->run (method, cmd); } +unsigned +method_num_rows (struct access_method *method) +{ + return method->nrow; +} + +unsigned +method_num_cols (struct access_method *method) +{ + return method->ncol; +} + const char * -method_result (struct access_method *method) +method_result (struct access_method *method, unsigned nrow, unsigned ncol) { + struct method_descr *mp = method_tab + method->type; + + if (nrow >= method->nrow || ncol >= method->ncol + || mp->get (method, nrow, ncol)) + return NULL; return method->result; } diff --git a/wydawca/process.c b/wydawca/process.c index ad911a7..a5c6f05 100644 --- a/wydawca/process.c +++ b/wydawca/process.c @@ -152,8 +152,7 @@ scan_directory_pair (struct directory_pair *dpair) continue; } - finfo.mtime = st.st_mtime; - finfo.uid = st.st_uid; + finfo.sb = st; parse_file_name (ent->d_name, &finfo); if (debug_level) @@ -180,6 +179,8 @@ close_methods (struct directory_pair *dpair) { method_done (dpair->verify_method); method_done (dpair->gpg_key_method); + method_done (dpair->project_owner_method); + method_done (dpair->user_data_method); } /* Scan all configured update directories */ diff --git a/wydawca/sql.c b/wydawca/sql.c index c1de81d..ff358a5 100644 --- a/wydawca/sql.c +++ b/wydawca/sql.c @@ -83,6 +83,18 @@ sql_init_method (struct access_method *method) return 0; } +int +sql_free_result (struct access_method *method) +{ + struct sqlconn *conn = method->v.sqlconn; + if (conn->result) + { + mysql_free_result (conn->result); + conn->result = NULL; + } + return 0; +} + /* Finish the initialized MySQL access method */ int sql_done_method (struct access_method *method) @@ -92,7 +104,8 @@ sql_done_method (struct access_method *method) return 0; if (--conn->initcount) return 0; - mysql_close (&method->v.sqlconn->mysql); + sql_free_result (method); + mysql_close (&conn->mysql); return 0; } @@ -100,11 +113,8 @@ sql_done_method (struct access_method *method) int sql_run_method (struct access_method *method, const char *query) { - MYSQL *mysql = &method->v.sqlconn->mysql; - MYSQL_RES *result; - MYSQL_ROW row; - long n; - size_t len; + struct sqlconn *conn = method->v.sqlconn; + MYSQL *mysql = &conn->mysql; if (mysql_query (mysql, query)) { @@ -113,42 +123,43 @@ sql_run_method (struct access_method *method, const char *query) return 1; } - result = mysql_store_result (mysql); - if (!result) + conn->result = mysql_store_result (mysql); + if (!conn->result) { - logmsg (LOG_ERR, "Query returned 0 tuples"); + logmsg (LOG_ERR, "Cannot get result: %s", mysql_error (mysql)); logmsg (LOG_NOTICE, "The failed query was: %s", query); return 1; } - - n = mysql_num_rows (result); - if (n != 1) - { - logmsg (LOG_NOTICE, "Query returned %ld tuples", n); - logmsg (LOG_NOTICE, "The query was: %s", query); - if (n == 0) - return 1; - } - n = mysql_num_fields (result); - if (n != 1) + method->nrow = mysql_num_rows (conn->result); + method->ncol = mysql_num_fields (conn->result); + if (debug_level > 1) { - logmsg (LOG_NOTICE, "Query returned %ld fields", n); - logmsg (LOG_NOTICE, "The query was: %s", query); + logmsg (LOG_DEBUG, "Query returned %u columns in %u rows", + method->ncol, method->nrow); + logmsg (LOG_DEBUG, "The query was: %s", query); } - row = mysql_fetch_row (result); - if (row[0] == NULL) + return 0; +} + +int +sql_get_method (struct access_method *method, unsigned nrow, unsigned ncol) +{ + struct sqlconn *conn = method->v.sqlconn; + MYSQL_ROW row; + size_t len; + + if (!conn->result) + return 1; + mysql_data_seek (conn->result, nrow); + row = mysql_fetch_row (conn->result); + if (row[ncol] == NULL) len = 0; else - len = trim_length (row[0]); + len = trim_length (row[ncol]); - method_copy_result (method, row[0], len); - - mysql_free_result (result); - + method_copy_result (method, row[ncol], len); return 0; } - - diff --git a/wydawca/sql.h b/wydawca/sql.h index 6b2e6c4..2af0b97 100644 --- a/wydawca/sql.h +++ b/wydawca/sql.h @@ -27,6 +27,7 @@ struct sqlconn char *password; size_t initcount; /* Number of initializations */ MYSQL mysql; + MYSQL_RES *result; }; void sql_register_conn (struct sqlconn *); @@ -36,3 +37,5 @@ struct sqlconn *sql_find_connection (const char *ident); int sql_init_method (struct access_method *method); int sql_done_method (struct access_method *method); int sql_run_method (struct access_method *method, const char *cmd); +int sql_get_method (struct access_method *method, unsigned nrow, unsigned ncol); +int sql_free_result (struct access_method *method); diff --git a/wydawca/triplet.c b/wydawca/triplet.c index daf3265..46c6011 100644 --- a/wydawca/triplet.c +++ b/wydawca/triplet.c @@ -51,7 +51,14 @@ hash_triplet_free (void *data) free (tp->directive); free (tp->blurb); free (tp->tmp); - + + if (tp->user_data) + { + for (i = 0; i < NITEMS (tp->user_data); i++) + free (tp->user_data[i]); + free (tp->user_data); + } + free (tp); } @@ -96,7 +103,7 @@ triplet_expired_p (struct file_triplet *trp, time_t ttl) for (i = 0; i < FILE_TYPE_COUNT; i++) { if (trp->file[i].name - && (now - trp->file[i].mtime) > ttl) + && (now - trp->file[i].sb.st_mtime) > ttl) { if (debug_level) logmsg (LOG_DEBUG, "File %s expired", trp->file[i].name); @@ -131,8 +138,10 @@ check_triplet_state (struct file_triplet *trp) else if (trp->file[file_dist].name && trp->file[file_signature].name) { - if (trp->file[file_dist].uid == trp->file[file_signature].uid - && trp->file[file_dist].uid == trp->file[file_directive].uid) + if (trp->file[file_dist].sb.st_uid == + trp->file[file_signature].sb.st_uid + && trp->file[file_dist].sb.st_uid == + trp->file[file_directive].sb.st_uid) return triplet_complete; else { @@ -172,6 +181,8 @@ triplet_processor (void *data, void *proc_data) struct file_triplet *trp = data; struct directory_pair *dpair = proc_data; + trp->dpair = dpair; + if (debug_level) logmsg (LOG_DEBUG, "FILE %s, DIST=%s, SIG=%s, DIRECTIVE=%s", trp->name, @@ -234,3 +245,308 @@ count_collected_triplets () return triplet_table ? hash_get_n_entries (triplet_table) : 0; } + +static char * +expand_project_base (struct kw_expansion *exp, void *data) +{ + struct file_triplet *trp = data; + return trp->project; +} + +static char * +expand_url (struct kw_expansion *exp, void *data) +{ + struct file_triplet *trp = data; + return trp->dpair->url; +} + +static char * +expand_relative_dir (struct kw_expansion *exp, void *data) +{ + struct file_triplet *trp = data; + directive_get_value (trp, "directory", &exp->value); + exp->static_p = 1; + return exp->value; +} + +static char * +expand_dest_dir (struct kw_expansion *exp, void *data) +{ + struct file_triplet *trp = data; + return trp->dpair->dest_dir; +} + +static char * +expand_source_dir (struct kw_expansion *exp, void *data) +{ + struct file_triplet *trp = data; + return trp->dpair->source_dir; +} + +static void +decode_file_mode (mode_t mode, char *string) +{ + *string++ = mode & S_IRUSR ? 'r' : '-'; + *string++ = mode & S_IWUSR ? 'w' : '-'; + *string++ = (mode & S_ISUID + ? (mode & S_IXUSR ? 's' : 'S') + : (mode & S_IXUSR ? 'x' : '-')); + *string++ = mode & S_IRGRP ? 'r' : '-'; + *string++ = mode & S_IWGRP ? 'w' : '-'; + *string++ = (mode & S_ISGID + ? (mode & S_IXGRP ? 's' : 'S') + : (mode & S_IXGRP ? 'x' : '-')); + *string++ = mode & S_IROTH ? 'r' : '-'; + *string++ = mode & S_IWOTH ? 'w' : '-'; + *string++ = (mode & S_ISVTX + ? (mode & S_IXOTH ? 't' : 'T') + : (mode & S_IXOTH ? 'x' : '-')); + *string = '\0'; +} + +/* Width of "user/group size", with initial value chosen + heuristically. This grows as needed, though this may cause some + stairstepping in the output. Make it too small and the output will + almost always look ragged. Make it too large and the output will + be spaced out too far. */ +static int ugswidth = 19; + +static int +format_file_data (struct file_triplet *trp, enum file_type type, char **pret) +{ + char modes[11]; + struct file_info *info = trp->file + type; + char timebuf[sizeof "YYYY-MM-DD HH:MM:SS +0000"]; |