]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm: Output is now written via "formatter" interface. The default can be changed...
authorTimo Sirainen <tss@iki.fi>
Fri, 11 Jun 2010 19:34:44 +0000 (20:34 +0100)
committerTimo Sirainen <tss@iki.fi>
Fri, 11 Jun 2010 19:34:44 +0000 (20:34 +0100)
Currently implemented 3 formatters: flow, tab and table.

--HG--
branch : HEAD

15 files changed:
src/doveadm/Makefile.am
src/doveadm/doveadm-mail-mailbox-status.c
src/doveadm/doveadm-mail-mailbox.c
src/doveadm/doveadm-mail-search.c
src/doveadm/doveadm-mail.c
src/doveadm/doveadm-mail.h
src/doveadm/doveadm-print-flow.c [new file with mode: 0644]
src/doveadm/doveadm-print-private.h [new file with mode: 0644]
src/doveadm/doveadm-print-tab.c [new file with mode: 0644]
src/doveadm/doveadm-print-table.c [new file with mode: 0644]
src/doveadm/doveadm-print.c [new file with mode: 0644]
src/doveadm/doveadm-print.h [new file with mode: 0644]
src/doveadm/doveadm-who.c
src/doveadm/doveadm.c
src/plugins/quota/doveadm-quota.c

index a8f0f29e7cb7f9bae35fc3b0f5ab327c80c49408..36dc756e357a5cd3dca881a964281c76c32e9cce 100644 (file)
@@ -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
index c1d8846b48ace1427526f5ebb9f94c8792bf5edd..d1039a719975655acbca1f95415c034f57536aff 100644 (file)
@@ -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;
 }
 
index 3d21921376db9fa991fec578980cee74a31cf274..aea9c5a68a671686e4907ad047b1234ca3651c69 100644 (file)
@@ -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;
 }
 
index 82e0fb2ba5f7c730eee0e9fe5c7c0e2a837d98fd..b65ff9f039dc64d214b55079fa7329560031892b 100644 (file)
@@ -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;
 }
 
index 7120ebcc8966378943a4624508dab146390c69d4..1ac7916ab5a4ca6348eac142936e8f3faf758897 100644 (file)
@@ -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 <stdio.h>
@@ -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[])
index e1e105ffa3bd87277ccb76f8f2658e553035ec40..2093fad0b7eee54678474144ac822e69c83e2bbb 100644 (file)
@@ -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 (file)
index 0000000..d372a4f
--- /dev/null
@@ -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 <stdio.h>
+
+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 (file)
index 0000000..5ff4d8b
--- /dev/null
@@ -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 (file)
index 0000000..ffe5e68
--- /dev/null
@@ -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 <stdio.h>
+
+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 (file)
index 0000000..9c591bc
--- /dev/null
@@ -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 <stdio.h>
+
+#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 (file)
index 0000000..956da28
--- /dev/null
@@ -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 (file)
index 0000000..30700eb
--- /dev/null
@@ -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
index 25bdeb41fe94360f74a7e531df52bdb82b0ca5a9..f2c4e4e5c7a10d3bee8926245cfba2488b9f7bb5 100644 (file)
@@ -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 <stdio.h>
@@ -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);
        }
 
index 786e2f73d22d5baea07e6737794e7ec350cbea77..1706d367acc3af57b5fd44c6dff13a6a24d4b389 100644 (file)
@@ -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 <formatter>] ");
        if (*prefix != '\0')
                fprintf(out, "%s ", prefix);
        fprintf(out, "<command> [<args>]\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);
index bb4f1f4301a45377d13fe232ee83967f1d90307e..c8e199a6d7385fe62a09eea5dc0a911af469bda0 100644 (file)
@@ -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;
 }