Skip to content

Commit

Permalink
fix(mail): improve algo to fetch imap folders for mail view
Browse files Browse the repository at this point in the history
  • Loading branch information
QHivert committed Sep 11, 2024
1 parent 2a17449 commit 68f4fc1
Showing 1 changed file with 141 additions and 139 deletions.
280 changes: 141 additions & 139 deletions SoObjects/Mailer/SOGoMailAccount.m
Original file line number Diff line number Diff line change
Expand Up @@ -454,64 +454,55 @@ - (NSArray *) allFolderPaths: (SOGoMailListingMode) theListingMode
//
- (NSString *) _folderType: (NSString *) folderName
flags: (NSMutableArray *) flags
folderTypes: (NSDictionary *) folderTypes
{
static NSDictionary *metadata = nil;
NSString *folderType, *key, *rights;
static NSDictionary *folderTypeDict = nil;
NSString *folderType, *key, *rights, *flag;
NSEnumerator *flagEnum;
SOGoUserDefaults *ud;

if (!metadata)
{
ud = [[context activeUser] userDefaults];
metadata = [[[self imap4Connection] allFoldersMetadataForURL: [self imap4URL]
onlySubscribedFolders: [ud mailShowSubscribedFoldersOnly]]
objectForKey: @"list"];
[metadata retain];
}
{
ud = [[context activeUser] userDefaults];
metadata = [[[self imap4Connection] allFoldersMetadataForURL: [self imap4URL]
onlySubscribedFolders: [ud mailShowSubscribedFoldersOnly]]
objectForKey: @"list"];
[metadata retain];
}

key = [NSString stringWithFormat: @"/%@", folderName];
[flags addObjectsFromArray: [metadata objectForKey: key]];

// RFC6154 (https://tools.ietf.org/html/rfc6154) describes special uses for IMAP mailboxes.
// We do honor them, as long as your SOGo{Drafts,Trash,Sent,Junk}FolderName are properly configured
// See http://wiki.dovecot.org/MailboxSettings for a Dovecot example.
if ([folderName isEqualToString: inboxFolderName])
folderType = @"inbox";
else if ([flags containsObject: [self draftsFolderNameInContext: context]] ||
[folderName isEqualToString: [self draftsFolderNameInContext: context]])
folderType = @"draft";
else if ([flags containsObject: [self sentFolderNameInContext: context]] ||
[folderName isEqualToString: [self sentFolderNameInContext: context]])
folderType = @"sent";
else if ([flags containsObject: [self trashFolderNameInContext: context]] ||
[folderName isEqualToString: [self trashFolderNameInContext: context]])
folderType = @"trash";
else if ([flags containsObject: [self junkFolderNameInContext: context]] ||
[folderName isEqualToString: [self junkFolderNameInContext: context]])
folderType = @"junk";
else if ([flags containsObject: [self templatesFolderNameInContext: context]] ||
[folderName isEqualToString: [self templatesFolderNameInContext: context]])
folderType = @"templates";
else if ([folderName isEqualToString: otherUsersFolderName])
folderType = @"otherUsers";
else if ([folderName isEqualToString: sharedFoldersName])
folderType = @"shared";
else
if((folderType = [folderTypes objectForKey: folderName]))
return folderType;

flagEnum = [flags objectEnumerator];
while((flag = [flagEnum nextObject]))
{
if([flag isEqualToString: inboxFolderName] || [flag isEqualToString: otherUsersFolderName] || [flag isEqualToString: sharedFoldersName])
continue;
if((folderType = [folderTypes objectForKey: flag]))
return folderType;
}

folderType = @"folder";
if (([sharedFoldersName length] && [folderName hasPrefix: sharedFoldersName]) ||
([otherUsersFolderName length] && [folderName hasPrefix: otherUsersFolderName]))
{
rights = [[self imap4Connection] myRightsForMailboxAtURL: [NSURL URLWithString: folderName]];
if (![rights isKindOfClass: [NSException class]] &&
([rights rangeOfString: @"r"].location == NSNotFound))
{
folderType = @"folder";
if (([sharedFoldersName length] && [folderName hasPrefix: sharedFoldersName]) ||
([otherUsersFolderName length] && [folderName hasPrefix: otherUsersFolderName]))
{
rights = [[self imap4Connection] myRightsForMailboxAtURL: [NSURL URLWithString: folderName]];
if (![rights isKindOfClass: [NSException class]] &&
([rights rangeOfString: @"r"].location == NSNotFound))
{
[flags addObjectUniquely: @"noselect"];
if ([rights rangeOfString: @"i"].location != NSNotFound)
// No read but insert = dropbox
folderType = @"dropbox";
}
}
[flags addObjectUniquely: @"noselect"];
if ([rights rangeOfString: @"i"].location != NSNotFound)
// No read but insert = dropbox
folderType = @"dropbox";
}
}

return folderType;
}
Expand All @@ -521,6 +512,7 @@ - (NSString *) _folderType: (NSString *) folderName
//
- (NSMutableDictionary *) _insertFolder: (NSString *) folderPath
foldersList: (NSMutableArray *) theFolders
folderTypes: (NSDictionary *) folderTypes
{
NSArray *pathComponents;
NSMutableArray *folders, *flags;
Expand All @@ -541,103 +533,99 @@ - (NSMutableDictionary *) _insertFolder: (NSString *) folderPath
// The variable folderPath is something like '/INBOX/Junk' so pathComponents becomes ('/', 'INBOX', 'Junk').
// That's why we always ignore the first element
for (i = 1; i < count; i++)
{
last = ((count - i) == 1);
folder = nil;
if ([currentPath length])
currentPath = [NSString stringWithFormat: @"%@/%@", currentPath, [pathComponents objectAtIndex: i]];
else
currentPath = [pathComponents objectAtIndex: i];
{
last = ((count - i) == 1);
folder = nil;
if ([currentPath length])
currentPath = [NSString stringWithFormat: @"%@/%@", currentPath, [pathComponents objectAtIndex: i]];
else
currentPath = [pathComponents objectAtIndex: i];

// Search for the current path in the children of the parent folder.
// For the first iteration, take the parent folder passed as argument.
if (parentFolder)
folders = [parentFolder objectForKey: @"children"];
else
folders = theFolders;
// Search for the current path in the children of the parent folder.
// For the first iteration, take the parent folder passed as argument.
if (parentFolder)
folders = [parentFolder objectForKey: @"children"];
else
folders = theFolders;

for (j = 0; j < [folders count]; j++)
{
currentFolder = [folders objectAtIndex: j];
if ([currentPath isEqualToString: [currentFolder objectForKey: @"path"]])
{
folder = currentFolder;
// Make sure all branches are ready to receive children
if (!last && ![folder objectForKey: @"children"])
[folder setObject: [NSMutableArray array] forKey: @"children"];
for (j = 0; j < [folders count]; j++)
{
currentFolder = [folders objectAtIndex: j];
if ([currentPath isEqualToString: [currentFolder objectForKey: @"path"]])
{
folder = currentFolder;
// Make sure all branches are ready to receive children
if (!last && ![folder objectForKey: @"children"])
[folder setObject: [NSMutableArray array] forKey: @"children"];
break;
}
}

break;
}
}
// Check if the current folder is the "Other users" folder (shared mailboxes)
currentFolderName = [[pathComponents objectAtIndex: i] stringByDecodingImap4FolderName];
if (otherUsersFolderName && [currentFolderName caseInsensitiveCompare: otherUsersFolderName] == NSOrderedSame)
isOtherUsersFolder = YES;
else
isOtherUsersFolder = NO;

// Check if the current folder is the "Other users" folder (shared mailboxes)
currentFolderName = [[pathComponents objectAtIndex: i] stringByDecodingImap4FolderName];
if (otherUsersFolderName
&& [currentFolderName caseInsensitiveCompare: otherUsersFolderName] == NSOrderedSame)
isOtherUsersFolder = YES;
if (folder == nil)
{
// Folder was not found; create it and add it to the folders list
if (parentIsOtherUsersFolder)
{
// Parent folder is the "Other users" folder; translate the user's mailbox name
// to the full name of the person
userManager = [SOGoUserManager sharedUserManager];
if ((fullName = [userManager getCNForUID: currentFolderName]) && [fullName length])
currentFolderName = fullName;
else if ((fullName = [userManager getEmailForUID: currentFolderName]) && [fullName length])
currentFolderName = fullName;
}
else if (isOtherUsersFolder)
currentFolderName = [self labelForKey: @"OtherUsersFolderName"];
else if (sharedFoldersName && [currentFolderName caseInsensitiveCompare: sharedFoldersName] == NSOrderedSame)
currentFolderName = [self labelForKey: @"SharedFoldersName"];

flags = [NSMutableArray array];

if (last)
{
folderType = [self _folderType: currentPath flags: flags folderTypes: folderTypes];
}
else
isOtherUsersFolder = NO;

if (folder == nil)
{
// Folder was not found; create it and add it to the folders list
if (parentIsOtherUsersFolder)
{
// Parent folder is the "Other users" folder; translate the user's mailbox name
// to the full name of the person
userManager = [SOGoUserManager sharedUserManager];
if ((fullName = [userManager getCNForUID: currentFolderName]) && [fullName length])
currentFolderName = fullName;
else if ((fullName = [userManager getEmailForUID: currentFolderName]) && [fullName length])
currentFolderName = fullName;
}
else if (isOtherUsersFolder)
currentFolderName = [self labelForKey: @"OtherUsersFolderName"];
else if (sharedFoldersName
&& [currentFolderName caseInsensitiveCompare: sharedFoldersName] == NSOrderedSame)
currentFolderName = [self labelForKey: @"SharedFoldersName"];

flags = [NSMutableArray array];

if (last)
{
folderType = [self _folderType: currentPath
flags: flags];
}
else
{
folderType = @"additional";
[flags addObject: @"noselect"];
}

if ([subscribedFolders objectForKey: folderPath])
isSubscribed = YES;
else
isSubscribed = NO;

folder = [NSMutableDictionary dictionaryWithObjectsAndKeys:
currentPath, @"path",
folderType, @"type",
currentFolderName, @"name",
[NSMutableArray array], @"children",
flags, @"flags",
[NSNumber numberWithBool: isSubscribed], @"subscribed",
nil];

if (sieveFolderUTF8Encoding)
sievePath = [currentPath stringByDecodingImap4FolderName];
else
sievePath = currentPath;
[folder setObject: sievePath forKey: @"sievePath"];

// Either add this new folder to its parent or the list of root folders
[folders addObject: folder];
}
{
folderType = @"additional";
[flags addObject: @"noselect"];
}

if ([subscribedFolders objectForKey: folderPath])
isSubscribed = YES;
else
isSubscribed = NO;

folder = [NSMutableDictionary dictionaryWithObjectsAndKeys:
currentPath, @"path",
folderType, @"type",
currentFolderName, @"name",
[NSMutableArray array], @"children",
flags, @"flags",
[NSNumber numberWithBool: isSubscribed], @"subscribed",
nil];

if (sieveFolderUTF8Encoding)
sievePath = [currentPath stringByDecodingImap4FolderName];
else
sievePath = currentPath;
[folder setObject: sievePath forKey: @"sievePath"];

parentFolder = folder;
parentIsOtherUsersFolder = isOtherUsersFolder;
// Either add this new folder to its parent or the list of root folders
[folders addObject: folder];
}

parentFolder = folder;
parentIsOtherUsersFolder = isOtherUsersFolder;
}

return parentFolder;
}

Expand All @@ -651,11 +639,25 @@ - (NSArray *) allFoldersMetadata: (SOGoMailListingMode) theListingMode
NSEnumerator *rawFolders;
NSAutoreleasePool *pool;
NSArray *allFolderPaths;
NSMutableDictionary *folderTypes;

allFolderPaths = [self allFolderPaths: theListingMode];
rawFolders = [allFolderPaths objectEnumerator];
folders = [NSMutableArray array];

folderTypes = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@"inbox", inboxFolderName,
@"draft", [self draftsFolderNameInContext: context],
@"sent", [self sentFolderNameInContext: context],
@"trash", [self trashFolderNameInContext: context],
@"junk", [self junkFolderNameInContext: context],
@"templates", [self templatesFolderNameInContext: context],
nil];
if(otherUsersFolderName && [otherUsersFolderName length] > 0)
[folderTypes setObject: @"otherUsers" forKey: otherUsersFolderName];
if(sharedFoldersName && [sharedFoldersName length] > 0)
[folderTypes setObject: @"shared" forKey: sharedFoldersName];

while ((currentFolder = [rawFolders nextObject]))
{
// Using a local pool to avoid using too many file descriptors. This could
Expand All @@ -666,7 +668,8 @@ - (NSArray *) allFoldersMetadata: (SOGoMailListingMode) theListingMode

// Insert folder into folders tree
[self _insertFolder: currentFolder
foldersList: folders];
foldersList: folders
folderTypes: folderTypes];

[pool release];
}
Expand Down Expand Up @@ -1119,11 +1122,10 @@ - (NSString *) _userFolderNameWithPurpose: (NSString *) purpose
folderName = [[account objectForKey: @"specialMailboxes"]
objectForKey: purpose];
if (!folderName && accountIdx > 0)
{
account = [accounts objectAtIndex: 0];
folderName = [[account objectForKey: @"specialMailboxes"]
objectForKey: purpose];
}
{
account = [accounts objectAtIndex: 0];
folderName = [[account objectForKey: @"specialMailboxes"] objectForKey: purpose];
}

return folderName;
}
Expand Down

0 comments on commit 68f4fc1

Please sign in to comment.