summaryrefslogtreecommitdiffstats
path: root/src/lib-mail/mail-user-hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib-mail/mail-user-hash.c')
-rw-r--r--src/lib-mail/mail-user-hash.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/src/lib-mail/mail-user-hash.c b/src/lib-mail/mail-user-hash.c
new file mode 100644
index 0000000..88724a6
--- /dev/null
+++ b/src/lib-mail/mail-user-hash.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "md5.h"
+#include "str.h"
+#include "var-expand.h"
+#include "mail-user-hash.h"
+
+bool mail_user_hash(const char *username, const char *format,
+ unsigned int *hash_r, const char **error_r)
+{
+ unsigned char md5[MD5_RESULTLEN];
+ unsigned int i, hash = 0;
+ int ret = 1;
+
+ if (strcmp(format, "%u") == 0) {
+ /* fast path */
+ md5_get_digest(username, strlen(username), md5);
+ } else if (strcmp(format, "%Lu") == 0) {
+ /* almost as fast path */
+ T_BEGIN {
+ md5_get_digest(t_str_lcase(username),
+ strlen(username), md5);
+ } T_END;
+ } else T_BEGIN {
+ const struct var_expand_table tab[] = {
+ { 'u', username, "user" },
+ { 'n', t_strcut(username, '@'), "username" },
+ { 'd', i_strchr_to_next(username, '@'), "domain" },
+ { '\0', NULL, NULL }
+ };
+ string_t *str = t_str_new(128);
+
+ ret = var_expand(str, format, tab, error_r);
+ i_assert(ret >= 0);
+ md5_get_digest(str_data(str), str_len(str), md5);
+ } T_END_PASS_STR_IF(ret == 0, error_r);
+ for (i = 0; i < sizeof(hash); i++)
+ hash = (hash << CHAR_BIT) | md5[i];
+ if (hash == 0) {
+ /* Make sure we don't return the hash as 0, since it's often
+ treated in a special way that won't work well. For example
+ trying to insert it into a hash table will assert-crash. */
+ hash = 1;
+ }
+ *hash_r = hash;
+ return ret > 0;
+}