diff options
Diffstat (limited to 'src/plugins/imap-old-stats/imap-stats-plugin.c')
-rw-r--r-- | src/plugins/imap-old-stats/imap-stats-plugin.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/src/plugins/imap-old-stats/imap-stats-plugin.c b/src/plugins/imap-old-stats/imap-stats-plugin.c new file mode 100644 index 0000000..6c91aa7 --- /dev/null +++ b/src/plugins/imap-old-stats/imap-stats-plugin.c @@ -0,0 +1,128 @@ +/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */ + +#include "imap-common.h" +#include "base64.h" +#include "str.h" +#include "imap-commands.h" +#include "stats.h" +#include "stats-plugin.h" +#include "stats-connection.h" +#include "imap-stats-plugin.h" + +#define IMAP_STATS_IMAP_CONTEXT(obj) \ + MODULE_CONTEXT(obj, imap_stats_imap_module) + +struct stats_client_command { + union imap_module_context module_ctx; + + unsigned int id; + bool continued; + struct stats *stats, *pre_stats; +}; + +static MODULE_CONTEXT_DEFINE_INIT(imap_stats_imap_module, + &imap_module_register); + +const char *imap_stats_plugin_version = DOVECOT_ABI_VERSION; + +static void stats_command_pre(struct client_command_context *cmd) +{ + struct stats_user *suser = STATS_USER_CONTEXT(cmd->client->user); + struct stats_client_command *scmd; + static unsigned int stats_cmd_id_counter = 0; + + if (suser == NULL || !suser->track_commands) + return; + + if (strcasecmp(cmd->name, "IDLE") == 0) { + /* IDLE can run forever and waste stats process's memory while + waiting for it to timeout. don't send them. */ + return; + } + + scmd = IMAP_STATS_IMAP_CONTEXT(cmd); + if (scmd == NULL) { + scmd = p_new(cmd->pool, struct stats_client_command, 1); + scmd->id = ++stats_cmd_id_counter; + scmd->stats = stats_alloc(cmd->pool); + scmd->pre_stats = stats_alloc(cmd->pool); + MODULE_CONTEXT_SET(cmd, imap_stats_imap_module, scmd); + } + + mail_user_stats_fill(cmd->client->user, scmd->pre_stats); +} + +static void stats_command_post(struct client_command_context *cmd) +{ + struct stats_user *suser = STATS_USER_CONTEXT(cmd->client->user); + struct stats_client_command *scmd = IMAP_STATS_IMAP_CONTEXT(cmd); + struct stats *new_stats, *diff_stats; + const char *error; + size_t args_pos = 0, args_len = 0; + string_t *str; + buffer_t *buf; + + if (suser == NULL || scmd == NULL) + return; + + new_stats = stats_alloc(pool_datastack_create()); + diff_stats = stats_alloc(pool_datastack_create()); + + mail_user_stats_fill(cmd->client->user, new_stats); + if (!stats_diff(scmd->pre_stats, new_stats, diff_stats, &error)) + i_error("stats: command stats shrank: %s", error); + stats_add(scmd->stats, diff_stats); + + str = t_str_new(128); + str_append(str, "UPDATE-CMD\t"); + str_append(str, suser->stats_session_id); + + str_printfa(str, "\t%u\t", scmd->id); + if (cmd->state == CLIENT_COMMAND_STATE_DONE) + str_append_c(str, 'd'); + if (scmd->continued) + str_append_c(str, 'c'); + else { + str_append_c(str, '\t'); + str_append(str, cmd->name); + str_append_c(str, '\t'); + args_pos = str_len(str); + if (cmd->args != NULL) + str_append(str, cmd->args); + args_len = str_len(str) - args_pos; + scmd->continued = TRUE; + } + + buf = t_buffer_create(128); + stats_export(buf, scmd->stats); + str_append_c(str, '\t'); + base64_encode(buf->data, buf->used, str); + + str_append_c(str, '\n'); + + if (str_len(str) > PIPE_BUF) { + /* truncate the args so it fits */ + size_t delete_count = str_len(str) - PIPE_BUF; + + i_assert(args_pos != 0); + if (delete_count > args_len) + delete_count = args_len; + str_delete(str, args_pos + args_len - delete_count, + delete_count); + } + + stats_connection_send(suser->stats_conn, str); +} + +void imap_old_stats_plugin_init(struct module *module ATTR_UNUSED) +{ + command_hook_register(stats_command_pre, stats_command_post); +} + +void imap_old_stats_plugin_deinit(void) +{ + command_hook_unregister(stats_command_pre, stats_command_post); +} + +const char *imap_old_stats_plugin_dependencies[] = { "old_stats", NULL }; +const char imap_old_stats_plugin_binary_dependency[] = "imap"; |