///
module imap.auth;
import imap.sil : SILdoc;
import std.string;
import std.stdio;
import deimos.openssl.ssl;
import deimos.openssl.hmac;
import deimos.openssl.evp;
import imap.defines;


@SILdoc("challenge-response authentication mechanism MD5")
string authCramMD5(string user, string pass, string challenge) {
    import std.conv : to;
    import std.algorithm : map;
    import std.array : array;
    import std.string : join;
    import std.format : format;
    size_t n;
    uint i;
    ubyte[] resp, ret;
    ubyte[EVP_MAX_MD_SIZE] md;
    uint mdlen;
    HMAC_CTX hmac;

    n = challenge.length * 3 / 4 + 1;
    resp.length = n;
    EVP_DecodeBlock(resp.ptr, cast(const(ubyte) *) challenge.toStringz, challenge.length.to!int);

    HMAC_Init(&hmac, cast(const(void) *) pass.toStringz, pass.length.to!int, EVP_md5());
    HMAC_Update(&hmac, cast(const(ubyte) *) resp.ptr, resp.length.to!int);
    HMAC_Final(&hmac, md.ptr, &mdlen);

    auto mdhex = md[0 .. mdlen]
        .map!(c => format!"%02X"(c)).array.join("");
    auto buf = format!"%s %s"(user, mdhex);
    n = (buf.length + 3) * 4 / 3 + 1;
    ret.length = n;
    EVP_EncodeBlock(ret.ptr, cast(ubyte*) buf.ptr, buf.length.to!int);
    return cast(string) (ret.idup);
}