1 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "array.h"
5 #include "istream.h"
6 #include "ostream.h"
7 #include "doveadm-print-private.h"
8
9 struct doveadm_print_header_context {
10 const char *key;
11 char *sticky_value;
12 bool sticky;
13 };
14
15 struct doveadm_print_context {
16 pool_t pool;
17 ARRAY(struct doveadm_print_header_context) headers;
18 const struct doveadm_print_vfuncs *v;
19
20 unsigned int header_idx;
21 bool print_stream_open;
22 };
23
24 bool doveadm_print_hide_titles = FALSE;
25 struct ostream *doveadm_print_ostream = NULL;
26
27 static struct doveadm_print_context *ctx;
28
doveadm_print_is_initialized(void)29 bool doveadm_print_is_initialized(void)
30 {
31 return ctx != NULL;
32 }
33
doveadm_print_header(const char * key,const char * title,enum doveadm_print_header_flags flags)34 void doveadm_print_header(const char *key, const char *title,
35 enum doveadm_print_header_flags flags)
36 {
37 struct doveadm_print_header hdr;
38 struct doveadm_print_header_context *hdr_ctx;
39
40 i_assert(title != NULL);
41
42 i_zero(&hdr);
43 hdr.key = key;
44 hdr.title = title;
45 hdr.flags = flags;
46 ctx->v->header(&hdr);
47
48 hdr_ctx = array_append_space(&ctx->headers);
49 hdr_ctx->key = p_strdup(ctx->pool, key);
50 hdr_ctx->sticky = (flags & DOVEADM_PRINT_HEADER_FLAG_STICKY) != 0;
51 }
52
doveadm_print_header_simple(const char * key_title)53 void doveadm_print_header_simple(const char *key_title)
54 {
55 doveadm_print_header(key_title, key_title, 0);
56 }
57
doveadm_print_get_headers_count(void)58 unsigned int doveadm_print_get_headers_count(void)
59 {
60 return array_count(&ctx->headers);
61 }
62
doveadm_print_sticky_headers(void)63 static void doveadm_print_sticky_headers(void)
64 {
65 const struct doveadm_print_header_context *headers;
66 unsigned int count;
67
68 headers = array_get(&ctx->headers, &count);
69 i_assert(count > 0);
70 for (;;) {
71 if (ctx->header_idx == count)
72 ctx->header_idx = 0;
73 else if (headers[ctx->header_idx].sticky) {
74 ctx->v->print(headers[ctx->header_idx].sticky_value);
75 ctx->header_idx++;
76 } else {
77 break;
78 }
79 }
80 }
81
doveadm_print(const char * value)82 void doveadm_print(const char *value)
83 {
84 i_assert(!ctx->print_stream_open);
85
86 doveadm_print_sticky_headers();
87 ctx->v->print(value);
88 ctx->header_idx++;
89 }
90
doveadm_print_num(uintmax_t value)91 void doveadm_print_num(uintmax_t value)
92 {
93 T_BEGIN {
94 doveadm_print(dec2str(value));
95 } T_END;
96 }
97
doveadm_print_stream(const void * value,size_t size)98 void doveadm_print_stream(const void *value, size_t size)
99 {
100 if (!ctx->print_stream_open) {
101 doveadm_print_sticky_headers();
102 ctx->print_stream_open = TRUE;
103 }
104 ctx->v->print_stream(value, size);
105 if (size == 0) {
106 ctx->header_idx++;
107 ctx->print_stream_open = FALSE;
108 }
109 }
110
doveadm_print_istream(struct istream * input)111 int doveadm_print_istream(struct istream *input)
112 {
113 const unsigned char *data;
114 size_t size;
115 ssize_t ret;
116
117 while ((ret = i_stream_read_more(input, &data, &size)) > 0) {
118 doveadm_print_stream(data, size);
119 i_stream_skip(input, size);
120 }
121 i_assert(ret == -1);
122 doveadm_print_stream("", 0);
123 if (input->stream_errno != 0) {
124 /* caller will log the error */
125 return -1;
126 }
127 return 0;
128 }
129
doveadm_print_sticky(const char * key,const char * value)130 void doveadm_print_sticky(const char *key, const char *value)
131 {
132 struct doveadm_print_header_context *hdr;
133
134 if (ctx == NULL) {
135 /* command doesn't really print anything */
136 return;
137 }
138
139 array_foreach_modifiable(&ctx->headers, hdr) {
140 if (strcmp(hdr->key, key) == 0) {
141 i_free(hdr->sticky_value);
142 hdr->sticky_value = i_strdup(value);
143 return;
144 }
145 }
146 i_unreached();
147 }
148
doveadm_print_flush(void)149 void doveadm_print_flush(void)
150 {
151 if (ctx != NULL && ctx->v->flush != NULL)
152 ctx->v->flush();
153 o_stream_uncork(doveadm_print_ostream);
154 o_stream_cork(doveadm_print_ostream);
155 }
156
doveadm_print_unstick_headers(void)157 void doveadm_print_unstick_headers(void)
158 {
159 struct doveadm_print_header_context *hdr;
160
161 if (ctx != NULL) {
162 array_foreach_modifiable(&ctx->headers, hdr)
163 hdr->sticky = FALSE;
164 }
165 }
166
doveadm_print_init(const char * name)167 void doveadm_print_init(const char *name)
168 {
169 pool_t pool;
170 unsigned int i;
171
172 if (ctx != NULL) {
173 /* already forced the type */
174 return;
175 }
176
177 pool = pool_alloconly_create("doveadm print", 1024);
178 ctx = p_new(pool, struct doveadm_print_context, 1);
179 ctx->pool = pool;
180 p_array_init(&ctx->headers, pool, 16);
181
182 for (i = 0; doveadm_print_vfuncs_all[i] != NULL; i++) {
183 if (strcmp(doveadm_print_vfuncs_all[i]->name, name) == 0) {
184 ctx->v = doveadm_print_vfuncs_all[i];
185 break;
186 }
187 }
188 if (ctx->v == NULL)
189 i_fatal("Unknown print formatter: %s", name);
190 if (ctx->v->init != NULL)
191 ctx->v->init();
192 }
193
doveadm_print_deinit(void)194 void doveadm_print_deinit(void)
195 {
196 struct doveadm_print_header_context *hdr;
197
198 if (ctx == NULL)
199 return;
200
201 if (ctx->v->flush != NULL && doveadm_print_ostream != NULL) {
202 ctx->v->flush();
203 o_stream_uncork(doveadm_print_ostream);
204 }
205 if (ctx->v->deinit != NULL)
206 ctx->v->deinit();
207 array_foreach_modifiable(&ctx->headers, hdr)
208 i_free(hdr->sticky_value);
209 pool_unref(&ctx->pool);
210 ctx = NULL;
211 }
212