diff --git a/source/symmetry/imap/defines.d b/source/symmetry/imap/defines.d index 4d7690a..bf6cec3 100644 --- a/source/symmetry/imap/defines.d +++ b/source/symmetry/imap/defines.d @@ -39,6 +39,9 @@ enum Capability { @("IDLE") idle = 0x10, + @("AUTH=XOAUTH2") + oauth2, + @("IMAP4rev1") imap4Rev1, diff --git a/source/symmetry/imap/request.d b/source/symmetry/imap/request.d index 43f11fc..cde2952 100644 --- a/source/symmetry/imap/request.d +++ b/source/symmetry/imap/request.d @@ -191,7 +191,15 @@ Session login(Session session) { if (rg.status == ImapStatus.preAuth) { rl = ImapStatus.preAuth; } else { - if (session.capabilities.has(Capability.cramMD5) && session.options.cramMD5) { + if (session.capabilities.has(Capability.oauth2) && login.oauthToken.strip.length) { + version (Trace) stderr.writefln("oauth"); + import std.base64; + auto str = Base64.encode(cast(ubyte[]) ("user=" ~ login.username ~ "\x01auth=Bearer " ~ login.oauthToken.strip ~ "\x01\x01")); + t = session.check!sendRequest(format!"AUTHENTICATE XOAUTH2 %s"(str)); + res = session.check!responseGeneric(t); + version (Trace) stderr.writefln("response: %s", res); + rl = res.status; + } else if (session.capabilities.has(Capability.cramMD5) && session.options.cramMD5) { version (Trace) stderr.writefln("cram"); t = session.check!sendRequest("AUTHENTICATE CRAM-MD5"); res = session.check!responseAuthenticate(t); diff --git a/source/symmetry/imap/session.d b/source/symmetry/imap/session.d index e4e206f..c2b4c03 100644 --- a/source/symmetry/imap/session.d +++ b/source/symmetry/imap/session.d @@ -74,6 +74,9 @@ struct ImapLogin { @SILdoc("User's secret keyword. If a password wasn't supplied the user will be asked to enter one interactively the first time it will be needed. It takes a string as a value.") string password; + @SILdoc("OAuth2 token, if present, it will try this before the username and password.") + string oauthToken; + string toString() const { import std.format : format; return format!"%s:[hidden]"(username);