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 | b89ece30bebb5b9dd06e4e061537b6bf068566f2 (patch) | |
tree | c7f65b64fccfac2f0e7e134e5f7666a4fb1907d1 /src/triplet.c | |
parent | 338c0d9c35c56f35c636df1c1da0852a466e731f (diff) | |
download | wydawca-b89ece30bebb5b9dd06e4e061537b6bf068566f2.tar.gz wydawca-b89ece30bebb5b9dd06e4e061537b6bf068566f2.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/wydawca/trunk@297 6bb4bd81-ecc2-4fd4-a2d4-9571d19c0d33
Diffstat (limited to 'src/triplet.c')
-rw-r--r-- | src/triplet.c | 324 |
1 files changed, 320 insertions, 4 deletions
diff --git a/src/triplet.c b/src/triplet.c index daf3265..46c6011 100644 --- a/src/triplet.c +++ b/src/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"]; + struct passwd *pw; + struct group *grp; + char sbuf[INT_BUFSIZE_BOUND (uintmax_t)]; + char *sptr; + size_t slen; + int pad; + char *user_name; + char *group_name; + struct tm *tm; + char *buf; + + if (!info->name) + return 1; + + /* MODE OWNER GROUP SIZE MTIME FILE_NAME MD5SUM? */ + + modes[0] = '-'; /* Only regular files are allowed */ + decode_file_mode (info->sb.st_mode, modes + 1); + + /* File time */ + tm = localtime (&info->sb.st_mtime); + strftime (timebuf, sizeof timebuf, "%Y-%m-%d %H:%M:%S %z", tm); + + /* FIXME: owner and group name should be store in TRP after verification */ + pw = getpwuid (TRIPLET_UID (trp)); + if (!pw) + user_name = "UNKNOWN"; /* should not happen */ + else + user_name = pw->pw_name; + + grp = getgrgid (TRIPLET_GID (trp)); + if (!grp) + group_name = "UNKNOWN"; /* should not happen */ + else + group_name = grp->gr_name; + + /* Size */ + sptr = umaxtostr (info->sb.st_size, sbuf); + + /* Figure out padding and format the buffer */ + slen = strlen (sptr); + pad = strlen (user_name) + 1 + strlen (group_name) + 1 + slen; + if (pad > ugswidth) + ugswidth = pad; + + asprintf (&buf, + "%s %s %s %*s %s %s", + modes, user_name, group_name, ugswidth - pad + slen, sptr, + timebuf, info->name); + *pret = buf; + return 0; +} + +static char * +expand_triplet_full (struct kw_expansion *exp, void *data) +{ + struct file_triplet *trp = data; + char *buf[FILE_TYPE_COUNT] = { NULL, NULL, NULL }; + + format_file_data (trp, file_dist, &buf[file_dist]); + format_file_data (trp, file_signature, &buf[file_signature]); + format_file_data (trp, file_directive, &buf[file_directive]); + + exp->value = xmalloc (strlen (buf[file_dist]) + 1 + + strlen (buf[file_signature]) + 1 + + strlen (buf[file_directive]) + 1); + sprintf (exp->value, "%s\n%s\n%s", buf[file_dist], buf[file_signature], + buf[file_directive]); + + free (buf[file_dist]); + free (buf[file_signature]); + free (buf[file_directive]); + + exp->static_p = 0; + return exp->value; +} + +static char * +expand_triplet_upload (struct kw_expansion *exp, void *data) +{ + struct file_triplet *trp = data; + char *buf[2] = { NULL, NULL }; + + format_file_data (trp, file_dist, &buf[file_dist]); + format_file_data (trp, file_signature, &buf[file_signature]); + + exp->value = xmalloc (strlen (buf[file_dist]) + 1 + + strlen (buf[file_signature]) + 1); + sprintf (exp->value, "%s\n%s", buf[file_dist], buf[file_signature]); + + free (buf[file_dist]); + free (buf[file_signature]); + + exp->static_p = 0; + return exp->value; +} + +static char * +expand_triplet_dist (struct kw_expansion *exp, void *data) +{ + struct file_triplet *trp = data; + format_file_data (trp, file_dist, &exp->value); + exp->static_p = 0; + return exp->value; +} + +static char * +expand_triplet_sig (struct kw_expansion *exp, void *data) +{ + struct file_triplet *trp = data; + format_file_data (trp, file_signature, &exp->value); + exp->static_p = 0; + return exp->value; +} + +static char * +expand_triplet_directive (struct kw_expansion *exp, void *data) +{ + struct file_triplet *trp = data; + format_file_data (trp, file_directive, &exp->value); + exp->static_p = 0; + return exp->value; +} + +static char * +expand_user_name (struct kw_expansion *exp, void *data) +{ + struct passwd *pw; + struct file_triplet *trp = data; + + /* FIXME: should user name be stored in the triplet? */ + pw = getpwuid (TRIPLET_UID (trp)); + if (!pw) + return NULL; + exp->value = xstrdup (pw->pw_name); + exp->static_p = 0; + return exp->value; +} + +static void +fill_user_data (struct file_triplet *trp) +{ + int rc; + struct access_method *method = trp->dpair->user_data_method; + char *text; + unsigned nrows, ncols; + struct kw_expansion kwexp[4]; + struct passwd *pw; + + if (trp->user_data) + return; + + if (method->type == method_none) + return; + + if (method_init (method)) + return; + + pw = getpwuid (TRIPLET_UID (trp)); + if (!pw) + return; + make_default_kwexp (kwexp, pw->pw_name, 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) + return; + + nrows = method_num_rows (method); + ncols = method_num_cols (method); + + if (nrows > 0) + { + int i; + trp->user_data = xcalloc (ncols, sizeof (trp->user_data[0])); + for (i = 0; i < ncols; i++) + { + const char *str = method_result (method, 0, i); + if (str) + trp->user_data[i] = xstrdup (str); + } + } +} + +static char * +expand_user_real_name (struct kw_expansion *exp, void *data) +{ + struct file_triplet *trp = data; + fill_user_data (trp); + if (trp->user_data[0]) + return trp->user_data[0]; + exp->value = "UNKNOWN"; + exp->static_p = 1; + return exp->value; +} + +static char * +expand_user_email (struct kw_expansion *exp, void *data) +{ + struct file_triplet *trp = data; + fill_user_data (trp); + if (trp->user_data[1]) + return trp->user_data[1]; + exp->value = "UNKNOWN"; + exp->static_p = 1; + return exp->value; +} + +struct kw_expansion triplet_exp[] = { + { "project", NULL, 0, expand_project_base, NULL }, + { "url", NULL, 0, expand_url, NULL }, + { "dir", NULL, 0, expand_relative_dir, NULL }, + { "dest-dir", NULL, 0, expand_dest_dir, NULL }, + { "source-dir", NULL, 0, expand_source_dir, NULL }, + { "triplet:full", NULL, 0, expand_triplet_full, NULL }, + { "triplet:upload", NULL, 0, expand_triplet_upload, NULL }, + { "triplet:dist", NULL, 0, expand_triplet_dist, NULL }, + { "triplet:sig", NULL, 0, expand_triplet_sig, NULL }, + { "triplet:dir", NULL, 0, expand_triplet_directive, NULL }, + { "user", NULL, 0, expand_user_name, NULL }, + { "user:name", NULL, 0, expand_user_name, NULL }, + { "user:real-name", NULL, 0, expand_user_real_name, NULL }, + { "user:email", NULL, 0, expand_user_email, NULL }, +}; + +char * +triplet_expand_param (const char *tmpl, struct file_triplet *trp) +{ + free_kwexp (triplet_exp, NITEMS (triplet_exp)); + return expand_param (tmpl, triplet_exp, NITEMS (triplet_exp), trp); +} |