From: Timo Sirainen Date: Fri, 11 Jun 2010 19:34:44 +0000 (+0100) Subject: doveadm: Output is now written via "formatter" interface. The default can be changed... X-Git-Tag: 2.0.beta6~9 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7ed711d973b319320da100d3e905ef7b99ed69d6;p=thirdparty%2Fdovecot%2Fcore.git doveadm: Output is now written via "formatter" interface. The default can be changed with -f parameter. Currently implemented 3 formatters: flow, tab and table. --HG-- branch : HEAD --- diff --git a/src/doveadm/Makefile.am b/src/doveadm/Makefile.am index a8f0f29e7c..36dc756e35 100644 --- a/src/doveadm/Makefile.am +++ b/src/doveadm/Makefile.am @@ -64,6 +64,10 @@ doveadm_SOURCES = \ doveadm-mail-list-iter.c \ doveadm-mail-search.c \ doveadm-penalty.c \ + doveadm-print.c \ + doveadm-print-flow.c \ + doveadm-print-tab.c \ + doveadm-print-table.c \ doveadm-pw.c \ doveadm-settings.c \ doveadm-who.c @@ -74,5 +78,7 @@ noinst_HEADERS = \ doveadm-mail.h \ doveadm-mail-iter.h \ doveadm-mail-list-iter.h \ + doveadm-print.h \ + doveadm-print-private.h \ doveadm-settings.h \ doveadm-who.h diff --git a/src/doveadm/doveadm-mail-mailbox-status.c b/src/doveadm/doveadm-mail-mailbox-status.c index c1d8846b48..d1039a7199 100644 --- a/src/doveadm/doveadm-mail-mailbox-status.c +++ b/src/doveadm/doveadm-mail-mailbox-status.c @@ -4,6 +4,7 @@ #include "str.h" #include "mail-namespace.h" #include "mail-storage.h" +#include "doveadm-print.h" #include "doveadm-mail.h" #include "doveadm-mail-list-iter.h" @@ -58,36 +59,25 @@ static void status_output(struct status_cmd_context *ctx, struct mailbox *box, const struct mailbox_status *status, uint8_t mailbox_guid[MAIL_GUID_128_SIZE]) { - string_t *str = t_str_new(128); - if (box != NULL) - str_printfa(str, "%s: ", mailbox_get_vname(box)); + doveadm_print(mailbox_get_vname(box)); if ((ctx->items & STATUS_MESSAGES) != 0) - str_printfa(str, "messages=%u ", status->messages); + doveadm_print_num(status->messages); if ((ctx->items & STATUS_RECENT) != 0) - str_printfa(str, "recent=%u ", status->recent); + doveadm_print_num(status->recent); if ((ctx->items & STATUS_UIDNEXT) != 0) - str_printfa(str, "uidnext=%u ", status->uidnext); + doveadm_print_num(status->uidnext); if ((ctx->items & STATUS_UIDVALIDITY) != 0) - str_printfa(str, "uidvalidity=%u ", status->uidvalidity); + doveadm_print_num(status->uidvalidity); if ((ctx->items & STATUS_UNSEEN) != 0) - str_printfa(str, "unseen=%u ", status->unseen); - if ((ctx->items & STATUS_HIGHESTMODSEQ) != 0) { - str_printfa(str, "highestmodseq=%llu ", - (unsigned long long)status->highest_modseq); - } - if ((ctx->items & STATUS_VIRTUAL_SIZE) != 0) { - str_printfa(str, "vsize=%llu ", - (unsigned long long)status->virtual_size); - } - if (ctx->guid) { - str_printfa(str, "guid=%s ", - mail_guid_128_to_string(mailbox_guid)); - } - - str_truncate(str, str_len(str)-1); - dm_printf(&ctx->ctx, "%s\n", str_c(str)); + doveadm_print_num(status->unseen); + if ((ctx->items & STATUS_HIGHESTMODSEQ) != 0) + doveadm_print_num(status->highest_modseq); + if ((ctx->items & STATUS_VIRTUAL_SIZE) != 0) + doveadm_print_num(status->virtual_size); + if (ctx->guid) + doveadm_print(mail_guid_128_to_string(mailbox_guid)); } static void @@ -164,6 +154,27 @@ static void cmd_mailbox_status_init(struct doveadm_mail_cmd_context *_ctx, status_parse_fields(ctx, t_strsplit_spaces(fields, " ")); ctx->search_args = doveadm_mail_mailbox_search_args_build(args); + + if (!ctx->total_sum) { + doveadm_print_header("mailbox", "mailbox", + DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); + } + if ((ctx->items & STATUS_MESSAGES) != 0) + doveadm_print_header_simple("messages"); + if ((ctx->items & STATUS_RECENT) != 0) + doveadm_print_header_simple("recent"); + if ((ctx->items & STATUS_UIDNEXT) != 0) + doveadm_print_header_simple("uidnext"); + if ((ctx->items & STATUS_UIDVALIDITY) != 0) + doveadm_print_header_simple("uidvalidity"); + if ((ctx->items & STATUS_UNSEEN) != 0) + doveadm_print_header_simple("unseen"); + if ((ctx->items & STATUS_HIGHESTMODSEQ) != 0) + doveadm_print_header_simple("highestmodseq"); + if ((ctx->items & STATUS_VIRTUAL_SIZE) != 0) + doveadm_print_header_simple("vsize"); + if (ctx->guid) + doveadm_print_header_simple("guid"); } static bool @@ -190,6 +201,7 @@ static struct doveadm_mail_cmd_context *cmd_mailbox_status_alloc(void) ctx->ctx.v.parse_arg = cmd_mailbox_status_parse_arg; ctx->ctx.v.init = cmd_mailbox_status_init; ctx->ctx.v.run = cmd_mailbox_status_run; + doveadm_print_init(DOVEADM_PRINT_TYPE_FLOW); return &ctx->ctx; } diff --git a/src/doveadm/doveadm-mail-mailbox.c b/src/doveadm/doveadm-mail-mailbox.c index 3d21921376..aea9c5a68a 100644 --- a/src/doveadm/doveadm-mail-mailbox.c +++ b/src/doveadm/doveadm-mail-mailbox.c @@ -7,6 +7,7 @@ #include "mail-namespace.h" #include "mail-storage.h" #include "mail-search-build.h" +#include "doveadm-print.h" #include "doveadm-mail-list-iter.h" #include "doveadm-mail.h" @@ -123,9 +124,9 @@ cmd_mailbox_list_run(struct doveadm_mail_cmd_context *_ctx, while ((info = doveadm_mail_list_iter_next(iter)) != NULL) { str_truncate(str, 0); if (ctx->mutf7 || imap_utf7_to_utf8(info->name, str) < 0) - dm_printf(_ctx, "%s\n", info->name); + doveadm_print(info->name); else - dm_printf(_ctx, "%s\n", str_c(str)); + doveadm_print(str_c(str)); } doveadm_mail_list_iter_deinit(&iter); } @@ -158,6 +159,8 @@ static void cmd_mailbox_list_init(struct doveadm_mail_cmd_context *_ctx, { struct list_cmd_context *ctx = (struct list_cmd_context *)_ctx; + doveadm_print_header("mailbox", "mailbox", + DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); ctx->search_args = doveadm_mail_mailbox_search_args_build(args); } @@ -170,6 +173,7 @@ static struct doveadm_mail_cmd_context *cmd_mailbox_list_alloc(void) ctx->ctx.ctx.v.run = cmd_mailbox_list_run; ctx->ctx.ctx.v.parse_arg = cmd_mailbox_list_parse_arg; ctx->ctx.ctx.getopt_args = "78s"; + doveadm_print_init(DOVEADM_PRINT_TYPE_FLOW); return &ctx->ctx.ctx; } diff --git a/src/doveadm/doveadm-mail-search.c b/src/doveadm/doveadm-mail-search.c index 82e0fb2ba5..b65ff9f039 100644 --- a/src/doveadm/doveadm-mail-search.c +++ b/src/doveadm/doveadm-mail-search.c @@ -2,6 +2,7 @@ #include "lib.h" #include "mail-storage.h" +#include "doveadm-print.h" #include "doveadm-mail-list-iter.h" #include "doveadm-mail-iter.h" #include "doveadm-mail.h" @@ -27,8 +28,12 @@ cmd_search_box(struct doveadm_mail_cmd_context *ctx, ret = -1; else { guid_str = mail_guid_128_to_string(guid); - while (doveadm_mail_iter_next(iter, mail)) - dm_printf(ctx, "%s %u\n", guid_str, mail->uid); + while (doveadm_mail_iter_next(iter, mail)) { + doveadm_print(guid_str); + T_BEGIN { + doveadm_print(dec2str(mail->uid)); + } T_END; + } } mail_free(&mail); if (doveadm_mail_iter_deinit(&iter) < 0) @@ -60,6 +65,11 @@ static void cmd_search_init(struct doveadm_mail_cmd_context *ctx, if (args[0] == NULL) doveadm_mail_help_name("search"); + doveadm_print_header("mailbox-guid", "mailbox-guid", + DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); + doveadm_print_header("uid", "uid", + DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); + ctx->search_args = doveadm_mail_build_search_args(args); } @@ -70,6 +80,7 @@ static struct doveadm_mail_cmd_context *cmd_search_alloc(void) ctx = doveadm_mail_cmd_alloc(struct doveadm_mail_cmd_context); ctx->v.init = cmd_search_init; ctx->v.run = cmd_search_run; + doveadm_print_init(DOVEADM_PRINT_TYPE_FLOW); return ctx; } diff --git a/src/doveadm/doveadm-mail.c b/src/doveadm/doveadm-mail.c index 7120ebcc89..1ac7916ab5 100644 --- a/src/doveadm/doveadm-mail.c +++ b/src/doveadm/doveadm-mail.c @@ -18,6 +18,7 @@ #include "mail-search-parser.h" #include "doveadm.h" #include "doveadm-settings.h" +#include "doveadm-print.h" #include "doveadm-mail.h" #include @@ -41,7 +42,6 @@ doveadm_mail_cmd_alloc_size(size_t size) pool = pool_alloconly_create("doveadm mail cmd", 1024); ctx = p_malloc(pool, size); ctx->pool = pool; - ctx->dm_printf_last_lf = TRUE; return ctx; } @@ -276,7 +276,7 @@ doveadm_mail_all_users(struct doveadm_mail_cmd_context *ctx, n = user_count / 10000; for (interval = 10; n > 0 && interval < 1000; interval *= 10) n /= 10; - + user_idx = 0; while ((ret = ctx->v.get_next_user(ctx, &user)) > 0) { if (wildcard_user != NULL) { @@ -284,6 +284,7 @@ doveadm_mail_all_users(struct doveadm_mail_cmd_context *ctx, continue; } input.username = user; + doveadm_print_sticky("username", user); T_BEGIN { ret = doveadm_mail_next_user(ctx, &input, &error); if (ret < 0) @@ -360,6 +361,9 @@ doveadm_mail_cmd(const struct doveadm_mail_cmd *cmd, int argc, char *argv[]) switch (c) { case 'A': ctx->iterate_all_users = TRUE; + doveadm_print_header("username", "Username", + DOVEADM_PRINT_HEADER_FLAG_STICKY | + DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); break; case 'u': service_flags |= @@ -396,29 +400,6 @@ doveadm_mail_cmd(const struct doveadm_mail_cmd *cmd, int argc, char *argv[]) exit(FATAL_DEFAULT); } -void dm_printf(struct doveadm_mail_cmd_context *ctx, const char *format, ...) -{ - va_list args; - - va_start(args, format); - if (!ctx->iterate_all_users) - vprintf(format, args); - else T_BEGIN { - const char *str = t_strdup_vprintf(format, args); - bool prev_lf = ctx->dm_printf_last_lf; - - for (; *str != '\0'; str++) { - if (prev_lf) - printf("%s: ", ctx->cur_mail_user->username); - putchar(*str); - prev_lf = *str == '\n'; - } - ctx->dm_printf_last_lf = prev_lf; - - } T_END; - va_end(args); -} - static bool doveadm_mail_try_run_multi_word(const struct doveadm_mail_cmd *cmd, const char *cmdname, int argc, char *argv[]) diff --git a/src/doveadm/doveadm-mail.h b/src/doveadm/doveadm-mail.h index e1e105ffa3..2093fad0b7 100644 --- a/src/doveadm/doveadm-mail.h +++ b/src/doveadm/doveadm-mail.h @@ -45,7 +45,6 @@ struct doveadm_mail_cmd_context { ARRAY_DEFINE(module_contexts, union doveadm_mail_cmd_module_context *); unsigned int iterate_all_users:1; - unsigned int dm_printf_last_lf:1; unsigned int failed:1; }; @@ -85,11 +84,6 @@ doveadm_mail_cmd_alloc_size(size_t size); #define doveadm_mail_cmd_alloc(type) \ (type *)doveadm_mail_cmd_alloc_size(sizeof(type)) -/* same as printf(), but when running with -A parameter, - prefix each line with username. */ -void dm_printf(struct doveadm_mail_cmd_context *ctx, const char *format, ...) - ATTR_FORMAT(2, 3); - struct doveadm_mail_cmd cmd_expunge; struct doveadm_mail_cmd cmd_search; struct doveadm_mail_cmd cmd_fetch; diff --git a/src/doveadm/doveadm-print-flow.c b/src/doveadm/doveadm-print-flow.c new file mode 100644 index 0000000000..d372a4fa58 --- /dev/null +++ b/src/doveadm/doveadm-print-flow.c @@ -0,0 +1,75 @@ +/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "doveadm-print-private.h" + +#include + +struct doveadm_print_flow_header { + const char *title; + enum doveadm_print_header_flags flags; +}; + +struct doveadm_print_flow_context { + pool_t pool; + ARRAY_DEFINE(headers, struct doveadm_print_flow_header); + unsigned int header_idx; +}; + +static struct doveadm_print_flow_context *ctx; + +static void +doveadm_print_flow_header(const struct doveadm_print_header *hdr) +{ + struct doveadm_print_flow_header *fhdr; + + fhdr = array_append_space(&ctx->headers); + fhdr->title = p_strdup(ctx->pool, hdr->title); + fhdr->flags = hdr->flags; +} + +static void doveadm_print_flow_print(const char *value) +{ + const struct doveadm_print_flow_header *hdr = + array_idx(&ctx->headers, ctx->header_idx); + + if ((hdr->flags & DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE) == 0) + printf("%s=", hdr->title); + printf("%s", value); + + if (++ctx->header_idx < array_count(&ctx->headers)) + printf(" "); + else { + ctx->header_idx = 0; + printf("\n"); + } +} + +static void doveadm_print_flow_init(void) +{ + pool_t pool; + + pool = pool_alloconly_create("doveadm print flow", 1024); + ctx = p_new(pool, struct doveadm_print_flow_context, 1); + ctx->pool = pool; + p_array_init(&ctx->headers, pool, 16); +} + +static void doveadm_print_flow_deinit(void) +{ + if (ctx->header_idx != 0) + printf("\n"); + + pool_unref(&ctx->pool); + ctx = NULL; +} + +struct doveadm_print_vfuncs doveadm_print_flow_vfuncs = { + "flow", + + doveadm_print_flow_init, + doveadm_print_flow_deinit, + doveadm_print_flow_header, + doveadm_print_flow_print +}; diff --git a/src/doveadm/doveadm-print-private.h b/src/doveadm/doveadm-print-private.h new file mode 100644 index 0000000000..5ff4d8b1b9 --- /dev/null +++ b/src/doveadm/doveadm-print-private.h @@ -0,0 +1,26 @@ +#ifndef DOVEADM_PRINT_PRIVATE_H +#define DOVEADM_PRINT_PRIVATE_H + +#include "doveadm-print.h" + +struct doveadm_print_header { + const char *key; + const char *title; + enum doveadm_print_header_flags flags; +}; + +struct doveadm_print_vfuncs { + const char *name; + + void (*init)(void); + void (*deinit)(void); + + void (*header)(const struct doveadm_print_header *hdr); + void (*print)(const char *value); +}; + +extern struct doveadm_print_vfuncs doveadm_print_flow_vfuncs; +extern struct doveadm_print_vfuncs doveadm_print_tab_vfuncs; +extern struct doveadm_print_vfuncs doveadm_print_table_vfuncs; + +#endif diff --git a/src/doveadm/doveadm-print-tab.c b/src/doveadm/doveadm-print-tab.c new file mode 100644 index 0000000000..ffe5e68c94 --- /dev/null +++ b/src/doveadm/doveadm-print-tab.c @@ -0,0 +1,56 @@ +/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "doveadm-print-private.h" + +#include + +struct doveadm_print_tab_context { + unsigned int header_idx, header_count; + + unsigned int header_written:1; +}; + +static struct doveadm_print_tab_context ctx; + +static void +doveadm_print_tab_header(const struct doveadm_print_header *hdr) +{ + if (ctx.header_count++ > 0) + printf("\t"); + printf("%s", hdr->title); +} + +static void doveadm_print_tab_print(const char *value) +{ + if (!ctx.header_written) { + printf("\n"); + ctx.header_written = TRUE; + } + if (ctx.header_idx > 0) + printf("\t"); + printf("%s", value); + + if (++ctx.header_idx < ctx.header_count) + printf(" "); + else { + ctx.header_idx = 0; + printf("\n"); + } +} + +static void doveadm_print_tab_deinit(void) +{ + if (!ctx.header_written) + printf("\n"); +} + +struct doveadm_print_vfuncs doveadm_print_tab_vfuncs = { + "tab", + + NULL, + doveadm_print_tab_deinit, + doveadm_print_tab_header, + doveadm_print_tab_print +}; diff --git a/src/doveadm/doveadm-print-table.c b/src/doveadm/doveadm-print-table.c new file mode 100644 index 0000000000..9c591bcb92 --- /dev/null +++ b/src/doveadm/doveadm-print-table.c @@ -0,0 +1,193 @@ +/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "doveadm-print-private.h" + +#include + +#define DEFAULT_COLUMNS 80 +#define MAX_BUFFER_LINES 100 + +struct doveadm_print_table_header { + const char *key; + const char *title; + enum doveadm_print_header_flags flags; + unsigned int min_length, max_length, length; +}; + +struct doveadm_print_table_context { + pool_t pool; + ARRAY_DEFINE(headers, struct doveadm_print_table_header); + ARRAY_TYPE(const_string) buffered_values; + unsigned int hdr_idx; + unsigned int columns; + + unsigned int lengths_set:1; +}; + +static struct doveadm_print_table_context *ctx; + +static void +doveadm_print_table_header(const struct doveadm_print_header *hdr) +{ + struct doveadm_print_table_header *thdr; + + thdr = array_append_space(&ctx->headers); + thdr->key = p_strdup(ctx->pool, hdr->key); + thdr->title = p_strdup(ctx->pool, hdr->title); + thdr->length = thdr->max_length = thdr->min_length = strlen(hdr->title); + thdr->flags = hdr->flags; +} + +static void doveadm_calc_header_length(void) +{ + struct doveadm_print_table_header *headers; + const char *value, *const *values; + unsigned int i, line, len, hdr_count, value_count, line_count; + unsigned int max_length, orig_length, diff; + + headers = array_get_modifiable(&ctx->headers, &hdr_count); + values = array_get(&ctx->buffered_values, &value_count); + i_assert((value_count % hdr_count) == 0); + line_count = value_count / hdr_count; + + /* find min and max lengths of fields */ + for (line = 0; line < line_count; line++) { + for (i = 0; i < hdr_count; i++) { + value = values[line*hdr_count + i]; + len = value == NULL ? 0 : strlen(value); + if (headers[i].min_length > len) + headers[i].min_length = len; + if (headers[i].max_length < len) { + headers[i].max_length = len; + headers[i].length = len; + } + } + } + + /* +1 for space between fields */ + max_length = 0; + for (i = 0; i < hdr_count; i++) + max_length += headers[i].max_length + 1; + max_length--; + + while (max_length > ctx->columns) { + /* shrink something so we'll fit */ + orig_length = max_length; + for (i = hdr_count - 1;; i--) { + diff = headers[i].length - headers[i].min_length; + if (max_length - diff <= ctx->columns) { + /* we can finish with this */ + diff = max_length - ctx->columns; + headers[i].length -= diff; + max_length -= diff; + break; + } + if (diff > 0) { + /* take a bit off from it */ + headers[i].length -= diff == 1 ? 1 : diff/2; + } + + if (i == 0) + break; + } + if (max_length == orig_length) { + /* can't shrink it any more */ + break; + } + } + if (max_length < ctx->columns) + headers[0].length += (ctx->columns - max_length) / 2; +} + +static void doveadm_print_next(const char *value) +{ + const struct doveadm_print_table_header *hdr; + + hdr = array_idx(&ctx->headers, ctx->hdr_idx); + + if ((hdr->flags & DOVEADM_PRINT_HEADER_FLAG_RIGHT_JUSTIFY) == 0) + printf("%-*s", (int)hdr->length, value); + else + printf("%*s", (int)hdr->length, value); + + if (++ctx->hdr_idx == array_count(&ctx->headers)) { + ctx->hdr_idx = 0; + printf("\n"); + } else { + printf(" "); + } +} + +static void doveadm_buffer_flush(void) +{ + const struct doveadm_print_table_header *headers; + const char *const *valuep; + unsigned int i, count; + + doveadm_calc_header_length(); + + headers = array_get(&ctx->headers, &count); + for (i = 0; i < count; i++) { + if (i > 0) fprintf(stderr, " "); + + if ((headers[i].flags & + DOVEADM_PRINT_HEADER_FLAG_RIGHT_JUSTIFY) == 0) { + fprintf(stderr, "%-*s", (int)headers[i].length, + headers[i].title); + } else { + fprintf(stderr, "%*s", (int)headers[i].length, + headers[i].title); + } + } + fprintf(stderr, "\n"); + + array_foreach(&ctx->buffered_values, valuep) + doveadm_print_next(*valuep); + array_clear(&ctx->buffered_values); +} + +static void doveadm_print_table_print(const char *value) +{ + if (!ctx->lengths_set) { + if (array_count(&ctx->buffered_values) < MAX_BUFFER_LINES) { + value = p_strdup(ctx->pool, value); + array_append(&ctx->buffered_values, &value, 1); + return; + } + doveadm_buffer_flush(); + } + doveadm_print_next(value); +} + +static void doveadm_print_table_init(void) +{ + pool_t pool; + + pool = pool_alloconly_create("doveadm print table", 1024); + ctx = p_new(pool, struct doveadm_print_table_context, 1); + ctx->pool = pool; + p_array_init(&ctx->headers, pool, 16); + i_array_init(&ctx->buffered_values, 64); + ctx->columns = DEFAULT_COLUMNS; +} + +static void doveadm_print_table_deinit(void) +{ + if (!ctx->lengths_set && array_count(&ctx->headers) > 0) + doveadm_buffer_flush(); + + array_free(&ctx->buffered_values); + pool_unref(&ctx->pool); + ctx = NULL; +} + +struct doveadm_print_vfuncs doveadm_print_table_vfuncs = { + "table", + + doveadm_print_table_init, + doveadm_print_table_deinit, + doveadm_print_table_header, + doveadm_print_table_print +}; diff --git a/src/doveadm/doveadm-print.c b/src/doveadm/doveadm-print.c new file mode 100644 index 0000000000..956da28a23 --- /dev/null +++ b/src/doveadm/doveadm-print.c @@ -0,0 +1,134 @@ +/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "doveadm-print-private.h" + +struct doveadm_print_header_context { + const char *key; + char *sticky_value; + bool sticky; +}; + +struct doveadm_print_context { + pool_t pool; + ARRAY_DEFINE(headers, struct doveadm_print_header_context); + const struct doveadm_print_vfuncs *v; + + unsigned int header_idx; +}; + +static struct doveadm_print_context *ctx; +static const struct doveadm_print_vfuncs *doveadm_print_vfuncs_all[] = { + &doveadm_print_flow_vfuncs, + &doveadm_print_tab_vfuncs, + &doveadm_print_table_vfuncs +}; + +void doveadm_print_header(const char *key, const char *title, + enum doveadm_print_header_flags flags) +{ + struct doveadm_print_header hdr; + struct doveadm_print_header_context *hdr_ctx; + + if (title == NULL) + flags |= DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE; + + memset(&hdr, 0, sizeof(hdr)); + hdr.key = key; + hdr.title = title; + hdr.flags = flags; + ctx->v->header(&hdr); + + hdr_ctx = array_append_space(&ctx->headers); + hdr_ctx->key = p_strdup(ctx->pool, key); + hdr_ctx->sticky = (flags & DOVEADM_PRINT_HEADER_FLAG_STICKY) != 0; +} + +void doveadm_print_header_simple(const char *key_title) +{ + doveadm_print_header(key_title, key_title, 0); +} + +void doveadm_print(const char *value) +{ + const struct doveadm_print_header_context *headers; + unsigned int count; + + headers = array_get(&ctx->headers, &count); + for (;;) { + if (ctx->header_idx == count) + ctx->header_idx = 0; + else if (headers[ctx->header_idx].sticky) { + ctx->v->print(headers[ctx->header_idx].sticky_value); + ctx->header_idx++; + } else { + break; + } + } + + ctx->v->print(value); + ctx->header_idx++; +} + +void doveadm_print_num(uintmax_t value) +{ + T_BEGIN { + doveadm_print(dec2str(value)); + } T_END; +} + +void doveadm_print_sticky(const char *key, const char *value) +{ + struct doveadm_print_header_context *hdr; + + array_foreach_modifiable(&ctx->headers, hdr) { + if (strcmp(hdr->key, key) == 0) { + i_free(hdr->sticky_value); + hdr->sticky_value = i_strdup(value); + return; + } + } + i_unreached(); +} + +void doveadm_print_init(const char *name) +{ + pool_t pool; + unsigned int i; + + if (ctx != NULL) { + /* already forced the type */ + return; + } + + pool = pool_alloconly_create("doveadm print", 1024); + ctx = p_new(pool, struct doveadm_print_context, 1); + ctx->pool = pool; + p_array_init(&ctx->headers, pool, 16); + + for (i = 0; i < N_ELEMENTS(doveadm_print_vfuncs_all); i++) { + if (strcmp(doveadm_print_vfuncs_all[i]->name, name) == 0) { + ctx->v = doveadm_print_vfuncs_all[i]; + break; + } + } + if (ctx->v == NULL) + i_fatal("Unknown print formatter: %s", name); + if (ctx->v->init != NULL) + ctx->v->init(); +} + +void doveadm_print_deinit(void) +{ + struct doveadm_print_header_context *hdr; + + if (ctx == NULL) + return; + + ctx->v->deinit(); + array_foreach_modifiable(&ctx->headers, hdr) + i_free(hdr->sticky_value); + pool_unref(&ctx->pool); + ctx = NULL; +} diff --git a/src/doveadm/doveadm-print.h b/src/doveadm/doveadm-print.h new file mode 100644 index 0000000000..30700eb3ca --- /dev/null +++ b/src/doveadm/doveadm-print.h @@ -0,0 +1,23 @@ +#ifndef DOVEADM_PRINT_H +#define DOVEADM_PRINT_H + +#define DOVEADM_PRINT_TYPE_FLOW "flow" +#define DOVEADM_PRINT_TYPE_TABLE "table" + +enum doveadm_print_header_flags { + DOVEADM_PRINT_HEADER_FLAG_RIGHT_JUSTIFY = 0x01, + DOVEADM_PRINT_HEADER_FLAG_STICKY = 0x02, + DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE = 0x04 +}; + +void doveadm_print_header(const char *key, const char *title, + enum doveadm_print_header_flags flags); +void doveadm_print_header_simple(const char *key_title); +void doveadm_print(const char *value); +void doveadm_print_num(uintmax_t value); +void doveadm_print_sticky(const char *key, const char *value); + +void doveadm_print_init(const char *name); +void doveadm_print_deinit(void); + +#endif diff --git a/src/doveadm/doveadm-who.c b/src/doveadm/doveadm-who.c index 25bdeb41fe..f2c4e4e5c7 100644 --- a/src/doveadm/doveadm-who.c +++ b/src/doveadm/doveadm-who.c @@ -6,7 +6,9 @@ #include "istream.h" #include "wildcard-match.h" #include "hash.h" +#include "str.h" #include "doveadm.h" +#include "doveadm-print.h" #include "doveadm-who.h" #include @@ -183,45 +185,54 @@ static bool who_user_filter_match(const struct who_user *user, return TRUE; } +static void who_print_user(const struct who_user *user) +{ + const struct ip_addr *ip; + const pid_t *pid; + string_t *str = t_str_new(256); + + doveadm_print(user->username); + doveadm_print(dec2str(user->connection_count)); + doveadm_print(user->service); + + str_append_c(str, '('); + array_foreach(&user->pids, pid) + str_printfa(str, "%ld ", (long)*pid); + if (str_len(str) > 1) + str_truncate(str, str_len(str)-1); + str_append_c(str, ')'); + doveadm_print(str_c(str)); + + str_truncate(str, 0); + str_append_c(str, '('); + array_foreach(&user->ips, ip) + str_printfa(str, "%s ", net_ip2addr(ip)); + if (str_len(str) > 1) + str_truncate(str, str_len(str)-1); + str_append_c(str, ')'); + doveadm_print(str_c(str)); +} + static void who_print(struct who_context *ctx) { struct hash_iterate_context *iter; void *key, *value; - fprintf(stderr, "%-30s # proto\t(pids)\t(ips)\n", "username"); + doveadm_print_header("username", "username", 0); + doveadm_print_header("connections", "#", + DOVEADM_PRINT_HEADER_FLAG_RIGHT_JUSTIFY); + doveadm_print_header("service", "proto", 0); + doveadm_print_header("pids", "(pids)", 0); + doveadm_print_header("ips", "(ips)", 0); iter = hash_table_iterate_init(ctx->users); while (hash_table_iterate(iter, &key, &value)) { struct who_user *user = value; - const struct ip_addr *ip; - const pid_t *pid; - bool first = TRUE; - - if (!who_user_filter_match(user, &ctx->filter)) - continue; - - printf("%-30s %2u %-5s ", user->username, - user->connection_count, user->service); - - printf("("); - array_foreach(&user->pids, pid) T_BEGIN { - if (first) - first = FALSE; - else - printf(" "); - printf("%ld", (long)*pid); - } T_END; - printf(") ("); - first = TRUE; - array_foreach(&user->ips, ip) T_BEGIN { - if (first) - first = FALSE; - else - printf(" "); - printf("%s", net_ip2addr(ip)); + + if (who_user_filter_match(user, &ctx->filter)) T_BEGIN { + who_print_user(user); } T_END; - printf(")\n"); - }; + } hash_table_iterate_deinit(&iter); } @@ -249,8 +260,10 @@ static void who_print_line(struct who_context *ctx, return; for (i = 0; i < line->refcount; i++) T_BEGIN { - printf("%-30s %-5s\t%ld\t%-15s\n", line->username, - line->service, (long)line->pid, net_ip2addr(&line->ip)); + doveadm_print(line->username); + doveadm_print(line->service); + doveadm_print(dec2str(line->pid)); + doveadm_print(net_ip2addr(&line->ip)); } T_END; } @@ -282,11 +295,15 @@ static void cmd_who(int argc, char *argv[]) argv += optind - 1; who_parse_args(&ctx, argv); + doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE); if (!separate_connections) { who_lookup(&ctx, who_aggregate_line); who_print(&ctx); } else { - fprintf(stderr, "%-30s proto\tpid\t%-15s\n", "username", "ip"); + doveadm_print_header_simple("username"); + doveadm_print_header_simple("service"); + doveadm_print_header_simple("pid"); + doveadm_print_header_simple("ip"); who_lookup(&ctx, who_print_line); } diff --git a/src/doveadm/doveadm.c b/src/doveadm/doveadm.c index 786e2f73d2..1706d367ac 100644 --- a/src/doveadm/doveadm.c +++ b/src/doveadm/doveadm.c @@ -6,6 +6,7 @@ #include "module-dir.h" #include "master-service.h" #include "master-service-settings.h" +#include "doveadm-print.h" #include "doveadm-mail.h" #include "doveadm-settings.h" #include "doveadm.h" @@ -86,7 +87,7 @@ usage_to(FILE *out, const char *prefix) const struct doveadm_cmd *cmd; string_t *str = t_str_new(1024); - fprintf(out, "usage: doveadm [-Dv] "); + fprintf(out, "usage: doveadm [-Dv] [-F ] "); if (*prefix != '\0') fprintf(out, "%s ", prefix); fprintf(out, " []\n"); @@ -297,13 +298,16 @@ int main(int argc, char *argv[]) /* "+" is GNU extension to stop at the first non-option. others just accept -+ option. */ master_service = master_service_init("doveadm", service_flags, - &argc, &argv, "+Dv"); + &argc, &argv, "+DF:v"); while ((c = master_getopt(master_service)) > 0) { switch (c) { case 'D': doveadm_debug = TRUE; doveadm_verbose = TRUE; break; + case 'F': + doveadm_print_init(optarg); + break; case 'v': doveadm_verbose = TRUE; break; @@ -365,6 +369,7 @@ int main(int argc, char *argv[]) if (!quick_init) { doveadm_mail_deinit(); module_dir_unload(&modules); + doveadm_print_deinit(); } array_free(&doveadm_cmds); master_service_deinit(&master_service); diff --git a/src/plugins/quota/doveadm-quota.c b/src/plugins/quota/doveadm-quota.c index bb4f1f4301..c8e199a6d7 100644 --- a/src/plugins/quota/doveadm-quota.c +++ b/src/plugins/quota/doveadm-quota.c @@ -4,6 +4,7 @@ #include "module-dir.h" #include "quota-plugin.h" #include "quota-private.h" +#include "doveadm-print.h" #include "doveadm-mail.h" const char *doveadm_quota_plugin_version = DOVECOT_VERSION; @@ -11,47 +12,60 @@ const char *doveadm_quota_plugin_version = DOVECOT_VERSION; void doveadm_quota_plugin_init(struct module *module); void doveadm_quota_plugin_deinit(void); -static void -cmd_quota_get_root(struct doveadm_mail_cmd_context *ctx, - struct quota_root *root) +static void cmd_quota_get_root(struct quota_root *root) { const char *const *res; uint64_t value, limit; int ret; - dm_printf(ctx, "%s: ", root->set->name); res = quota_root_get_resources(root); for (; *res != NULL; res++) { ret = quota_get_resource(root, "", *res, &value, &limit); - dm_printf(ctx, "%s ", *res); + doveadm_print(root->set->name); + doveadm_print(*res); if (ret > 0) { - dm_printf(ctx, "%llu/%llu", - (unsigned long long)value, - (unsigned long long)limit); - if (limit >= 100) { - dm_printf(ctx, " (%u%%)", - (unsigned int)(value / (limit/100))); - } + doveadm_print_num(value); + doveadm_print_num(limit); + if (limit >= 100) + doveadm_print_num(value / (limit/100)); + else + doveadm_print("0"); } else if (ret == 0) { - dm_printf(ctx, "%llu/unlimited", - (unsigned long long)value); - } else - dm_printf(ctx, "error"); - if (res[1] != NULL) - dm_printf(ctx, ", "); + doveadm_print_num(value); + doveadm_print("-"); + doveadm_print("0"); + } else { + doveadm_print("error"); + doveadm_print("error"); + doveadm_print("error"); + } } - dm_printf(ctx, "\n"); } static void -cmd_quota_get_run(struct doveadm_mail_cmd_context *ctx, +cmd_quota_get_run(struct doveadm_mail_cmd_context *ctx ATTR_UNUSED, struct mail_user *user) { struct quota_user *quser = QUOTA_USER_CONTEXT(user); struct quota_root *const *root; array_foreach(&quser->quota->roots, root) - cmd_quota_get_root(ctx, *root); + cmd_quota_get_root(*root); +} + +static void cmd_quota_get_init(struct doveadm_mail_cmd_context *ctx, + const char *const args[] ATTR_UNUSED) +{ + doveadm_print_header("root", "Quota name", 0); + doveadm_print_header("type", "Type", 0); + doveadm_print_header("value", "Value", + DOVEADM_PRINT_HEADER_FLAG_RIGHT_JUSTIFY); + doveadm_print_header("limit", "Limit", + DOVEADM_PRINT_HEADER_FLAG_RIGHT_JUSTIFY); + doveadm_print_header("percent", "%", + DOVEADM_PRINT_HEADER_FLAG_RIGHT_JUSTIFY); + + ctx->search_args = doveadm_mail_build_search_args(args); } static struct doveadm_mail_cmd_context * @@ -61,6 +75,8 @@ cmd_quota_get_alloc(void) ctx = doveadm_mail_cmd_alloc(struct doveadm_mail_cmd_context); ctx->v.run = cmd_quota_get_run; + ctx->v.init = cmd_quota_get_init; + doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE); return ctx; }