diff options
author | Daniel Borkmann <daniel@iogearbox.net> | 2019-10-01 20:29:21 +0200 |
---|---|---|
committer | Daniel Borkmann <daniel@iogearbox.net> | 2019-10-01 20:53:20 +0200 |
commit | 20d4421a5686afccbe0568f1ecca6992b8fcf2d7 (patch) | |
tree | 56e952bb30c1caf7034868a7f5b79144a4e07ba8 | |
parent | 4740bcd111b9c106b426a4bb9807917e9a17d4fe (diff) | |
download | l2md-20d4421a5686afccbe0568f1ecca6992b8fcf2d7.tar.gz |
l2md: make output modular to support different modes
Refactor the output handling of new mails in order to allow adding
new modes as next step.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | config.c | 46 | ||||
-rw-r--r-- | env.c | 11 | ||||
-rw-r--r-- | l2md.h | 21 | ||||
-rw-r--r-- | mail.c | 14 | ||||
-rw-r--r-- | maildir.c | 40 | ||||
-rw-r--r-- | repo.c | 8 |
7 files changed, 97 insertions, 45 deletions
@@ -1,7 +1,7 @@ CFLAGS = -O2 -Wall -Werror LDFLAGS = -lgit2 -l2md: l2md.o config.o env.o utils.o repo.o mail.o +l2md: l2md.o config.o env.o utils.o repo.o mail.o maildir.o $(CC) -o $@ $^ $(LDFLAGS) install: @@ -27,11 +27,12 @@ static void config_dump(struct config *cfg) return; verbose("general.base = %s\n", cfg->general.base); - verbose("general.maildir = %s\n", cfg->general.maildir); + verbose("general.mode = %s\n", cfg->ops->name); + verbose("general.%s = %s\n", cfg->ops->name, cfg->general.out); verbose("general.period = %u\n", cfg->general.period); repo_for_each(cfg, repo, i) { - verbose("repos.%s.maildir = %s\n", repo->name, repo->maildir); + verbose("repos.%s.%s = %s\n", repo->name, cfg->ops->name, repo->out); verbose("repos.%s.initial_import = %u\n", repo->name, repo->initial_import); url_for_each(repo, url, j) { verbose("repos.%s.url = %s\n", repo->name, url->path); @@ -70,15 +71,23 @@ static void config_set_basedir(struct config *cfg, const char *dir) wordfree(&p); } -static void config_set_maildir(struct config *cfg, const char *dir, bool root) +static void config_set_mode(struct config *cfg, const char *mode) +{ + if (!strncmp(mode, "maildir", sizeof("maildir"))) + cfg->ops = &ops_maildir; + else + panic("Unknown mode: %s!\n", mode); +} + +static void config_set_out(struct config *cfg, const char *ctx, bool root) { struct config_repo *repo = repo_last(cfg); - char *maildir = root ? cfg->general.maildir : repo->maildir; + char *out = root ? cfg->general.out : repo->out; wordexp_t p; - wordexp(dir, &p, 0); - dir = p.we_wordv[0]; - strlcpy(maildir, dir, sizeof(repo->maildir)); + wordexp(ctx, &p, 0); + ctx = p.we_wordv[0]; + strlcpy(out, ctx, sizeof(repo->out)); wordfree(&p); } @@ -113,7 +122,7 @@ static void config_new_repo(struct config *cfg, const char *name) cfg->repos_num); repo = repo_last(cfg); memset(repo, 0, sizeof(*repo)); - config_set_maildir(cfg, cfg->general.maildir, false); + config_set_out(cfg, cfg->general.out, false); strlcpy(repo->name, name, sizeof(repo->name)); } @@ -121,13 +130,14 @@ static void config_set_defaults(struct config *cfg, const char *homedir) { char path[PATH_MAX]; + cfg->ops = &ops_maildir; cfg->general.period = 60; slprintf(path, sizeof(path), "%s/.l2md", homedir); strlcpy(cfg->general.base, path, sizeof(cfg->general.base)); slprintf(path, sizeof(path), "%s/maildir", cfg->general.base); - strlcpy(cfg->general.maildir, path, sizeof(cfg->general.maildir)); + strlcpy(cfg->general.out, path, sizeof(cfg->general.out)); } void config_uninit(struct config *cfg) @@ -144,7 +154,7 @@ void config_uninit(struct config *cfg) struct config *config_init(int argc, char **argv) { const char *homedir = getenv("HOME"); - char buff[1024], tmp[1024]; + char buff[1024], tmp[1024] = {}; char path[PATH_MAX]; bool seen[STATE_MAX] = {}; int state = STATE_NONE; @@ -182,7 +192,7 @@ struct config *config_init(int argc, char **argv) state_next: if (!strcmp(buff, "[general]\n")) { state = STATE_GENERAL; - } else if (sscanf(buff, "[repo %[a-z0-9-]]\n", + } else if (sscanf(buff, "[repo %1023[a-z0-9-]]\n", tmp) == 1) { state = STATE_REPO; config_new_repo(cfg, tmp); @@ -196,19 +206,21 @@ struct config *config_init(int argc, char **argv) panic("[general] config must be before [repo *] config"); else if (sscanf(buff, "\tperiod = %u", &val) == 1) cfg->general.period = val; - else if (sscanf(buff, "\tmaildir = %s", tmp) == 1) - config_set_maildir(cfg, tmp, true); - else if (sscanf(buff, "\tbase = %s", tmp) == 1) + else if (sscanf(buff, "\tmode = %1023s", tmp) == 1) + config_set_mode(cfg, tmp); + else if (sscanf(buff, "\tmaildir = %1023s", tmp) == 1) + config_set_out(cfg, tmp, true); + else if (sscanf(buff, "\tbase = %1023s", tmp) == 1) config_set_basedir(cfg, tmp); else goto state_next; break; case STATE_REPO: - if (sscanf(buff, "\turl = %s", tmp) == 1) + if (sscanf(buff, "\turl = %1023s", tmp) == 1) config_new_url(cfg, tmp); - else if (sscanf(buff, "\tmaildir = %s", tmp) == 1) - config_set_maildir(cfg, tmp, false); + else if (sscanf(buff, "\tmaildir = %1023s", tmp) == 1) + config_set_out(cfg, tmp, false); else if (sscanf(buff, "\tinitial_import = %u", &val) == 1) config_set_initial_import(cfg, val); else @@ -52,16 +52,7 @@ static void bootstrap_repos(struct config *cfg) static void bootstrap_mail(struct config *cfg) { - struct config_repo *repo; - uint32_t i; - - repo_for_each(cfg, repo, i) { - xmkdir1_with_subdirs(repo->maildir); - - xmkdir2(repo->maildir, "cur"); - xmkdir2(repo->maildir, "tmp"); - xmkdir2(repo->maildir, "new"); - } + cfg->ops->bootstrap(cfg); } void bootstrap_env(struct config *cfg) @@ -34,8 +34,18 @@ #define MAIL "m" +struct config; +struct config_repo; + +struct mail_ops { + const char *name; + void (*bootstrap)(struct config *cfg); + void (*new_mail)(struct config_repo *repo, uint32_t url, + const char *oid, const void *raw, size_t len); +}; + struct config_general { - char maildir[PATH_MAX]; + char out[PATH_MAX]; char base[PATH_MAX]; uint32_t period; }; @@ -48,7 +58,7 @@ struct config_url { struct config_repo { char name[128]; - char maildir[PATH_MAX]; + char out[PATH_MAX]; git_repository *git; struct config_url *urls; uint32_t urls_num; @@ -60,6 +70,7 @@ struct config { struct config_general general; struct config_repo *repos; uint32_t repos_num; + const struct mail_ops *ops; }; #define repo_for_each(cfg, repo, i) \ @@ -79,6 +90,8 @@ struct config { extern pid_t own_pid; extern bool verbose_enabled; +extern struct mail_ops ops_maildir; + struct config *config_init(int argc, char **argv); void config_uninit(struct config *cfg); @@ -90,10 +103,10 @@ void sync_done(struct config *cfg); void repo_clone(struct config_repo *repo, struct config_url *url, const char *target); void repo_pull(struct config_repo *repo, struct config_url *url, const char *target); -void repo_walk_files(struct config *cfg, struct config_repo *repo, uint32_t which, +void repo_walk_files(struct config *cfg, struct config_repo *repo, uint32_t url, const char *path, const char *oid_last, char *oid_done, void (*repo_walker)(struct config *cfg, struct config_repo *repo, - uint32_t which, const char *oid, + uint32_t url, const char *oid, const void *raw, size_t len)); void repo_local_path(struct config *cfg, struct config_repo *repo, @@ -8,15 +8,11 @@ #include "l2md.h" -static void repo_walker(struct config *cfg, struct config_repo *repo, uint32_t which, - const char *oid, const void *raw, size_t len) +static void repo_walker(struct config *cfg, struct config_repo *repo, + uint32_t url, const char *oid, + const void *raw, size_t len) { - char dst[PATH_MAX]; - - slprintf(dst, sizeof(dst), "%s/new/0.%06u.%s-%u-%s", - repo->maildir, own_pid, repo->name, which, oid); - - xwrite_file(dst, raw, len, true); + cfg->ops->new_mail(repo, url, oid, raw, len); } void sync_mail(struct config *cfg) @@ -26,7 +22,7 @@ void sync_mail(struct config *cfg) char path[PATH_MAX]; uint32_t i, j; - verbose("Resyncing maildirs.\n"); + verbose("Resyncing mails.\n"); repo_for_each(cfg, repo, i) { url_for_each(repo, url, j) { diff --git a/maildir.c b/maildir.c new file mode 100644 index 0000000..5228650 --- /dev/null +++ b/maildir.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (C) 2019 Daniel Borkmann <daniel@iogearbox.net> */ + +#include <unistd.h> + +#include <sys/time.h> +#include <sys/types.h> + +#include "l2md.h" + +static void maildir_new_mail(struct config_repo *repo, uint32_t which, + const char *oid, const void *raw, size_t len) +{ + char dst[PATH_MAX]; + + slprintf(dst, sizeof(dst), "%s/new/0.%06u.%s-%u-%s", + repo->out, own_pid, repo->name, which, oid); + + xwrite_file(dst, raw, len, true); +} + +static void maildir_bootstrap(struct config *cfg) +{ + struct config_repo *repo; + uint32_t i; + + repo_for_each(cfg, repo, i) { + xmkdir1_with_subdirs(repo->out); + + xmkdir2(repo->out, "cur"); + xmkdir2(repo->out, "tmp"); + xmkdir2(repo->out, "new"); + } +} + +struct mail_ops ops_maildir = { + .name = "maildir", + .bootstrap = maildir_bootstrap, + .new_mail = maildir_new_mail, +}; @@ -179,10 +179,10 @@ void repo_local_oid(struct config *cfg, struct config_repo *repo, __repo_local_get(cfg, repo, url, OIDS, out, len); } -void repo_walk_files(struct config *cfg, struct config_repo *repo, uint32_t which, +void repo_walk_files(struct config *cfg, struct config_repo *repo, uint32_t url, const char *path, const char *oid_last, char *oid_done, void (*repo_walker)(struct config *cfg, struct config_repo *repo, - uint32_t which, const char *oid, + uint32_t url, const char *oid, const void *raw, size_t len)) { char oid_curr[GIT_OID_HEXSZ + 1]; @@ -249,7 +249,7 @@ void repo_walk_files(struct config *cfg, struct config_repo *repo, uint32_t whic panic_git("Cannot revparse object"); blob = (const git_blob *)object; - repo_walker(cfg, repo, which, oid_curr, git_blob_rawcontent(blob), + repo_walker(cfg, repo, url, oid_curr, git_blob_rawcontent(blob), (size_t)git_blob_rawsize(blob)); git_object_free(object); @@ -266,7 +266,7 @@ void repo_walk_files(struct config *cfg, struct config_repo *repo, uint32_t whic if (have_first && count) { git_oid_tostr(oid_curr, sizeof(oid_curr), &loid); printf("Processed %u new mail(s) for %s. %s: %s -> %s in %ld.%02lds.\n", - count, repo->name, repo->urls[which].path, oid_last ? oid_curr : + count, repo->name, repo->urls[url].path, oid_last ? oid_curr : "[none]", oid_done, res.tv_sec, res.tv_usec); } |