Skip to content

Commit

Permalink
charset-alias-plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
hyoshizane authored and sirainen committed Feb 19, 2018
1 parent de3e700 commit a12a2fa
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 1 deletion.
1 change: 1 addition & 0 deletions configure.ac
Expand Up @@ -3094,6 +3094,7 @@ src/plugins/imap-zlib/Makefile
src/plugins/mail-crypt/Makefile
src/plugins/var-expand-crypt/Makefile
src/plugins/apparmor/Makefile
src/plugins/charset-alias/Makefile
stamp.h
dovecot-config.in])

Expand Down
3 changes: 2 additions & 1 deletion src/plugins/Makefile.am
Expand Up @@ -52,4 +52,5 @@ SUBDIRS = \
$(DICT_LDAP) \
$(APPARMOR) \
fs-compress \
var-expand-crypt
var-expand-crypt \
charset-alias
19 changes: 19 additions & 0 deletions src/plugins/charset-alias/Makefile.am
@@ -0,0 +1,19 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-charset \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-storage

NOPLUGIN_LDFLAGS =
lib20_charset_alias_plugin_la_LDFLAGS = -module -avoid-version

module_LTLIBRARIES = \
lib20_charset_alias_plugin.la

lib20_charset_alias_plugin_la_SOURCES = \
charset-alias-plugin.c

noinst_HEADERS = \
charset-alias-plugin.h
199 changes: 199 additions & 0 deletions src/plugins/charset-alias/charset-alias-plugin.c
@@ -0,0 +1,199 @@
/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "array.h"
#include "str.h"
#include "mail-user.h"
#include "mail-storage-private.h"
#include "mail-storage-hooks.h"
#include "charset-utf8-private.h"
#include "charset-alias-plugin.h"


#define CHARSET_ALIAS_USER_CONTEXT(obj) \
MODULE_CONTEXT(obj, charset_alias_user_module)

static MODULE_CONTEXT_DEFINE_INIT(charset_alias_user_module,
&mail_user_module_register);

const char *charset_alias_plugin_version = DOVECOT_ABI_VERSION;

static int charset_alias_to_utf8_begin(const char *charset,
normalizer_func_t *normalizer,
struct charset_translation **t_r);

static void charset_alias_to_utf8_end(struct charset_translation *t);

static void charset_alias_to_utf8_reset(struct charset_translation *t);

static enum charset_result charset_alias_to_utf8(struct charset_translation *t,
const unsigned char *src,
size_t *src_size, buffer_t *dest);

/* charset_utf8_vfuncs is defined in lib-charset/charset-utf8.c */
extern const struct charset_utf8_vfuncs *charset_utf8_vfuncs;

static const struct charset_utf8_vfuncs *original_charset_utf8_vfuncs;

static const struct charset_utf8_vfuncs charset_alias_utf8_vfuncs = {
charset_alias_to_utf8_begin,
charset_alias_to_utf8_end,
charset_alias_to_utf8_reset,
charset_alias_to_utf8
};

struct charset_alias {
const char *charset;
const char *alias;
};

static ARRAY(struct charset_alias) charset_aliases;
static pool_t charset_alias_pool;
static int charset_alias_user_refcount = 0;

struct charset_alias_user {
union mail_user_module_context module_ctx;
};


static const char *charset_alias_get_alias(const char *charset)
{
const struct charset_alias* elem;
const char *key;

if (array_is_created(&charset_aliases)) {
key = t_str_lcase(charset);
array_foreach(&charset_aliases, elem) {
if (strcmp(key, elem->charset) == 0) {
return elem->alias;
}
}
}
return charset;
}

static int charset_alias_to_utf8_begin(const char *charset,
normalizer_func_t *normalizer,
struct charset_translation **t_r)
{
i_assert(original_charset_utf8_vfuncs != NULL);
charset = charset_alias_get_alias(charset);
return original_charset_utf8_vfuncs->to_utf8_begin(charset, normalizer, t_r);
}
static void charset_alias_to_utf8_end(struct charset_translation *t)
{
i_assert(original_charset_utf8_vfuncs != NULL);
return original_charset_utf8_vfuncs->to_utf8_end(t);
}

static void charset_alias_to_utf8_reset(struct charset_translation *t)
{
i_assert(original_charset_utf8_vfuncs != NULL);
return original_charset_utf8_vfuncs->to_utf8_reset(t);
}

static enum charset_result charset_alias_to_utf8(struct charset_translation *t,
const unsigned char *src,
size_t *src_size, buffer_t *dest)
{
i_assert(original_charset_utf8_vfuncs != NULL);
return original_charset_utf8_vfuncs->to_utf8(t, src, src_size, dest);
}

static unsigned int charset_aliases_init(struct mail_user *user, pool_t pool, const char *str)
{
const char *key, *value, *const *keyvalues;
struct charset_alias alias;
int i;

i_assert(!array_is_created(&charset_aliases));

p_array_init(&charset_aliases, pool, 1);
keyvalues = t_strsplit_spaces(str, " ");
for (i = 0; keyvalues[i] != '\0'; i++) {
value = strchr(keyvalues[i], '=');
if (value == NULL) {
i_error("charset_alias: Missing '=' in charset_aliases setting");
continue;
}
key = t_strdup_until(keyvalues[i], value++);
if (key[0] == '\0' || value[0] == '\0') {
i_error("charset_alias: charset or alias missing in charset_aliases setting");
continue;
}
if (strcasecmp(key, value) != 0) {
if (user->mail_debug)
i_debug("charset_alias: add charset-alias %s for %s", value, key);
alias.charset = p_strdup(pool, t_str_lcase(key));
alias.alias = p_strdup(pool, value);
array_append(&charset_aliases, &alias, 1);
}
}
return array_count(&charset_aliases);
}

static void charset_alias_utf8_vfuncs_set(void)
{
original_charset_utf8_vfuncs = charset_utf8_vfuncs;
charset_utf8_vfuncs = &charset_alias_utf8_vfuncs;
}

static void charset_alias_utf8_vfuncs_reset(void)
{
if (original_charset_utf8_vfuncs != NULL) {
charset_utf8_vfuncs = original_charset_utf8_vfuncs;
original_charset_utf8_vfuncs = NULL;
}
}

static void charset_alias_mail_user_deinit(struct mail_user *user)
{
struct charset_alias_user *cuser = CHARSET_ALIAS_USER_CONTEXT(user);

i_assert(charset_alias_user_refcount > 0);
if (--charset_alias_user_refcount == 0) {
charset_alias_utf8_vfuncs_reset();
array_free(&charset_aliases);
pool_unref(&charset_alias_pool);
}

cuser->module_ctx.super.deinit(user);
}

static void charset_alias_mail_user_created(struct mail_user *user)
{
struct mail_user_vfuncs *v = user->vlast;
struct charset_alias_user *cuser;
const char *str;

cuser = p_new(user->pool, struct charset_alias_user, 1);
cuser->module_ctx.super = *v;
user->vlast = &cuser->module_ctx.super;
v->deinit = charset_alias_mail_user_deinit;

if (charset_alias_user_refcount++ == 0) {
charset_alias_pool = pool_alloconly_create("charset_alias alias list", 128);
str = mail_user_plugin_getenv(user, "charset_aliases");
if (str != NULL && str[0] != '\0') {
if (charset_aliases_init(user, charset_alias_pool, str) > 0) {
charset_alias_utf8_vfuncs_set();
}
}
}

MODULE_CONTEXT_SET(user, charset_alias_user_module, cuser);
}

static struct mail_storage_hooks charset_alias_mail_storage_hooks = {
.mail_user_created = charset_alias_mail_user_created
};

void charset_alias_plugin_init(struct module *module)
{
mail_storage_hooks_add(module, &charset_alias_mail_storage_hooks);
}

void charset_alias_plugin_deinit(void)
{
mail_storage_hooks_remove(&charset_alias_mail_storage_hooks);
}
7 changes: 7 additions & 0 deletions src/plugins/charset-alias/charset-alias-plugin.h
@@ -0,0 +1,7 @@
#ifndef CHARSET_ALIAS_PLUGIN_H
#define CHARSET_ALIAS_PLUGIN_H

void charset_alias_plugin_init(struct module *module);
void charset_alias_plugin_deinit(void);

#endif

0 comments on commit a12a2fa

Please sign in to comment.