Search code examples
delphiindy10delphi-10.2-tokyo

Bug in TIdIMAP4.ListMailBoxes?


When I execute this command on a client's Lotus Notes server, I get lines returned looking like this:

* LIST (\HasNoChildren) "\\" Folder\Subfolder 1
* LIST (\HasNoChildren) "\\" Folder\Subfolder 2

In the resulting list, this is stored as:

[0] LIST
[1] \HasNoChildren
[2] \
[3] Folder\Subfolder
[4] 1

As I put this in a TreeView, I end up with:

- 1
|
- 2
|
- Folder
  |
  - Subfolder

My questions:

  1. is the IMAP server's response valid according to the protocol?

  2. how can I change the Notes config so it outputs the correct data (provided the client is willing to change it)?

  3. Is this a bug?

  4. And if so, how can I work around it?

I see there are two "failing" procedures: InternalParseListResult and ParseIntoBrackettedQuotedAndUnquotedParts.

Shouldn't ParseIntoBrackettedQuotedAndUnquotedParts simply regard everything after the delimiter as a Folder path?

InternalParseListResult doesn't check index 2 as Delimiter, instead it takes the one to last entry and takes the first character of that. In the example, the delimiter would become 'F'. It also decides that the last index is the folder name, so the folder ends up as '1' or '2'. Shouldn't it take the delimiter from LSlRetrieve[2] and regard LSlRetrieve[3] and higher as the folder name?

As all of these functions and procedures aren't virtual, I cannot create a descendant to reimplement the behavior. I can change Indy's code and have it revert back with the next update, so I am not looking to go that route.

When I run the command on our MS Outlook server, everything works as expected, as that returns lines like:

* LIST (\HasNoChildren) "." "INBOX.Folder.Subfolder 1"
* LIST (\HasNoChildren) "." "INBOX.Folder.Subfolder 2"

Solution

  • is the IMAP Server's response valid according to the protocol?

    As near as I can tell, yes.

    how can I change the Notes config so it outputs the correct data (provided the client is willing to change it)

    You don't.

    Is this a bug?

    Looks like it, yes. I have opened a ticket in Indy's issue tracker:

    https://github.com/IndySockets/Indy/issues/329

    And if so, how can I work around it?

    You could alter Indy's source code and recompile it. Which, as you already noted, will have to be applied each time Indy is updated.

    The alternative would be to use detour hooks to redirect the failing functions to your own replacement functions. They don't need to be virtual to be detoured.