(feat) added IMAP folders subscriptions management (fixes #255)
parent
49d58b436e
commit
42127c51ab
|
@ -813,7 +813,7 @@ void handle_eas_terminate(int signum)
|
||||||
}
|
}
|
||||||
|
|
||||||
allFoldersMetadata = [NSMutableArray array];
|
allFoldersMetadata = [NSMutableArray array];
|
||||||
[self _flattenFolders: [accountFolder allFoldersMetadata] into: allFoldersMetadata parent: nil parentType: nil];
|
[self _flattenFolders: [accountFolder allFoldersMetadata: SOGoMailStandardListing] into: allFoldersMetadata parent: nil parentType: nil];
|
||||||
|
|
||||||
// Get GUIDs of folder (IMAP)
|
// Get GUIDs of folder (IMAP)
|
||||||
// e.g. {folderINBOX = folder6b93c528176f1151c7260000aef6df92}
|
// e.g. {folderINBOX = folder6b93c528176f1151c7260000aef6df92}
|
||||||
|
|
2
NEWS
2
NEWS
|
@ -2,7 +2,7 @@
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
New features
|
New features
|
||||||
-
|
- [web] added IMAP folder subscriptions management (#255)
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
- [web] don't allow a recurrence rule to end before the first occurrence
|
- [web] don't allow a recurrence rule to end before the first occurrence
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2009-2014 Inverse inc.
|
Copyright (C) 2009-2016 Inverse inc.
|
||||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
|
||||||
|
|
||||||
This file is part of SOGo.
|
This file is part of SOGo.
|
||||||
|
|
||||||
|
@ -35,6 +34,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@class NSArray;
|
@class NSArray;
|
||||||
|
@class NSMutableDictionary;
|
||||||
@class NSMutableArray;
|
@class NSMutableArray;
|
||||||
@class NSString;
|
@class NSString;
|
||||||
|
|
||||||
|
@ -50,6 +50,11 @@ typedef enum {
|
||||||
rfc4314
|
rfc4314
|
||||||
} SOGoIMAPAclStyle;
|
} SOGoIMAPAclStyle;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SOGoMailStandardListing = 0,
|
||||||
|
SOGoMailSubscriptionsManagementListing = 1
|
||||||
|
} SOGoMailListingMode;
|
||||||
|
|
||||||
@interface SOGoMailAccount : SOGoMailBaseObject
|
@interface SOGoMailAccount : SOGoMailBaseObject
|
||||||
{
|
{
|
||||||
SOGoMailFolder *inboxFolder;
|
SOGoMailFolder *inboxFolder;
|
||||||
|
@ -61,6 +66,7 @@ typedef enum {
|
||||||
NSMutableArray *identities;
|
NSMutableArray *identities;
|
||||||
NSString *otherUsersFolderName;
|
NSString *otherUsersFolderName;
|
||||||
NSString *sharedFoldersName;
|
NSString *sharedFoldersName;
|
||||||
|
NSMutableDictionary *subscribedFolders;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (SOGoIMAPAclStyle) imapAclStyle;
|
- (SOGoIMAPAclStyle) imapAclStyle;
|
||||||
|
@ -83,8 +89,8 @@ typedef enum {
|
||||||
/* folder pathes */
|
/* folder pathes */
|
||||||
- (NSArray *) toManyRelationshipKeysWithNamespaces: (BOOL) withNSs;
|
- (NSArray *) toManyRelationshipKeysWithNamespaces: (BOOL) withNSs;
|
||||||
|
|
||||||
- (NSArray *) allFolderPaths;
|
- (NSArray *) allFolderPaths: (SOGoMailListingMode) theListingMode;
|
||||||
- (NSArray *) allFoldersMetadata;
|
- (NSArray *) allFoldersMetadata: (SOGoMailListingMode) theListingMode;
|
||||||
|
|
||||||
- (NSDictionary *) imapFolderGUIDs;
|
- (NSDictionary *) imapFolderGUIDs;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
|
||||||
Copyright (C) 2007-2016 Inverse inc.
|
Copyright (C) 2007-2016 Inverse inc.
|
||||||
|
|
||||||
This file is part of SOGo.
|
This file is part of SOGo.
|
||||||
|
@ -25,7 +24,6 @@
|
||||||
#import <Foundation/NSURL.h>
|
#import <Foundation/NSURL.h>
|
||||||
#import <Foundation/NSValue.h>
|
#import <Foundation/NSValue.h>
|
||||||
|
|
||||||
|
|
||||||
#import <NGObjWeb/NSException+HTTP.h>
|
#import <NGObjWeb/NSException+HTTP.h>
|
||||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||||
#import <NGExtensions/NSNull+misc.h>
|
#import <NGExtensions/NSNull+misc.h>
|
||||||
|
@ -73,6 +71,7 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
identities = nil;
|
identities = nil;
|
||||||
otherUsersFolderName = nil;
|
otherUsersFolderName = nil;
|
||||||
sharedFoldersName = nil;
|
sharedFoldersName = nil;
|
||||||
|
subscribedFolders = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
@ -88,11 +87,10 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
[identities release];
|
[identities release];
|
||||||
[otherUsersFolderName release];
|
[otherUsersFolderName release];
|
||||||
[sharedFoldersName release];
|
[sharedFoldersName release];
|
||||||
|
[subscribedFolders release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* listing the available folders */
|
|
||||||
|
|
||||||
- (BOOL) isInDraftsFolder
|
- (BOOL) isInDraftsFolder
|
||||||
{
|
{
|
||||||
return NO;
|
return NO;
|
||||||
|
@ -116,8 +114,6 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* namespaces */
|
|
||||||
|
|
||||||
- (void) _appendNamespaces: (NSMutableArray *) folders
|
- (void) _appendNamespaces: (NSMutableArray *) folders
|
||||||
{
|
{
|
||||||
NSDictionary *namespaceDict;
|
NSDictionary *namespaceDict;
|
||||||
|
@ -342,30 +338,45 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
- (NSArray *) allFolderPaths
|
- (NSArray *) allFolderPaths: (SOGoMailListingMode) theListingMode
|
||||||
{
|
{
|
||||||
NSMutableArray *folderPaths, *namespaces;
|
NSMutableArray *folderPaths, *namespaces;
|
||||||
NSArray *folders, *mainFolders;
|
NSArray *folders, *mainFolders;
|
||||||
SOGoUserDefaults *ud;
|
|
||||||
NSString *namespace;
|
NSString *namespace;
|
||||||
|
|
||||||
BOOL subscribedOnly;
|
BOOL subscribedOnly;
|
||||||
int count, max;
|
int count, max;
|
||||||
|
|
||||||
ud = [[context activeUser] userDefaults];
|
if (theListingMode == SOGoMailStandardListing)
|
||||||
subscribedOnly = [ud mailShowSubscribedFoldersOnly];
|
subscribedOnly = [[[context activeUser] userDefaults] mailShowSubscribedFoldersOnly];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subscribedOnly = NO;
|
||||||
|
DESTROY(subscribedFolders);
|
||||||
|
subscribedFolders = [[NSMutableDictionary alloc] init];
|
||||||
|
folders = [[self imap4Connection] allFoldersForURL: [self imap4URL]
|
||||||
|
onlySubscribedFolders: YES];
|
||||||
|
max = [folders count];
|
||||||
|
for (count = 0; count < max; count++)
|
||||||
|
{
|
||||||
|
[subscribedFolders setObject: [NSNull null]
|
||||||
|
forKey: [folders objectAtIndex: count]];
|
||||||
|
}
|
||||||
|
[[self imap4Connection] flushFolderHierarchyCache];
|
||||||
|
}
|
||||||
|
|
||||||
mainFolders = [[NSArray arrayWithObjects:
|
mainFolders = [[NSArray arrayWithObjects:
|
||||||
[self inboxFolderNameInContext: context],
|
[self inboxFolderNameInContext: context],
|
||||||
[self draftsFolderNameInContext: context],
|
[self draftsFolderNameInContext: context],
|
||||||
[self sentFolderNameInContext: context],
|
[self sentFolderNameInContext: context],
|
||||||
[self trashFolderNameInContext: context],
|
[self trashFolderNameInContext: context],
|
||||||
[self junkFolderNameInContext: context],
|
[self junkFolderNameInContext: context],
|
||||||
nil] stringsWithFormat: @"/%@"];
|
nil] stringsWithFormat: @"/%@"];
|
||||||
folders = [[self imap4Connection] allFoldersForURL: [self imap4URL]
|
folders = [[self imap4Connection] allFoldersForURL: [self imap4URL]
|
||||||
onlySubscribedFolders: subscribedOnly];
|
onlySubscribedFolders: subscribedOnly];
|
||||||
folderPaths = [folders mutableCopy];
|
folderPaths = [folders mutableCopy];
|
||||||
[folderPaths autorelease];
|
[folderPaths autorelease];
|
||||||
|
|
||||||
[folderPaths removeObjectsInArray: mainFolders];
|
[folderPaths removeObjectsInArray: mainFolders];
|
||||||
namespaces = [NSMutableArray arrayWithCapacity: 10];
|
namespaces = [NSMutableArray arrayWithCapacity: 10];
|
||||||
[self _appendNamespaces: namespaces];
|
[self _appendNamespaces: namespaces];
|
||||||
|
@ -441,6 +452,9 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
return folderType;
|
return folderType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
- (NSMutableDictionary *) _insertFolder: (NSString *) folderPath
|
- (NSMutableDictionary *) _insertFolder: (NSString *) folderPath
|
||||||
foldersList: (NSMutableArray *) theFolders
|
foldersList: (NSMutableArray *) theFolders
|
||||||
{
|
{
|
||||||
|
@ -449,8 +463,9 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
NSMutableDictionary *currentFolder, *parentFolder, *folder;
|
NSMutableDictionary *currentFolder, *parentFolder, *folder;
|
||||||
NSString *currentFolderName, *currentPath, *fullName, *folderType;
|
NSString *currentFolderName, *currentPath, *fullName, *folderType;
|
||||||
SOGoUserManager *userManager;
|
SOGoUserManager *userManager;
|
||||||
|
|
||||||
|
BOOL last, isOtherUsersFolder, parentIsOtherUsersFolder, isSubscribed;
|
||||||
int i, j, count;
|
int i, j, count;
|
||||||
BOOL last, isOtherUsersFolder, parentIsOtherUsersFolder;
|
|
||||||
|
|
||||||
parentFolder = nil;
|
parentFolder = nil;
|
||||||
parentIsOtherUsersFolder = NO;
|
parentIsOtherUsersFolder = NO;
|
||||||
|
@ -469,13 +484,9 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
// Search for the current path in the children of the parent folder.
|
// Search for the current path in the children of the parent folder.
|
||||||
// For the first iteration, take the parent folder passed as argument.
|
// For the first iteration, take the parent folder passed as argument.
|
||||||
if (parentFolder)
|
if (parentFolder)
|
||||||
{
|
folders = [parentFolder objectForKey: @"children"];
|
||||||
folders = [parentFolder objectForKey: @"children"];
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
folders = theFolders;
|
||||||
folders = theFolders;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (j = 0; j < [folders count]; j++)
|
for (j = 0; j < [folders count]; j++)
|
||||||
{
|
{
|
||||||
|
@ -485,10 +496,9 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
folder = currentFolder;
|
folder = currentFolder;
|
||||||
// Make sure all branches are ready to receive children
|
// Make sure all branches are ready to receive children
|
||||||
if (!last && ![folder objectForKey: @"children"])
|
if (!last && ![folder objectForKey: @"children"])
|
||||||
{
|
|
||||||
[folder setObject: [NSMutableArray array] forKey: @"children"];
|
[folder setObject: [NSMutableArray array] forKey: @"children"];
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,18 +506,13 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
currentFolderName = [[pathComponents objectAtIndex: i] stringByDecodingImap4FolderName];
|
currentFolderName = [[pathComponents objectAtIndex: i] stringByDecodingImap4FolderName];
|
||||||
if (otherUsersFolderName
|
if (otherUsersFolderName
|
||||||
&& [currentFolderName caseInsensitiveCompare: otherUsersFolderName] == NSOrderedSame)
|
&& [currentFolderName caseInsensitiveCompare: otherUsersFolderName] == NSOrderedSame)
|
||||||
{
|
isOtherUsersFolder = YES;
|
||||||
isOtherUsersFolder = YES;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
isOtherUsersFolder = NO;
|
||||||
isOtherUsersFolder = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (folder == nil)
|
if (folder == nil)
|
||||||
{
|
{
|
||||||
// Folder was not found; create it and add it to the folders list
|
// Folder was not found; create it and add it to the folders list
|
||||||
|
|
||||||
if (parentIsOtherUsersFolder)
|
if (parentIsOtherUsersFolder)
|
||||||
{
|
{
|
||||||
// Parent folder is the "Other users" folder; translate the user's mailbox name
|
// Parent folder is the "Other users" folder; translate the user's mailbox name
|
||||||
|
@ -519,14 +524,10 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
currentFolderName = fullName;
|
currentFolderName = fullName;
|
||||||
}
|
}
|
||||||
else if (isOtherUsersFolder)
|
else if (isOtherUsersFolder)
|
||||||
{
|
currentFolderName = [self labelForKey: @"OtherUsersFolderName"];
|
||||||
currentFolderName = [self labelForKey: @"OtherUsersFolderName"];
|
|
||||||
}
|
|
||||||
else if (sharedFoldersName
|
else if (sharedFoldersName
|
||||||
&& [currentFolderName caseInsensitiveCompare: sharedFoldersName] == NSOrderedSame)
|
&& [currentFolderName caseInsensitiveCompare: sharedFoldersName] == NSOrderedSame)
|
||||||
{
|
currentFolderName = [self labelForKey: @"SharedFoldersName"];
|
||||||
currentFolderName = [self labelForKey: @"SharedFoldersName"];
|
|
||||||
}
|
|
||||||
|
|
||||||
flags = [NSMutableArray array];;
|
flags = [NSMutableArray array];;
|
||||||
|
|
||||||
|
@ -536,13 +537,19 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
else
|
else
|
||||||
folderType = @"additional";
|
folderType = @"additional";
|
||||||
|
|
||||||
|
if ([subscribedFolders objectForKey: folderPath])
|
||||||
|
isSubscribed = YES;
|
||||||
|
else
|
||||||
|
isSubscribed = NO;
|
||||||
|
|
||||||
folder = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
folder = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||||
currentPath, @"path",
|
currentPath, @"path",
|
||||||
folderType, @"type",
|
folderType, @"type",
|
||||||
currentFolderName, @"name",
|
currentFolderName, @"name",
|
||||||
[NSMutableArray array], @"children",
|
[NSMutableArray array], @"children",
|
||||||
flags, @"flags",
|
flags, @"flags",
|
||||||
nil];
|
[NSNumber numberWithBool: isSubscribed], @"subscribed",
|
||||||
|
nil];
|
||||||
// Either add this new folder to its parent or the list of root folders
|
// Either add this new folder to its parent or the list of root folders
|
||||||
[folders addObject: folder];
|
[folders addObject: folder];
|
||||||
}
|
}
|
||||||
|
@ -557,7 +564,7 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
//
|
//
|
||||||
// Return a tree representation of the mailboxes
|
// Return a tree representation of the mailboxes
|
||||||
//
|
//
|
||||||
- (NSArray *) allFoldersMetadata
|
- (NSArray *) allFoldersMetadata: (SOGoMailListingMode) theListingMode
|
||||||
{
|
{
|
||||||
NSString *currentFolder;
|
NSString *currentFolder;
|
||||||
NSMutableArray *folders;
|
NSMutableArray *folders;
|
||||||
|
@ -565,7 +572,7 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
NSAutoreleasePool *pool;
|
NSAutoreleasePool *pool;
|
||||||
NSArray *allFolderPaths;
|
NSArray *allFolderPaths;
|
||||||
|
|
||||||
allFolderPaths = [self allFolderPaths];
|
allFolderPaths = [self allFolderPaths: theListingMode];
|
||||||
rawFolders = [allFolderPaths objectEnumerator];
|
rawFolders = [allFolderPaths objectEnumerator];
|
||||||
folders = [NSMutableArray array];
|
folders = [NSMutableArray array];
|
||||||
|
|
||||||
|
@ -587,8 +594,6 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
return folders;
|
return folders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* IMAP4 */
|
|
||||||
- (NSDictionary *) _mailAccount
|
- (NSDictionary *) _mailAccount
|
||||||
{
|
{
|
||||||
NSDictionary *mailAccount;
|
NSDictionary *mailAccount;
|
||||||
|
@ -761,7 +766,7 @@ static NSString *inboxFolderName = @"INBOX";
|
||||||
[self trashFolderNameInContext: context],
|
[self trashFolderNameInContext: context],
|
||||||
nil] stringsWithFormat: @"/%@"];
|
nil] stringsWithFormat: @"/%@"];
|
||||||
else
|
else
|
||||||
folderList = [self allFolderPaths];
|
folderList = [self allFolderPaths: SOGoMailStandardListing];
|
||||||
|
|
||||||
folders = [NSMutableDictionary dictionary];
|
folders = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
|
|
|
@ -227,7 +227,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||||
|
|
||||||
prefix = [self absoluteImap4Name];
|
prefix = [self absoluteImap4Name];
|
||||||
|
|
||||||
result = [[self mailAccountFolder] allFolderPaths];
|
result = [[self mailAccountFolder] allFolderPaths: SOGoMailStandardListing];
|
||||||
folderNames = [result objectEnumerator];
|
folderNames = [result objectEnumerator];
|
||||||
while ((currentFolderName = [folderNames nextObject]))
|
while ((currentFolderName = [folderNames nextObject]))
|
||||||
if ([currentFolderName hasPrefix: prefix])
|
if ([currentFolderName hasPrefix: prefix])
|
||||||
|
|
|
@ -361,4 +361,7 @@
|
||||||
"Folder compacted" = "Folder compacted";
|
"Folder compacted" = "Folder compacted";
|
||||||
|
|
||||||
/* Aria label for scope of search on messages */
|
/* Aria label for scope of search on messages */
|
||||||
"Search scope" = "Search scope";
|
"Search scope" = "Search scope";
|
||||||
|
|
||||||
|
/* Subscriptions Dialog */
|
||||||
|
"Manage Subscriptions" = "Manage Subscriptions";
|
|
@ -23,10 +23,11 @@ MailerUI_OBJC_FILES += \
|
||||||
UIxMailPopupView.m \
|
UIxMailPopupView.m \
|
||||||
UIxMailMoveToPopUp.m \
|
UIxMailMoveToPopUp.m \
|
||||||
UIxMailFilterPanel.m \
|
UIxMailFilterPanel.m \
|
||||||
UIxMailSearch.m \
|
UIxMailSearch.m \
|
||||||
\
|
\
|
||||||
UIxMailAccountActions.m \
|
UIxMailAccountActions.m \
|
||||||
UIxMailFolderActions.m \
|
UIxMailFolderActions.m \
|
||||||
|
UIxMailFolderSubscriptions.m \
|
||||||
UIxMailActions.m \
|
UIxMailActions.m \
|
||||||
UIxMailEditor.m \
|
UIxMailEditor.m \
|
||||||
UIxMailToSelection.m \
|
UIxMailToSelection.m \
|
||||||
|
|
|
@ -46,14 +46,33 @@
|
||||||
|
|
||||||
co = [self clientObject];
|
co = [self clientObject];
|
||||||
|
|
||||||
folders = [co allFoldersMetadata];
|
folders = [co allFoldersMetadata: SOGoMailStandardListing];
|
||||||
|
|
||||||
data = [NSDictionary dictionaryWithObjectsAndKeys:
|
data = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
folders, @"mailboxes",
|
folders, @"mailboxes",
|
||||||
[co getInboxQuota], @"quotas",
|
[co getInboxQuota], @"quotas",
|
||||||
nil];
|
nil];
|
||||||
|
|
||||||
return [self responseWithStatus: 200 andJSONRepresentation: data];
|
return [self responseWithStatus: 200
|
||||||
|
andJSONRepresentation: data];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (WOResponse *) listAllMailboxesAction
|
||||||
|
{
|
||||||
|
SOGoMailAccount *co;
|
||||||
|
NSArray *folders;
|
||||||
|
NSDictionary *data;
|
||||||
|
|
||||||
|
co = [self clientObject];
|
||||||
|
|
||||||
|
folders = [co allFoldersMetadata: SOGoMailSubscriptionsManagementListing];
|
||||||
|
|
||||||
|
data = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
folders, @"mailboxes",
|
||||||
|
nil];
|
||||||
|
|
||||||
|
return [self responseWithStatus: 200
|
||||||
|
andJSONRepresentation: data];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compose */
|
/* compose */
|
||||||
|
|
|
@ -743,42 +743,62 @@
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
#warning here should be done what should be done: IMAP subscription
|
// - (WOResponse *) _subscriptionStubAction
|
||||||
- (WOResponse *) _subscriptionStubAction
|
// {
|
||||||
|
// NSString *mailInvitationParam, *mailInvitationURL;
|
||||||
|
// WOResponse *response;
|
||||||
|
// SOGoMailFolder *clientObject;
|
||||||
|
|
||||||
|
// mailInvitationParam
|
||||||
|
// = [[context request] formValueForKey: @"mail-invitation"];
|
||||||
|
// if ([mailInvitationParam boolValue])
|
||||||
|
// {
|
||||||
|
// clientObject = [self clientObject];
|
||||||
|
// mailInvitationURL
|
||||||
|
// = [[clientObject soURLToBaseContainerForCurrentUser]
|
||||||
|
// absoluteString];
|
||||||
|
// response = [self responseWithStatus: 302];
|
||||||
|
// [response setHeader: mailInvitationURL
|
||||||
|
// forKey: @"location"];
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// response = [self responseWithStatus: 500];
|
||||||
|
// [response appendContentString: @"How did you end up here?"];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return response;
|
||||||
|
// }
|
||||||
|
|
||||||
|
- (WOResponse *) _subscribeOrUnsubscribeAction: (BOOL) subscribing
|
||||||
{
|
{
|
||||||
NSString *mailInvitationParam, *mailInvitationURL;
|
NGImap4Client *client;
|
||||||
WOResponse *response;
|
WOResponse *response;
|
||||||
SOGoMailFolder *clientObject;
|
SOGoMailFolder *co;
|
||||||
|
NSDictionary *d;
|
||||||
|
|
||||||
mailInvitationParam
|
co = [self clientObject];
|
||||||
= [[context request] formValueForKey: @"mail-invitation"];
|
client = [[co imap4Connection] client];
|
||||||
if ([mailInvitationParam boolValue])
|
|
||||||
{
|
if (subscribing)
|
||||||
clientObject = [self clientObject];
|
d = [client subscribe: [[co imap4URL] path]];
|
||||||
mailInvitationURL
|
|
||||||
= [[clientObject soURLToBaseContainerForCurrentUser]
|
|
||||||
absoluteString];
|
|
||||||
response = [self responseWithStatus: 302];
|
|
||||||
[response setHeader: mailInvitationURL
|
|
||||||
forKey: @"location"];
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
d = [client unsubscribe: [[co imap4URL] path]];
|
||||||
response = [self responseWithStatus: 500];
|
|
||||||
[response appendContentString: @"How did you end up here?"];
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
if ([[[[d objectForKey: @"RawResponse"] objectForKey: @"ResponseResult"] objectForKey: @"result"] isEqualToString: @"ok"])
|
||||||
|
return [self responseWith204];
|
||||||
|
|
||||||
|
return [self responseWithStatus: 200];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (WOResponse *) subscribeAction
|
- (WOResponse *) subscribeAction
|
||||||
{
|
{
|
||||||
return [self _subscriptionStubAction];
|
return [self _subscribeOrUnsubscribeAction: YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (WOResponse *) unsubscribeAction
|
- (WOResponse *) unsubscribeAction
|
||||||
{
|
{
|
||||||
return [self _subscriptionStubAction];
|
return [self _subscribeOrUnsubscribeAction: NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (WOResponse *) addOrRemoveLabelAction
|
- (WOResponse *) addOrRemoveLabelAction
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* UIxMailFolderSubscriptions.h - this file is part of SOGo
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Inverse inc.
|
||||||
|
*
|
||||||
|
* This file is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This file is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <SOGoUI/UIxComponent.h>
|
||||||
|
|
||||||
|
@interface UIxMailFolderSubscriptions : UIxComponent
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,42 @@
|
||||||
|
/* UIxMailFolderSubscriptions.m - this file is part of SOGo
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Inverse inc.
|
||||||
|
*
|
||||||
|
* This file is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This file is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <NGObjWeb/WORequest.h>
|
||||||
|
|
||||||
|
#import "UIxMailFolderSubscriptions.h"
|
||||||
|
|
||||||
|
@implementation UIxMailFolderSubscriptions
|
||||||
|
|
||||||
|
- (id) init
|
||||||
|
{
|
||||||
|
if ((self = [super init]))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -400,6 +400,15 @@
|
||||||
actionClass = "UIxMailAccountActions";
|
actionClass = "UIxMailAccountActions";
|
||||||
actionName = "listMailboxes";
|
actionName = "listMailboxes";
|
||||||
};
|
};
|
||||||
|
viewAll = {
|
||||||
|
protectedBy = "View";
|
||||||
|
actionClass = "UIxMailAccountActions";
|
||||||
|
actionName = "listAllMailboxes";
|
||||||
|
};
|
||||||
|
subscribe = {
|
||||||
|
protectedBy = "Access Contents Information";
|
||||||
|
pageName = "UIxMailFolderSubscriptions";
|
||||||
|
};
|
||||||
createFolder = {
|
createFolder = {
|
||||||
protectedBy = "View";
|
protectedBy = "View";
|
||||||
actionClass = "UIxMailFolderActions";
|
actionClass = "UIxMailFolderActions";
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?xml version="1.0" standalone="yes"?>
|
||||||
|
<!DOCTYPE container>
|
||||||
|
<container
|
||||||
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:var="http://www.skyrix.com/od/binding"
|
||||||
|
xmlns:const="http://www.skyrix.com/od/constant"
|
||||||
|
xmlns:label="OGo:label"
|
||||||
|
>
|
||||||
|
<md-dialog flex="50" flex-sm="80" flex-xs="100">
|
||||||
|
|
||||||
|
<md-toolbar>
|
||||||
|
<div class="md-toolbar-tools">
|
||||||
|
<md-icon class="material-icons sg-icon-toolbar-bg">folder</md-icon>
|
||||||
|
<div class="pseudo-input-container md-flex">
|
||||||
|
<label class="pseudo-input-label"><var:string label:value="Manage Subscriptions"/></label>
|
||||||
|
<div class="sg-md-title">{{subscriptions.account.name}}</div>
|
||||||
|
</div>
|
||||||
|
<md-button class="md-icon-button" ng-click="subscriptions.close()">
|
||||||
|
<md-icon aria-label="Close dialog">close</md-icon>
|
||||||
|
</md-button>
|
||||||
|
</div>
|
||||||
|
</md-toolbar>
|
||||||
|
|
||||||
|
<md-dialog-content class="md-dialog-content" layout="column">
|
||||||
|
<md-list>
|
||||||
|
<md-list-item ng-repeat="folder in subscriptions.account.$flattenMailboxes({all: true })"
|
||||||
|
md-item-size="48"
|
||||||
|
ng-hide="subscriptions.app.metadataForFolder(folder).special">
|
||||||
|
<div ng-class="'sg-child-level-' + folder.level">
|
||||||
|
<md-icon>{{subscriptions.app.metadataForFolder(folder).icon}}</md-icon>
|
||||||
|
</div>
|
||||||
|
<p class="sg-item-name">
|
||||||
|
{{subscriptions.app.metadataForFolder(folder).name}}
|
||||||
|
</p>
|
||||||
|
<md-checkbox class="md-secondary"
|
||||||
|
ng-model="folder.subscribed"
|
||||||
|
ng-click="folder.$toggleSubscribe()"
|
||||||
|
ng-true-value="1"
|
||||||
|
ng-false-value="0">
|
||||||
|
</md-checkbox>
|
||||||
|
</md-list-item>
|
||||||
|
</md-list>
|
||||||
|
</md-dialog-content>
|
||||||
|
|
||||||
|
<md-dialog-actions>
|
||||||
|
<md-button type="button" ng-click="subscriptions.close()"><var:string label:value="Close"/></md-button>
|
||||||
|
</md-dialog-actions>
|
||||||
|
|
||||||
|
</md-dialog>
|
||||||
|
</container>
|
|
@ -40,21 +40,35 @@
|
||||||
<md-list>
|
<md-list>
|
||||||
<md-list-item ng-click="app.toggleAccountState(account)">
|
<md-list-item ng-click="app.toggleAccountState(account)">
|
||||||
<div class="sg-no-wrap">{{account.name}}</div>
|
<div class="sg-no-wrap">{{account.name}}</div>
|
||||||
<div class="md-flex"><!-- spacer --></div>
|
<md-menu class="md-secondary">
|
||||||
<md-button class="md-icon-button md-secondary"
|
<md-icon label:aria-label="Options"
|
||||||
ng-show="account.id == 0"
|
ng-click="$mdOpenMenu($event)"
|
||||||
label:aria-label="Delegation..."
|
md-menu-origin="md-menu-origin">more_vert</md-icon>
|
||||||
ng-click="app.delegate(account)">
|
<md-menu-content width="3">
|
||||||
<md-tooltip md-delay="300"><var:string label:value="Delegation..."/></md-tooltip>
|
<md-menu-item ng-show="account.id == 0">
|
||||||
<md-icon>people</md-icon>
|
<md-button
|
||||||
</md-button>
|
label:aria-label="Delegation..."
|
||||||
<md-button class="md-icon-button md-secondary"
|
ng-click="app.delegate(account)">
|
||||||
label:aria-label="New Folder..."
|
<var:string label:value="Delegation..."/>
|
||||||
ng-click="app.newFolder(account)">
|
</md-button>
|
||||||
<md-tooltip md-delay="300"><var:string label:value="New Folder..."/></md-tooltip>
|
</md-menu-item>
|
||||||
<md-icon>add_circle_outline</md-icon>
|
<md-menu-item ng-show="app.showSubscribedOnly == 1">
|
||||||
</md-button>
|
<md-button
|
||||||
</md-list-item>
|
label:aria-label="Subscribe..."
|
||||||
|
ng-click="app.subscribe(account)">
|
||||||
|
<var:string label:value="Subscribe..."/>
|
||||||
|
</md-button>
|
||||||
|
</md-menu-item>
|
||||||
|
<md-menu-item>
|
||||||
|
<md-button
|
||||||
|
label:aria-label="New Folder..."
|
||||||
|
ng-click="app.newFolder(account)">
|
||||||
|
<var:string label:value="New Folder..."/>
|
||||||
|
</md-button>
|
||||||
|
</md-menu-item>
|
||||||
|
</md-menu-content>
|
||||||
|
</md-menu>
|
||||||
|
</md-list-item>
|
||||||
</md-list>
|
</md-list>
|
||||||
<div class="sg-quota ng-hide" ng-show="account.$quota">
|
<div class="sg-quota ng-hide" ng-show="account.$quota">
|
||||||
<md-progress-linear md-mode="determinate"
|
<md-progress-linear md-mode="determinate"
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {object} futureAccountData
|
* @param {object} futureAccountData
|
||||||
*/
|
*/
|
||||||
function Account(futureAccountData) {
|
function Account(futureAccountData, fetchAll) {
|
||||||
// Data is immediately available
|
// Data is immediately available
|
||||||
if (typeof futureAccountData.then !== 'function') {
|
if (typeof futureAccountData.then !== 'function') {
|
||||||
angular.extend(this, futureAccountData);
|
angular.extend(this, futureAccountData);
|
||||||
|
@ -24,6 +24,14 @@
|
||||||
// The promise will be unwrapped first
|
// The promise will be unwrapped first
|
||||||
//this.$unwrap(futureAccountData);
|
//this.$unwrap(futureAccountData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.fetchAll = false;
|
||||||
|
|
||||||
|
// Check if we're displaying the IMAP subscription management dialog
|
||||||
|
if (angular.isDefined(fetchAll) && fetchAll) {
|
||||||
|
this.fetchAll = true;
|
||||||
|
this.$getMailboxes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -84,7 +84,10 @@
|
||||||
Mailbox.$find = function(account) {
|
Mailbox.$find = function(account) {
|
||||||
var path, futureMailboxData;
|
var path, futureMailboxData;
|
||||||
|
|
||||||
futureMailboxData = this.$$resource.fetch(account.id.toString(), 'view');
|
if (account.fetchAll)
|
||||||
|
futureMailboxData = this.$$resource.fetch(account.id.toString(), 'viewAll');
|
||||||
|
else
|
||||||
|
futureMailboxData = this.$$resource.fetch(account.id.toString(), 'view');
|
||||||
|
|
||||||
return Mailbox.$unwrapCollection(account, futureMailboxData); // a collection of mailboxes
|
return Mailbox.$unwrapCollection(account, futureMailboxData); // a collection of mailboxes
|
||||||
};
|
};
|
||||||
|
@ -890,4 +893,15 @@
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function $toggleSubscribe
|
||||||
|
* @memberof Mailbox.prototype
|
||||||
|
* @desc Subscribe or unsubscribe to a mailbox
|
||||||
|
*/
|
||||||
|
Mailbox.prototype.$toggleSubscribe = function() {
|
||||||
|
if (this.subscribed)
|
||||||
|
return Mailbox.$$resource.post(this.id, 'subscribe');
|
||||||
|
|
||||||
|
return Mailbox.$$resource.post(this.id, 'unsubscribe');
|
||||||
|
};
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
vm.service = Mailbox;
|
vm.service = Mailbox;
|
||||||
vm.accounts = stateAccounts;
|
vm.accounts = stateAccounts;
|
||||||
vm.toggleAccountState = toggleAccountState;
|
vm.toggleAccountState = toggleAccountState;
|
||||||
|
vm.subscribe = subscribe;
|
||||||
vm.newFolder = newFolder;
|
vm.newFolder = newFolder;
|
||||||
vm.delegate = delegate;
|
vm.delegate = delegate;
|
||||||
vm.editFolder = editFolder;
|
vm.editFolder = editFolder;
|
||||||
|
@ -54,6 +55,10 @@
|
||||||
params: []
|
params: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Preferences.ready().then(function() {
|
||||||
|
vm.showSubscribedOnly = Preferences.defaults.SOGoMailShowSubscribedFoldersOnly;
|
||||||
|
});
|
||||||
|
|
||||||
vm.refreshUnseenCount();
|
vm.refreshUnseenCount();
|
||||||
|
|
||||||
function showAdvancedSearch(path) {
|
function showAdvancedSearch(path) {
|
||||||
|
@ -146,6 +151,40 @@
|
||||||
}, 150);
|
}, 150);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function subscribe(account) {
|
||||||
|
$mdDialog.show({
|
||||||
|
templateUrl: account.id + '/subscribe',
|
||||||
|
controller: SubscriptionsDialogController,
|
||||||
|
controllerAs: 'subscriptions',
|
||||||
|
clickOutsideToClose: true,
|
||||||
|
escapeToClose: true,
|
||||||
|
locals: {
|
||||||
|
srcApp: vm,
|
||||||
|
srcAccount: account
|
||||||
|
}
|
||||||
|
}).finally(function() {
|
||||||
|
account.$getMailboxes({reload: true});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngInject
|
||||||
|
*/
|
||||||
|
SubscriptionsDialogController.$inject = ['$scope', '$mdDialog', 'srcApp', 'srcAccount'];
|
||||||
|
function SubscriptionsDialogController($scope, $mdDialog, srcApp, srcAccount) {
|
||||||
|
var vm = this;
|
||||||
|
|
||||||
|
vm.app = srcApp;
|
||||||
|
vm.account = new Account({id: srcAccount.id,
|
||||||
|
name: srcAccount.name},
|
||||||
|
true);
|
||||||
|
vm.close = close;
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
$mdDialog.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function newFolder(parentFolder) {
|
function newFolder(parentFolder) {
|
||||||
Dialog.prompt(l('New folder'),
|
Dialog.prompt(l('New folder'),
|
||||||
l('Enter the new name of your folder :'))
|
l('Enter the new name of your folder :'))
|
||||||
|
@ -305,19 +344,19 @@
|
||||||
|
|
||||||
function metadataForFolder(folder) {
|
function metadataForFolder(folder) {
|
||||||
if (folder.type == 'inbox')
|
if (folder.type == 'inbox')
|
||||||
return {name: folder.name, icon:'inbox'};
|
return {name: folder.name, icon:'inbox', special: true};
|
||||||
else if (folder.type == 'draft')
|
else if (folder.type == 'draft')
|
||||||
return {name: l('DraftsFolderName'), icon: 'drafts'};
|
return {name: l('DraftsFolderName'), icon: 'drafts', special: true};
|
||||||
else if (folder.type == 'sent')
|
else if (folder.type == 'sent')
|
||||||
return {name: l('SentFolderName'), icon: 'send'};
|
return {name: l('SentFolderName'), icon: 'send', special: true};
|
||||||
else if (folder.type == 'trash')
|
else if (folder.type == 'trash')
|
||||||
return {name: l('TrashFolderName'), icon: 'delete'};
|
return {name: l('TrashFolderName'), icon: 'delete', special: true};
|
||||||
else if (folder.type == 'junk')
|
else if (folder.type == 'junk')
|
||||||
return {name: l('JunkFolderName'), icon: 'thumb_down'};
|
return {name: l('JunkFolderName'), icon: 'thumb_down', special: true};
|
||||||
else if (folder.type == 'additional')
|
else if (folder.type == 'additional')
|
||||||
return {name: folder.name, icon: 'folder_shared'};
|
return {name: folder.name, icon: 'folder_shared', special: true};
|
||||||
|
|
||||||
return {name: folder.name, icon: 'folder_open'};
|
return {name: folder.name, icon: 'folder_open', special: false};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFolderAs(folder, type) {
|
function setFolderAs(folder, type) {
|
||||||
|
|
Loading…
Reference in New Issue