Skip to content

Commit

Permalink
Added a quirks mode for ProtonMail
Browse files Browse the repository at this point in the history
Fixes issue #674
  • Loading branch information
jstedfast committed Mar 13, 2018
1 parent e8c7027 commit 5b6032d
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 20 deletions.
41 changes: 21 additions & 20 deletions MailKit/Net/Imap/ImapEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ enum ImapUntaggedResult {
Handled
}

enum ImapQuirksMode {
None,
ProtonMail
}

class ImapFolderNameComparer : IEqualityComparer<string>
{
public char DirectorySeparator;
Expand Down Expand Up @@ -132,6 +137,7 @@ class ImapEngine : IDisposable
internal readonly Dictionary<string, ImapFolder> FolderCache;
readonly CreateImapFolderDelegate createImapFolder;
readonly ImapFolderNameComparer cacheComparer;
internal ImapQuirksMode QuirksMode;
readonly List<ImapCommand> queue;
internal char TagPrefix;
ImapCommand current;
Expand Down Expand Up @@ -169,6 +175,7 @@ public ImapEngine (CreateImapFolderDelegate createImapFolderDelegate)
ProtocolVersion = ImapProtocolVersion.Unknown;
createImapFolder = createImapFolderDelegate;
Capabilities = ImapCapabilities.None;
QuirksMode = ImapQuirksMode.None;
queue = new List<ImapCommand> ();
}

Expand Down Expand Up @@ -561,6 +568,7 @@ public async Task ConnectAsync (ImapStream stream, bool doAsync, CancellationTok
Rights.Clear ();

State = ImapEngineState.Connected;
QuirksMode = ImapQuirksMode.None;
SupportedCharsets.Add ("UTF-8");
CapabilitiesVersion = 0;
QResyncEnabled = false;
Expand Down Expand Up @@ -605,7 +613,10 @@ public async Task ConnectAsync (ImapStream stream, bool doAsync, CancellationTok
OnAlert (code.Message);
} else if (token.Type != ImapTokenType.Eoln) {
// throw away any remaining text up until the end of the line
await ReadLineAsync (doAsync, cancellationToken).ConfigureAwait (false);
var line = await ReadLineAsync (doAsync, cancellationToken).ConfigureAwait (false);

if (line.IndexOf ("ProtonMail", StringComparison.OrdinalIgnoreCase) != -1)
QuirksMode = ImapQuirksMode.ProtonMail;
}
} catch {
Disconnect ();
Expand Down Expand Up @@ -2252,30 +2263,20 @@ public async Task QuerySpecialFoldersAsync (bool doAsync, CancellationToken canc
list.Clear ();

if ((Capabilities & ImapCapabilities.SpecialUse) != 0) {
ic = new ImapCommand (this, cancellationToken, null, "LIST (SPECIAL-USE) \"\" \"*\"\r\n");
// Note: Some IMAP servers like ProtonMail respond to SPECIAL-USE LIST queries with BAD, so fall
// back to just issuing a standard LIST command and hope we get back some SPECIAL-USE attributes.
//
// See https://github.com/jstedfast/MailKit/issues/674 for dertails.
if (QuirksMode != ImapQuirksMode.ProtonMail)
ic = new ImapCommand (this, cancellationToken, null, "LIST (SPECIAL-USE) \"\" \"*\"\r\n");
else
ic = new ImapCommand (this, cancellationToken, null, "LIST \"\" \"%%\"\r\n");
ic.RegisterUntaggedHandler ("LIST", ImapUtils.ParseFolderListAsync);
ic.UserData = list;

QueueCommand (ic);

try {
await RunAsync (ic, doAsync).ConfigureAwait (false);
} catch (ImapCommandException) {
// Note: Some IMAP servers like ProtonMail respond to SPECIAL-USE LIST queries with BAD, so fall
// back to just issuing a standard LIST command and hope we get back some SPECIAL-USE attributes.
//
// See https://github.com/jstedfast/MailKit/issues/674 for dertails.
ic = new ImapCommand (this, cancellationToken, null, "LIST \"\" \"%\"\r\n");
ic.RegisterUntaggedHandler ("LIST", ImapUtils.ParseFolderListAsync);
ic.UserData = list;

list.Clear ();

QueueCommand (ic);

await RunAsync (ic, doAsync).ConfigureAwait (false);
}

await RunAsync (ic, doAsync).ConfigureAwait (false);
await LookupParentFoldersAsync (list, doAsync, cancellationToken).ConfigureAwait (false);

AssignSpecialFolders (list);
Expand Down
2 changes: 2 additions & 0 deletions MailKit/Net/Imap/ImapUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -443,10 +443,12 @@ public static async Task ParseFolderListAsync (ImapEngine engine, ImapCommand ic
switch (token.Type) {
case ImapTokenType.Literal:
encodedName = await engine.ReadLiteralAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
encodedName.TrimEnd (delim);
break;
case ImapTokenType.QString:
case ImapTokenType.Atom:
encodedName = (string) token.Value;
encodedName.TrimEnd (delim);
break;
case ImapTokenType.Nil:
// Note: according to rfc3501, section 4.5, NIL is acceptable as a mailbox name.
Expand Down

0 comments on commit 5b6032d

Please sign in to comment.