doveadm-zlib.c revision 43a6cdb3561dcfc5950542ce62509a7747a977ae
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "lib.h"
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen#include "net.h"
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen#include "istream.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "ostream.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "istream-zlib.h"
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch#include "ostream-zlib.h"
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch#include "module-dir.h"
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch#include "master-service.h"
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch#include "doveadm-dump.h"
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include <stdio.h>
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include <fcntl.h>
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include <unistd.h>
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic bool test_dump_imapzlib(const char *path)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char *p;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen char buf[4096];
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen int fd, ret;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen bool match = FALSE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen p = strrchr(path, '.');
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (p == NULL || (strcmp(p, ".in") != 0 && strcmp(p, ".out") != 0))
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return FALSE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen fd = open(path, O_RDONLY);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (fd == -1)
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen return FALSE;
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen ret = read(fd, buf, sizeof(buf)-1);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (ret > 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen buf[ret] = '\0';
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen (void)str_lcase(buf);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen match = strstr(buf, " ok begin compression.") != NULL ||
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen strstr(buf, " compress deflate") != NULL;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_close_fd(&fd);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen return match;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen}
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen#ifdef HAVE_ZLIB
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic void cmd_dump_imapzlib(int argc ATTR_UNUSED, char *argv[])
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen struct istream *input, *input2;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen const unsigned char *data;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen size_t size;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char *line;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen int fd;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch fd = open(argv[1], O_RDONLY);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (fd < 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_fatal("open(%s) failed: %m", argv[1]);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen input = i_stream_create_fd_autoclose(&fd, 1024*32);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen while ((line = i_stream_read_next_line(input)) != NULL) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* skip tag */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen printf("%s\r\n", line);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen while (*line != ' ' && *line != '\0') line++;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (*line == '\0')
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch continue;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch line++;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen if (strncmp(line, "OK Begin compression", 20) == 0 ||
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston strcasecmp(line, "COMPRESS DEFLATE") == 0)
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston break;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch input2 = i_stream_create_deflate(input, TRUE);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_stream_unref(&input);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch while (i_stream_read_more(input2, &data, &size) != -1) {
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (fwrite(data, 1, size, stdout) != size)
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen break;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen i_stream_skip(input2, size);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_stream_unref(&input2);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen fflush(stdout);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstruct client {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen int fd;
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen struct io *io_client, *io_server;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct istream *input;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct ostream *output;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen bool compressed;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen};
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic void client_input(struct client *client)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct istream *input;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct ostream *output;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen unsigned char buf[1024];
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen ssize_t ret;
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen ret = read(STDIN_FILENO, buf, sizeof(buf));
cd2fc7dd28c3a2e3f82e8480eaf3ba7c4abc3614Timo Sirainen if (ret == 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (client->compressed) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen master_service_stop(master_service);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* start compression */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_info("<Compression started>");
526631052ca3175357302af8fa7dcbf763b40c53Stephan Bosch input = i_stream_create_deflate(client->input, TRUE);
526631052ca3175357302af8fa7dcbf763b40c53Stephan Bosch output = o_stream_create_deflate(client->output, 6);
526631052ca3175357302af8fa7dcbf763b40c53Stephan Bosch i_stream_unref(&client->input);
526631052ca3175357302af8fa7dcbf763b40c53Stephan Bosch o_stream_unref(&client->output);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->input = input;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch client->output = output;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch client->compressed = TRUE;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen if (ret < 0)
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston i_fatal("read(stdin) failed: %m");
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch o_stream_nsend(client->output, buf, ret);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch}
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
c649139f889c02154fc9a153728b81619edb5663Timo Sirainenstatic void server_input(struct client *client)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const unsigned char *data;
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch size_t size;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (i_stream_read(client->input) == -1) {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (client->input->stream_errno != 0) {
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston i_fatal("read(server) failed: %s",
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston i_stream_get_error(client->input));
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston }
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston i_info("Server disconnected");
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston master_service_stop(master_service);
53ec1ff2231d477db3103c51987fa9cb6033bc16Timo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch data = i_stream_get_data(client->input, &size);
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen if (write(STDOUT_FILENO, data, size) < 0)
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen i_fatal("write(stdout) failed: %m");
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen i_stream_skip(client->input, size);
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen}
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen
88b90ce9dfe1056d1ec5497b95592d30a849e5f1Timo Sirainenstatic void cmd_zlibconnect(int argc ATTR_UNUSED, char *argv[])
88b90ce9dfe1056d1ec5497b95592d30a849e5f1Timo Sirainen{
526631052ca3175357302af8fa7dcbf763b40c53Stephan Bosch struct client client;
526631052ca3175357302af8fa7dcbf763b40c53Stephan Bosch struct ip_addr *ips;
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen unsigned int ips_count;
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen in_port_t port = 143;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen int fd, ret;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (argv[1] == NULL ||
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen (argv[2] != NULL && net_str2port(argv[2], &port) < 0))
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen help(&doveadm_cmd_zlibconnect);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch ret = net_gethostbyname(argv[1], &ips, &ips_count);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (ret != 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_fatal("Host %s lookup failed: %s", argv[1],
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen net_gethosterror(ret));
f7fa93fb42a5b9d4a7e2f0367f03f920ef7ec443Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
f7fa93fb42a5b9d4a7e2f0367f03f920ef7ec443Timo Sirainen if ((fd = net_connect_ip(&ips[0], port, NULL)) == -1)
f7fa93fb42a5b9d4a7e2f0367f03f920ef7ec443Timo Sirainen i_fatal("connect(%s, %u) failed: %m", argv[1], port);
f7fa93fb42a5b9d4a7e2f0367f03f920ef7ec443Timo Sirainen
dafbec2c6b4275233a78cb137f41dd8041aa1c46Timo Sirainen i_info("Connected to %s port %u. Ctrl-D starts compression",
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch net_ip2addr(&ips[0]), port);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston i_zero(&client);
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston client.fd = fd;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client.input = i_stream_create_fd(fd, (size_t)-1);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client.output = o_stream_create_fd(fd, 0);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen o_stream_set_no_error_handling(client.output, TRUE);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client.io_client = io_add(STDIN_FILENO, IO_READ, client_input, &client);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client.io_server = io_add(fd, IO_READ, server_input, &client);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen master_service_run(master_service, NULL);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen io_remove(&client.io_client);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen io_remove(&client.io_server);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_stream_unref(&client.input);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen o_stream_unref(&client.output);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (close(fd) < 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_fatal("close() failed: %m");
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#else
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic void cmd_dump_imapzlib(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_fatal("Dovecot compiled without zlib support");
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic void cmd_zlibconnect(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_fatal("Dovecot compiled without zlib support");
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#endif
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstruct doveadm_cmd_dump doveadm_cmd_dump_zlib = {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen "imapzlib",
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen test_dump_imapzlib,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen cmd_dump_imapzlib
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen};
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstruct doveadm_cmd doveadm_cmd_zlibconnect = {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen cmd_zlibconnect,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen "zlibconnect",
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen "<host> [<port>]"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen};
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen