Compare commits
28
Commits
SOGo-5.11.2
...
feat-6025
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe6836084e | ||
|
|
5030922a7c | ||
|
|
066a9bbb83 | ||
|
|
fcaaebcc66 | ||
|
|
c7b0133000 | ||
|
|
2f9c2cf4da | ||
|
|
57db6b5f91 | ||
|
|
f65ab9b43a | ||
|
|
2258d5cd60 | ||
|
|
ea427ea41a | ||
|
|
ce86d14826 | ||
|
|
7f7c743976 | ||
|
|
6f86506b28 | ||
|
|
e44bc1fc91 | ||
|
|
c90e2b0501 | ||
|
|
cd0324dd49 | ||
|
|
581b2c1912 | ||
|
|
9a9d968756 | ||
|
|
fe003eeef5 | ||
|
|
a09f4d8f49 | ||
|
|
617c1bbc64 | ||
|
|
5bab72726a | ||
|
|
01863987dd | ||
|
|
f1257088f2 | ||
|
|
1c611a0a4a | ||
|
|
f2ba6870d5 | ||
|
|
253d14cfce | ||
|
|
b3c77a0e00 |
No files matched your search
@@ -815,6 +815,8 @@ Obiously, if your users can connect without specifying a domain, let this parame
|
||||
|S |SOGoDomainAllowed
|
||||
|Parameter used to define which domains SOGo should allowed during a connection request. This parameter is an array of strings.
|
||||
|
||||
|S |SOGoURLCreateAccount
|
||||
|Add a link below the login form and set the link using the value of this setting.
|
||||
|
||||
|S |SOGoPasswordRecoveryEnabled
|
||||
|Boolean enable password recovery with secret question or secondary e-mail. Default value is `NO`.
|
||||
@@ -1676,6 +1678,9 @@ URL could be set to something like:
|
||||
|
||||
See the "EMail reminders" section in this document for more information.
|
||||
|
||||
|S |SOGoEnableMailCleaning
|
||||
|Parameter used to enable cleaning folders and mailbox (remove mail older than X days). Default value is `NO`.
|
||||
|
||||
|S |SOGoDisableOrganizerEventCheck
|
||||
|Parameter used to disable organizer's calendar event check
|
||||
|
||||
@@ -3949,7 +3954,7 @@ _Defaults_ stores all parameters that can be found in Preferences panel. So it g
|
||||
autoreply to many others options.
|
||||
|
||||
|
||||
user-preferences get|set|unset defaults|settings user key [value|-f filename] [-p credentialFile]
|
||||
user-preferences get|set|unset defaults|settings user key [value|-f filename] [-p credentialFile [-F]]
|
||||
|
||||
* First argument is the action *get*, *set* or *unset*
|
||||
* Second argument is parameter type *settings* or *defaults*
|
||||
@@ -3957,7 +3962,8 @@ autoreply to many others options.
|
||||
* Fourth argument *key* is the name of the parameters where to make the action
|
||||
* If the action is *set*, you should provide either *value* as fifth argument or a file with the value inside with *-f* filename/path
|
||||
* If the action is *set* or *unset* and the *key* concerns a sieve script (filter, vacation, forward...), you
|
||||
should provide a credential file, a one-line file that contains "username:password" of an admin account of your imap/sieve server.
|
||||
should provide a credential file, a one-line file that contains "username:password" of an admin account of your imap/sieve server. If you
|
||||
want t oforce the sieve script activation add -F after.
|
||||
|
||||
As there is a lot of parameters, this documentation will not go into details for each one. To know what are
|
||||
the key names and their value you should got to your database in table defined by _SOGoProfileURL_ in your sogo.conf.
|
||||
@@ -3986,7 +3992,7 @@ sogo-tool user-preferences unset defaults user1 Forward -p /etc/sogo/cred
|
||||
|
||||
*set* action:
|
||||
----
|
||||
sogo-tool user-preferences set defaults user1 Forward '{"forwardAddress":["sogo-tests2@sogo.alinto"],"enabled":1,"keepCopy":0}' -p cred
|
||||
sogo-tool user-preferences set defaults user1 Forward '{"forwardAddress":["sogo-tests2@sogo.alinto"],"enabled":1,"keepCopy":0}' -p cred -F
|
||||
----
|
||||
or create a json file which contains _{"forwardAddress":["sogo-tests2@sogo.alinto"],"enabled":1,"keepCopy":0}_ then:
|
||||
----
|
||||
|
||||
@@ -464,7 +464,8 @@ lastPossibleRecurrenceStartDateUsingFirstInstanceCalendarDateRange: (NGCalendarD
|
||||
}
|
||||
}
|
||||
|
||||
if ([self hasRecurrenceDates])
|
||||
//If there are recurrence rules and we have no date yet, its means it's infinite and rdates shouldn't be count as last dates.
|
||||
if ([self hasRecurrenceDates] && !([self hasRecurrenceRules] && !date))
|
||||
{
|
||||
NSEnumerator *rDates;
|
||||
|
||||
|
||||
@@ -1130,28 +1130,26 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
delta = [masterEndDate timeIntervalSinceDate: [master startDate]];
|
||||
recurrenceIdRange = [NGCalendarDateRange calendarDateRangeWithStartDate: recurrenceId
|
||||
endDate: [recurrenceId dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds: delta]];
|
||||
if ([dateRange doesIntersectWithDateRange: recurrenceIdRange])
|
||||
recordIndex = [self _indexOfRecordMatchingDate: recurrenceId inArray: ma];
|
||||
if ([dateRange doesIntersectWithDateRange: recurrenceIdRange] && recordIndex == -1) {
|
||||
[self warnWithFormat:
|
||||
@"missing exception record for recurrence-id %@ (uid %@), ma = %@, dr = %@, rir = %@",
|
||||
recurrenceId, [component uid], ma, dateRange, recurrenceIdRange];
|
||||
}
|
||||
if ([dateRange doesIntersectWithDateRange: recurrenceIdRange] && recordIndex != -1)
|
||||
{
|
||||
// The recurrence exception intersects with the date range;
|
||||
// find the occurence and replace it with the new record
|
||||
recordIndex = [self _indexOfRecordMatchingDate: recurrenceId inArray: ma];
|
||||
if (recordIndex > -1)
|
||||
{
|
||||
if ([dateRange containsDate: [component startDate]] ||
|
||||
(endDate && [dateRange containsDate: endDate]))
|
||||
{
|
||||
// We must pass nil to :container here in order to avoid re-entrancy issues.
|
||||
newRecord = [self _fixupRecord: [component quickRecordFromContent: nil container: nil nameInContainer: nil]];
|
||||
[ma replaceObjectAtIndex: recordIndex withObject: newRecord];
|
||||
}
|
||||
else
|
||||
// The range doesn't cover the exception; remove it from the records
|
||||
[ma removeObjectAtIndex: recordIndex];
|
||||
}
|
||||
else
|
||||
[self errorWithFormat:
|
||||
@"missing exception record for recurrence-id %@ (uid %@)",
|
||||
recurrenceId, [component uid]];
|
||||
if ([dateRange containsDate: [component startDate]] ||
|
||||
(endDate && [dateRange containsDate: endDate]))
|
||||
{
|
||||
// We must pass nil to :container here in order to avoid re-entrancy issues.
|
||||
newRecord = [self _fixupRecord: [component quickRecordFromContent: nil container: nil nameInContainer: nil]];
|
||||
[ma replaceObjectAtIndex: recordIndex withObject: newRecord];
|
||||
}
|
||||
else
|
||||
// The range doesn't cover the exception; remove it from the records
|
||||
[ma removeObjectAtIndex: recordIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1859,7 +1859,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
// Retrieve this occurence ID.
|
||||
recurrenceId = [occurence recurrenceId];
|
||||
|
||||
if ([occurence userIsAttendee: ownerUser])
|
||||
if ([occurence userIsAttendee: ownerUser] && !activeUserIsOwner)
|
||||
{
|
||||
// The current user deletes the occurence; let the organizer know that
|
||||
// the user has declined this occurence.
|
||||
|
||||
@@ -291,6 +291,7 @@ static NSString *userAgent = nil;
|
||||
{
|
||||
[headers setObject: @"true" forKey: @"receipt"];
|
||||
[headers setObject: receipt forKey: @"Disposition-Notification-To"];
|
||||
[headers setObject: receipt forKey: @"Return-Receipt-To"];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -302,12 +303,14 @@ static NSString *userAgent = nil;
|
||||
if (pureSender)
|
||||
{
|
||||
[headers setObject: pureSender forKey: @"Disposition-Notification-To"];
|
||||
[headers setObject: pureSender forKey: @"Return-Receipt-To"];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[headers removeObjectForKey: @"receipt"];
|
||||
[headers removeObjectForKey: @"Disposition-Notification-To"];
|
||||
[headers removeObjectForKey: @"Return-Receipt-To"];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -990,7 +993,6 @@ static NSString *userAgent = nil;
|
||||
[self _fileAttachmentsFromPart: [m body] onlyImages: onlyImages];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -1019,7 +1021,7 @@ static NSString *userAgent = nil;
|
||||
|
||||
addresses = [NSMutableArray array];
|
||||
[self _addEMailsOfAddresses: [sourceEnvelope from] toArray: addresses];
|
||||
if ([addresses count])
|
||||
if ([addresses count] > 0)
|
||||
[info setObject: [addresses objectAtIndex: 0] forKey: @"from"];
|
||||
addresses = [NSMutableArray array];
|
||||
[self _addEMailsOfAddresses: [sourceEnvelope to] toArray: addresses];
|
||||
@@ -1035,15 +1037,17 @@ static NSString *userAgent = nil;
|
||||
addresses = [NSMutableArray array];
|
||||
[self _addEMailsOfAddresses: [sourceEnvelope replyTo] toArray: addresses];
|
||||
if ([addresses count] > 0)
|
||||
[info setObject: addresses forKey: @"replyTo"];
|
||||
[info setObject: [addresses objectAtIndex: 0] forKey: @"replyTo"];
|
||||
|
||||
h = [sourceMail mailHeaders];
|
||||
priority = [h objectForKey: @"x-priority"];
|
||||
if ([priority isNotEmpty] && [priority isKindOfClass: [NSString class]])
|
||||
[info setObject: (NSString*)priority forKey: @"X-Priority"];
|
||||
receipt = [h objectForKey: @"disposition-notification-to"];
|
||||
if ([receipt isNotEmpty] && [receipt isKindOfClass: [NSString class]])
|
||||
if ([receipt isNotEmpty] && [receipt isKindOfClass: [NSString class]]) {
|
||||
[info setObject: (NSString*)receipt forKey: @"Disposition-Notification-To"];
|
||||
[info setObject: (NSString*)receipt forKey: @"Return-Receipt-To"];
|
||||
}
|
||||
|
||||
ud = [[context activeUser] userDefaults];
|
||||
|
||||
@@ -1893,6 +1897,8 @@ static NSString *userAgent = nil;
|
||||
[map setObject: s forKey: @"X-Priority"];
|
||||
if ([(s = [headers objectForKey: @"Disposition-Notification-To"]) length] > 0)
|
||||
[map setObject: s forKey: @"Disposition-Notification-To"];
|
||||
if ([(s = [headers objectForKey: @"Return-Receipt-To"]) length] > 0)
|
||||
[map setObject: s forKey: @"Return-Receipt-To"];
|
||||
|
||||
[self _addHeaders: _headers toHeaderMap: map];
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ typedef enum {
|
||||
- (NSArray *) toManyRelationshipKeysWithNamespaces: (BOOL) withNSs;
|
||||
|
||||
- (NSArray *) allFolderPaths: (SOGoMailListingMode) theListingMode;
|
||||
- (NSArray *) allFolderPaths: (SOGoMailListingMode) theListingMode onlyRoot: (BOOL) onlyRoot;
|
||||
- (NSArray *) allFoldersMetadata: (SOGoMailListingMode) theListingMode;
|
||||
|
||||
- (NSDictionary *) imapFolderGUIDs;
|
||||
|
||||
@@ -378,14 +378,21 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
return folders;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (NSArray *) allFolderPaths: (SOGoMailListingMode) theListingMode
|
||||
- (NSArray *) allFolderPaths: (SOGoMailListingMode) theListingMode
|
||||
{
|
||||
NSMutableArray *folderPaths, *namespaces;
|
||||
return [self allFolderPaths: theListingMode onlyRoot: NO];
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (NSArray *) allFolderPaths: (SOGoMailListingMode) theListingMode onlyRoot: (BOOL) onlyRoot
|
||||
{
|
||||
NSMutableArray *folderPaths, *namespaces, *filteredFolders;
|
||||
NSArray *folders, *mainFolders;
|
||||
NSString *namespace;
|
||||
NSString *folder;
|
||||
NSUInteger slashCount;
|
||||
|
||||
BOOL subscribedOnly;
|
||||
int count, max;
|
||||
@@ -401,10 +408,10 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
onlySubscribedFolders: YES];
|
||||
max = [folders count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
[subscribedFolders setObject: [NSNull null]
|
||||
forKey: [folders objectAtIndex: count]];
|
||||
}
|
||||
{
|
||||
[subscribedFolders setObject: [NSNull null]
|
||||
forKey: [folders objectAtIndex: count]];
|
||||
}
|
||||
[[self imap4Connection] flushFolderHierarchyCache];
|
||||
}
|
||||
|
||||
@@ -418,6 +425,17 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
nil] stringsWithFormat: @"/%@"];
|
||||
folders = [[self imap4Connection] allFoldersForURL: [self imap4URL]
|
||||
onlySubscribedFolders: subscribedOnly];
|
||||
if (onlyRoot) {
|
||||
filteredFolders = [[NSMutableArray alloc] init];
|
||||
for (folder in folders) {
|
||||
slashCount = [[folder componentsSeparatedByString:@"/"] count] - 1;
|
||||
if (slashCount <= 1) {
|
||||
[filteredFolders addObject: folder];
|
||||
}
|
||||
}
|
||||
folders = [NSArray arrayWithArray: filteredFolders];
|
||||
[filteredFolders release];
|
||||
}
|
||||
folderPaths = [folders mutableCopy];
|
||||
[folderPaths autorelease];
|
||||
|
||||
|
||||
@@ -2306,7 +2306,7 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
||||
|
||||
- (NSArray *) membersForGroupWithUID: (NSString *) uid
|
||||
{
|
||||
NSMutableArray *dns, *uids;
|
||||
NSMutableArray *dns, *uids, *userLogins;
|
||||
NSString *dn, *login;
|
||||
SOGoUserManager *um;
|
||||
NSDictionary *d, *contactInfos;
|
||||
@@ -2327,6 +2327,7 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
||||
members = [NSMutableArray new];
|
||||
uids = [NSMutableArray array];
|
||||
dns = [NSMutableArray array];
|
||||
userLogins = [NSMutableArray array];
|
||||
|
||||
// We check if it's a static group
|
||||
// Fetch "members" - we get DNs
|
||||
@@ -2358,6 +2359,13 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
||||
pool = [NSAutoreleasePool new];
|
||||
dn = [dns objectAtIndex: i];
|
||||
login = [um getLoginForDN: [dn lowercaseString]];
|
||||
if([userLogins containsObject: login])
|
||||
{
|
||||
[pool release];
|
||||
continue; //user alrady fetch
|
||||
}
|
||||
if(login != nil)
|
||||
[userLogins addObject: login];
|
||||
user = [SOGoUser userWithLogin: login roles: nil];
|
||||
if (user)
|
||||
{
|
||||
@@ -2385,6 +2393,13 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
||||
{
|
||||
pool = [NSAutoreleasePool new];
|
||||
login = [uids objectAtIndex: i];
|
||||
if([userLogins containsObject: login])
|
||||
{
|
||||
[pool release];
|
||||
continue; //user alrady fetch
|
||||
}
|
||||
if(login != nil)
|
||||
[userLogins addObject: login];
|
||||
user = [SOGoUser userWithLogin: login roles: nil];
|
||||
if (user)
|
||||
{
|
||||
@@ -2456,4 +2471,4 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
||||
return rc;
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
@@ -65,7 +65,8 @@
|
||||
domain: &domain
|
||||
perr: &perr
|
||||
expire: &expire
|
||||
grace: &grace]
|
||||
grace: &grace
|
||||
additionalInfo: nil]
|
||||
&& perr == PolicyNoError);
|
||||
|
||||
if (!rc)
|
||||
|
||||
@@ -140,6 +140,10 @@ NSComparisonResult languageSort(id el1, id el2, void *context);
|
||||
- (BOOL)isURLEncryptionEnabled;
|
||||
- (NSString *)urlEncryptionPassphrase;
|
||||
|
||||
- (NSString *)urlCreateAccount;
|
||||
|
||||
- (BOOL)enableMailCleaning;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SOGOSYSTEMDEFAULTS_H */
|
||||
@@ -928,4 +928,14 @@ NSComparisonResult languageSort(id el1, id el2, void *context)
|
||||
return disableExport;
|
||||
}
|
||||
|
||||
- (NSString *)urlCreateAccount
|
||||
{
|
||||
return [self stringForKey: @"SOGoURLCreateAccount"];
|
||||
}
|
||||
|
||||
- (BOOL) enableMailCleaning
|
||||
{
|
||||
return [self boolForKey: @"SOGoEnableMailCleaning"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -502,6 +502,7 @@ static const NSString *kObfuscatedSecondaryEmailKey = @"obfuscatedSecondaryEmail
|
||||
perr: (SOGoPasswordPolicyError *) perr
|
||||
expire: (int *) expire
|
||||
grace: (int *) grace
|
||||
additionalInfo: (NSMutableDictionary **)_additionalInfo
|
||||
{
|
||||
NSObject <SOGoSource> *sogoSource;
|
||||
NSEnumerator *authIDs;
|
||||
@@ -520,8 +521,11 @@ static const NSString *kObfuscatedSecondaryEmailKey = @"obfuscatedSecondaryEmail
|
||||
perr: perr
|
||||
expire: expire
|
||||
grace: grace];
|
||||
if (_additionalInfo && *_additionalInfo && [sogoSource userPasswordPolicy] && [[sogoSource userPasswordPolicy] count] > 0) {
|
||||
[*_additionalInfo setObject:[sogoSource userPasswordPolicy] forKey:@"userPolicies"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (checkOK && *domain == nil)
|
||||
{
|
||||
SOGoSystemDefaults *sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
@@ -554,6 +558,7 @@ static const NSString *kObfuscatedSecondaryEmailKey = @"obfuscatedSecondaryEmail
|
||||
perr: (SOGoPasswordPolicyError *) _perr
|
||||
expire: (int *) _expire
|
||||
grace: (int *) _grace
|
||||
additionalInfo:(NSMutableDictionary **)_additionalInfo
|
||||
{
|
||||
return [self checkLogin: _login
|
||||
password: _pwd
|
||||
@@ -561,6 +566,7 @@ static const NSString *kObfuscatedSecondaryEmailKey = @"obfuscatedSecondaryEmail
|
||||
perr: _perr
|
||||
expire: _expire
|
||||
grace: _grace
|
||||
additionalInfo: _additionalInfo
|
||||
useCache: YES];
|
||||
}
|
||||
|
||||
@@ -573,6 +579,7 @@ static const NSString *kObfuscatedSecondaryEmailKey = @"obfuscatedSecondaryEmail
|
||||
perr: (SOGoPasswordPolicyError *) _perr
|
||||
expire: (int *) _expire
|
||||
grace: (int *) _grace
|
||||
additionalInfo: (NSMutableDictionary **)_additionalInfo
|
||||
useCache: (BOOL) useCache
|
||||
{
|
||||
NSString *dictPassword, *username, *jsonUser;
|
||||
@@ -726,7 +733,8 @@ static const NSString *kObfuscatedSecondaryEmailKey = @"obfuscatedSecondaryEmail
|
||||
domain: _domain
|
||||
perr: _perr
|
||||
expire: _expire
|
||||
grace: _grace])
|
||||
grace: _grace
|
||||
additionalInfo: _additionalInfo])
|
||||
{
|
||||
checkOK = YES;
|
||||
if (!currentUser)
|
||||
|
||||
@@ -37,20 +37,22 @@
|
||||
|
||||
+ (id) sharedSOGoWebAuthenticator;
|
||||
|
||||
- (BOOL) checkLogin: (NSString *) _login
|
||||
password: (NSString *) _pwd
|
||||
domain: (NSString **) _domain
|
||||
perr: (SOGoPasswordPolicyError *) _perr
|
||||
expire: (int *) _expire
|
||||
grace: (int *) _grace;
|
||||
- (BOOL)checkLogin:(NSString *)_login
|
||||
password:(NSString *)_pwd
|
||||
domain:(NSString **)_domain
|
||||
perr:(SOGoPasswordPolicyError *)_perr
|
||||
expire:(int *)_expire
|
||||
grace:(int *)_grace
|
||||
additionalInfo:(NSMutableDictionary **)_additionalInfo;
|
||||
|
||||
- (BOOL) checkLogin: (NSString *) _login
|
||||
password: (NSString *) _pwd
|
||||
domain: (NSString **) _domain
|
||||
perr: (SOGoPasswordPolicyError *) _perr
|
||||
expire: (int *) _expire
|
||||
grace: (int *) _grace
|
||||
useCache: (BOOL) useCache;
|
||||
- (BOOL)checkLogin:(NSString *)_login
|
||||
password:(NSString *)_pwd
|
||||
domain:(NSString **)_domain
|
||||
perr:(SOGoPasswordPolicyError *)_perr
|
||||
expire:(int *)_expire
|
||||
grace:(int *)_grace
|
||||
additionalInfo:(NSMutableDictionary **)_additionalInfo
|
||||
useCache:(BOOL)useCache;
|
||||
|
||||
- (WOCookie *) cookieWithUsername: (NSString *) username
|
||||
andPassword: (NSString *) password
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
domain: &domain
|
||||
perr: &perr
|
||||
expire: &expire
|
||||
grace: &grace];
|
||||
grace: &grace
|
||||
additionalInfo: nil];
|
||||
}
|
||||
|
||||
- (BOOL) checkLogin: (NSString *) _login
|
||||
@@ -111,6 +112,7 @@
|
||||
perr: (SOGoPasswordPolicyError *) _perr
|
||||
expire: (int *) _expire
|
||||
grace: (int *) _grace
|
||||
additionalInfo: (NSMutableDictionary **)_additionalInfo
|
||||
{
|
||||
return [self checkLogin: _login
|
||||
password: _pwd
|
||||
@@ -118,6 +120,7 @@
|
||||
perr: _perr
|
||||
expire: _expire
|
||||
grace: _grace
|
||||
additionalInfo: _additionalInfo
|
||||
useCache: YES];
|
||||
}
|
||||
|
||||
@@ -127,6 +130,7 @@
|
||||
perr: (SOGoPasswordPolicyError *) _perr
|
||||
expire: (int *) _expire
|
||||
grace: (int *) _grace
|
||||
additionalInfo: (NSMutableDictionary **)_additionalInfo
|
||||
useCache: (BOOL) _useCache
|
||||
{
|
||||
SOGoCASSession *session;
|
||||
@@ -164,6 +168,7 @@
|
||||
perr: _perr
|
||||
expire: _expire
|
||||
grace: _grace
|
||||
additionalInfo: _additionalInfo
|
||||
useCache: _useCache];
|
||||
|
||||
//[self logWithFormat: @"Checked login with ppolicy enabled: %d %d %d", *_perr, *_expire, *_grace];
|
||||
@@ -250,7 +255,8 @@
|
||||
domain: &domain
|
||||
perr: &perr
|
||||
expire: &expire
|
||||
grace: &grace])
|
||||
grace: &grace
|
||||
additionalInfo: nil])
|
||||
return nil;
|
||||
|
||||
if (domain && [login rangeOfString: @"@"].location == NSNotFound)
|
||||
|
||||
+77
-25
@@ -245,6 +245,20 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL) checkLogin: (NSString *) _login
|
||||
password: (NSString *) _pwd
|
||||
perr: (SOGoPasswordPolicyError *) _perr
|
||||
expire: (int *) _expire
|
||||
grace: (int *) _grace
|
||||
{
|
||||
return [self checkLogin: _login
|
||||
password: _pwd
|
||||
perr: _perr
|
||||
expire: _perr
|
||||
grace: _grace
|
||||
disablepasswordPolicyCheck: NO];
|
||||
}
|
||||
|
||||
//
|
||||
// SQL sources don't support right now all the password policy
|
||||
// stuff supported by OpenLDAP (and others). If we want to support
|
||||
@@ -256,6 +270,7 @@
|
||||
perr: (SOGoPasswordPolicyError *) _perr
|
||||
expire: (int *) _expire
|
||||
grace: (int *) _grace
|
||||
disablepasswordPolicyCheck: (BOOL) _disablepasswordPolicyCheck
|
||||
{
|
||||
EOAdaptorChannel *channel;
|
||||
EOQualifier *qualifier;
|
||||
@@ -335,10 +350,69 @@
|
||||
else
|
||||
[self errorWithFormat:@"failed to acquire channel for URL: %@",
|
||||
[_viewURL absoluteString]];
|
||||
|
||||
if (YES == rc && !_disablepasswordPolicyCheck) {
|
||||
[self checkPasswordPolicyWithPassword:_pwd perr: _perr];
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a given password against the configured user password policies.
|
||||
*
|
||||
* This method checks if the provided password complies with all defined
|
||||
* password policies for the user. Each policy is expected to include
|
||||
* a regular expression (`regex`) that the password must match.
|
||||
*
|
||||
* If the password violates any policy, the method sets an appropriate error
|
||||
* in the `perr` parameter and stops further validation.
|
||||
*
|
||||
* @param password the password to validate.
|
||||
* @param perr will be set to indicate a policy violation, if the password
|
||||
* does not meet the required standards. Possible values include:
|
||||
* `PolicyInsufficientPasswordQuality` for insufficient complexity.
|
||||
* @return YES if the password satisfies all policies, NO otherwise.
|
||||
*
|
||||
* @note This method assumes that `_userPasswordPolicy` is an array of dictionaries,
|
||||
* where each dictionary represents a password policy with at least a "regex" key.
|
||||
* @warning If a policy does not include a "regex" key, an error will be logged, and
|
||||
* the method will continue to the next policy.
|
||||
*/
|
||||
- (BOOL) checkPasswordPolicyWithPassword: (NSString *)password perr: (SOGoPasswordPolicyError *)perr
|
||||
{
|
||||
BOOL isPolicyOk;
|
||||
NSDictionary *policy;
|
||||
NSEnumerator *policies;
|
||||
NSRange match;
|
||||
NSString *regex;
|
||||
|
||||
isPolicyOk = YES;
|
||||
|
||||
if ([_userPasswordPolicy count])
|
||||
{
|
||||
policies = [_userPasswordPolicy objectEnumerator];
|
||||
while (isPolicyOk && (policy = [policies nextObject]))
|
||||
{
|
||||
regex = [policy objectForKey: @"regex"];
|
||||
if (regex)
|
||||
{
|
||||
match = [password rangeOfString: regex options: NSRegularExpressionSearch];
|
||||
isPolicyOk = isPolicyOk && match.length > 0;
|
||||
if (match.length == 0)
|
||||
{
|
||||
// [self errorWithFormat: @"Password not conform to policy %@ (%@)", regex, [policy objectForKey: @"label"]];
|
||||
*perr = PolicyInsufficientPasswordQuality;
|
||||
}
|
||||
}
|
||||
else
|
||||
[self errorWithFormat: @"Invalid password policy (missing regex): %@", policy];
|
||||
}
|
||||
}
|
||||
|
||||
return isPolicyOk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a user's password.
|
||||
* @param login the user's login name.
|
||||
@@ -357,11 +431,8 @@
|
||||
BOOL didChange, isOldPwdOk, isPolicyOk;
|
||||
EOAdaptorChannel *channel;
|
||||
GCSChannelManager *cm;
|
||||
NSDictionary *policy;
|
||||
NSEnumerator *policies;
|
||||
NSException *ex;
|
||||
NSRange match;
|
||||
NSString *sqlstr, *regex;
|
||||
NSString *sqlstr;
|
||||
|
||||
*perr = -1;
|
||||
isOldPwdOk = NO;
|
||||
@@ -369,30 +440,11 @@
|
||||
didChange = NO;
|
||||
|
||||
// Verify current password
|
||||
isOldPwdOk = [self checkLogin:login password:oldPassword perr:perr expire:0 grace:0];
|
||||
isOldPwdOk = [self checkLogin:login password:oldPassword perr:perr expire:0 grace:0 disablepasswordPolicyCheck: YES];
|
||||
|
||||
if (isOldPwdOk || passwordRecovery)
|
||||
{
|
||||
if ([_userPasswordPolicy count])
|
||||
{
|
||||
policies = [_userPasswordPolicy objectEnumerator];
|
||||
while (isPolicyOk && (policy = [policies nextObject]))
|
||||
{
|
||||
regex = [policy objectForKey: @"regex"];
|
||||
if (regex)
|
||||
{
|
||||
match = [newPassword rangeOfString: regex options: NSRegularExpressionSearch];
|
||||
isPolicyOk = isPolicyOk && match.length > 0;
|
||||
if (match.length == 0)
|
||||
{
|
||||
// [self errorWithFormat: @"Password not conform to policy %@ (%@)", regex, [policy objectForKey: @"label"]];
|
||||
*perr = PolicyInsufficientPasswordQuality;
|
||||
}
|
||||
}
|
||||
else
|
||||
[self errorWithFormat: @"Invalid password policy (missing regex): %@", policy];
|
||||
}
|
||||
}
|
||||
isPolicyOk = [self checkPasswordPolicyWithPassword:newPassword perr: perr];
|
||||
}
|
||||
|
||||
if ((isOldPwdOk || passwordRecovery) && isPolicyOk)
|
||||
|
||||
@@ -267,4 +267,8 @@
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (NSString *) applicationName {
|
||||
return @"SOGo";
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -68,6 +68,7 @@ typedef enum
|
||||
" -p credentialFile Specify the file containing the sieve admin credentials\n"
|
||||
" The file should contain a single line:\n"
|
||||
" username:password\n"
|
||||
" -F force the activation of the sieve script in case external scripts. Must be the las targument after -p credentialsFile"
|
||||
" Examples:\n"
|
||||
" sogo-tool user-preferences get defaults janedoe SOGoLanguage\n"
|
||||
" sogo-tool user-preferences unset settings janedoe Mail\n"
|
||||
@@ -144,9 +145,19 @@ typedef enum
|
||||
account = [folder lookupName: @"0" inContext: localContext acquire: NO];
|
||||
[account setContext: localContext];
|
||||
|
||||
error = [account updateFiltersWithUsername: authname
|
||||
andPassword: authpwd
|
||||
forceActivation: NO];
|
||||
if([[arguments lastObject] isEqualToString: @"-F"])
|
||||
{
|
||||
error = [account updateFiltersWithUsername: authname
|
||||
andPassword: authpwd
|
||||
forceActivation: YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
error = [account updateFiltersWithUsername: authname
|
||||
andPassword: authpwd
|
||||
forceActivation: NO];
|
||||
}
|
||||
|
||||
if (error)
|
||||
return NO;
|
||||
}
|
||||
@@ -248,7 +259,7 @@ typedef enum
|
||||
break;
|
||||
|
||||
case UserPreferencesSet:
|
||||
if (max > 4)
|
||||
if (![arguments containsObject: @"-f"])
|
||||
{
|
||||
/* value specified on command line */
|
||||
value = [sanitizedArguments objectAtIndex: 4];
|
||||
|
||||
+1
-2
@@ -114,8 +114,7 @@
|
||||
if (count < max)
|
||||
{
|
||||
max -= count;
|
||||
toolArguments = [arguments
|
||||
subarrayWithRange: NSMakeRange (count, max)];
|
||||
toolArguments = [arguments subarrayWithRange: NSMakeRange (count, max)];
|
||||
[toolArguments retain];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,3 +233,10 @@
|
||||
"passwordRecovery_SecretQuestion2" = "What was your first car ?";
|
||||
"passwordRecovery_SecretQuestion3" = "What is your favorite movie ?";
|
||||
"passwordRecovery_SecondaryEmail" = "Secondary E-mail";
|
||||
|
||||
/* Password */
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Minimum of %{0} lowercase letter";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Minimum of %{0} uppercase letter";
|
||||
"POLICY_MIN_DIGIT" = "Minimum of %{0} digit";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Minimum of %{0} special symbols";
|
||||
"POLICY_MIN_LENGTH" = "Minimum length of %{0} characters";
|
||||
@@ -233,3 +233,10 @@
|
||||
"passwordRecovery_SecretQuestion2" = "Quelle était votre première voiture ?";
|
||||
"passwordRecovery_SecretQuestion3" = "Quel est votre film préféré ?";
|
||||
"passwordRecovery_SecondaryEmail" = "E-mail secondaire";
|
||||
|
||||
/* Password */
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Au moins %{0} lettre(s) minuscule(s)";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Au moins %{0} lettre(s) majuscule(s)";
|
||||
"POLICY_MIN_DIGIT" = "Au moins %{0} chiffre(s)";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Au moins %{0} caractère(s) special(aux)";
|
||||
"POLICY_MIN_LENGTH" = "Longueur d'au moins %{0} caractère(s)";
|
||||
@@ -171,6 +171,7 @@
|
||||
/* MailListView */
|
||||
"Sender" = "Sender";
|
||||
"Subject or Sender" = "Subject or Sender";
|
||||
"Subject or Recipient" = "Subject or Recipient";
|
||||
"To or Cc" = "To or Cc";
|
||||
"Entire Message" = "Entire Message";
|
||||
"Date" = "Date";
|
||||
@@ -514,3 +515,18 @@
|
||||
|
||||
/* Hotkey to forward to a message */
|
||||
"hotkey_forward" = "f";
|
||||
|
||||
/* Email deletion */
|
||||
"Clean folder" = "Clean folder";
|
||||
"Clean mailbox" = "Clean mailbox";
|
||||
"Delete permanently (do not use trash)" = "Delete permanently (do not use trash)";
|
||||
"Apply to subfolders" = "Apply to subfolders";
|
||||
"Delete e-mails older than" = "Delete e-mails older than";
|
||||
"3 months" = "3 months";
|
||||
"6 months" = "6 months";
|
||||
"9 months" = "9 months";
|
||||
"1 year" = "1 year";
|
||||
"Custom" = "Custom";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "You are about to permanently delete some messages. Are you sure you want to proceed with this action?";
|
||||
"Apply" = "Apply";
|
||||
"%{0} message(s) deleted" = "%{0} message(s) deleted";
|
||||
@@ -171,6 +171,7 @@
|
||||
/* MailListView */
|
||||
"Sender" = "Expéditeur";
|
||||
"Subject or Sender" = "Sujet ou expéditeur";
|
||||
"Subject or Recipient" = "Sujet ou destinataire";
|
||||
"To or Cc" = "Pour ou Copie à";
|
||||
"Entire Message" = "Message Complet";
|
||||
"Date" = "Date";
|
||||
@@ -514,3 +515,18 @@
|
||||
|
||||
/* Hotkey to forward to a message */
|
||||
"hotkey_forward" = "f";
|
||||
|
||||
/* Email deletion */
|
||||
"Clean folder" = "Nettoyer le dossier";
|
||||
"Clean mailbox" = "Nettoyer la boite mail";
|
||||
"Delete permanently (do not use trash)" = "Supprimer définitivement (ne pas utiliser la corbeille)";
|
||||
"Apply to subfolders" = "Appliquer aux sous-dossiers";
|
||||
"Delete e-mails older than" = "Supprimer les e-mails plus vieux de";
|
||||
"3 months" = "3 mois";
|
||||
"6 months" = "6 mois";
|
||||
"9 months" = "9 mois";
|
||||
"1 year" = "1 an";
|
||||
"Custom" = "Personnalisé";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "Vous êtes sur le point de supprimer définitivement certains messages. Êtes-vous certain de vouloir effectuer cette action ?";
|
||||
"Apply" = "Appliquer";
|
||||
"%{0} message(s) deleted" = "%{0} message(s) supprimés";
|
||||
@@ -132,6 +132,8 @@
|
||||
drafts = [account draftsFolderInContext: context];
|
||||
newMail = [drafts newDraft];
|
||||
[newMail fetchMailForEditing: co];
|
||||
if ([co isInTemplatesFolder])
|
||||
[newMail save];
|
||||
[newMail storeInfo];
|
||||
|
||||
accountName = [account nameInContainer];
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
@@ -46,6 +47,8 @@
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserSettings.h>
|
||||
|
||||
#import <EOControl/EOQualifier.h>
|
||||
|
||||
#import "UIxMailFolderActions.h"
|
||||
|
||||
@implementation UIxMailFolderActions
|
||||
@@ -1298,4 +1301,126 @@
|
||||
return [self _markMessagesAsJunkOrNotJunk: NO];
|
||||
}
|
||||
|
||||
- (BOOL)isDateStringValid: (NSString *)dateString {
|
||||
NSString *dateRegex = @"^\\d{4}-\\d{2}-\\d{2}$";
|
||||
NSPredicate *dateTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", dateRegex];
|
||||
return [dateTest evaluateWithObject:dateString];
|
||||
}
|
||||
|
||||
- (void) cleanFolderWithFolder: (SOGoMailFolder *)folder
|
||||
withQualifier: (EOQualifier *)qualifier
|
||||
recursive: (BOOL)isRecursive
|
||||
withTrashFolder: (BOOL)useTrashFolder
|
||||
exception: (NSException **)exception
|
||||
counter: (NSUInteger *)counter {
|
||||
NSArray *results, *subfolders;
|
||||
NSUInteger i;
|
||||
SOGoMailFolder *newFolder;
|
||||
NSString *folderName;
|
||||
NSException *e;
|
||||
|
||||
results = [folder fetchUIDsMatchingQualifier: qualifier
|
||||
sortOrdering: @"REVERSE DATE"
|
||||
threaded: NO];
|
||||
|
||||
if (results && [results count] > 0) {
|
||||
e = [folder deleteUIDs: results
|
||||
useTrashFolder: &useTrashFolder
|
||||
inContext: [self context]];
|
||||
[folder expunge];
|
||||
[self logWithFormat: @"Removed %d messages in %@ (%@)", [results count], [folder nameInContainer], results];
|
||||
*counter += [results count];
|
||||
if (e) {
|
||||
[self errorWithFormat: @"Error while cleaning mailbox : %@", e];
|
||||
*exception = e;
|
||||
}
|
||||
}
|
||||
|
||||
if (isRecursive) {
|
||||
subfolders = [folder subfolders];
|
||||
for (i = 0 ; i < [subfolders count] ; i++) {
|
||||
folderName = [NSString stringWithFormat:@"%@/%@", [folder nameInContainer], [subfolders objectAtIndex: i]];
|
||||
newFolder = [[SOGoMailFolder alloc] initWithName: folderName inContainer: [folder container]];
|
||||
[self cleanFolderWithFolder: newFolder
|
||||
withQualifier: qualifier
|
||||
recursive: isRecursive
|
||||
withTrashFolder: useTrashFolder
|
||||
exception: exception
|
||||
counter: counter];
|
||||
[newFolder release];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (WOResponse *) cleanMailboxAction
|
||||
{
|
||||
NSDictionary *jsonRequest, *jsonResponse;
|
||||
WORequest *request;
|
||||
NSString *searchString, *folderName;
|
||||
EOQualifier *searchQualifier;
|
||||
BOOL isRecursive, useTrashFolder;
|
||||
NSException *exception;
|
||||
SOGoMailFolder *folder;
|
||||
SOGoMailAccount *account;
|
||||
NSUInteger i, counter;
|
||||
NSArray *folderNames;
|
||||
|
||||
request = [[self context] request];
|
||||
jsonRequest = [[request contentAsString] objectFromJSONString];
|
||||
|
||||
if (![[SOGoSystemDefaults sharedSystemDefaults] enableMailCleaning])
|
||||
return [self responseWithStatus: 401];
|
||||
|
||||
if (![self isDateStringValid: [jsonRequest objectForKey: @"date"]]) {
|
||||
[self errorWithFormat: @"Error while cleaning mailbox, invalid date : %@", [jsonRequest objectForKey: @"date"]];
|
||||
return [self responseWithStatus: 502];
|
||||
}
|
||||
|
||||
searchString = [NSString stringWithFormat: @"(NOT (flags = 'deleted') AND (DATE <= (NSCalendarDate)\"%@\"))", [jsonRequest objectForKey: @"date"]];
|
||||
searchQualifier = [EOQualifier qualifierWithQualifierFormat: searchString];
|
||||
isRecursive = [[jsonRequest objectForKey: @"applyToSubfolders"] boolValue];
|
||||
useTrashFolder = ![[jsonRequest objectForKey: @"permanentlyDelete"] boolValue];
|
||||
counter = 0;
|
||||
exception = nil;
|
||||
|
||||
if ([[self clientObject] isKindOfClass: [SOGoMailFolder class]]) {
|
||||
folder = [self clientObject];
|
||||
[self cleanFolderWithFolder: folder
|
||||
withQualifier: searchQualifier
|
||||
recursive: isRecursive
|
||||
withTrashFolder: useTrashFolder
|
||||
exception: &exception
|
||||
counter: &counter];
|
||||
} else if ([[self clientObject] isKindOfClass: [SOGoMailAccount class]]) {
|
||||
account = [self clientObject];
|
||||
folderNames = [account allFolderPaths: SOGoMailStandardListing onlyRoot: YES];
|
||||
for (i = 0 ; i < [folderNames count] ; i ++) {
|
||||
folderName = [folderNames objectAtIndex: i];
|
||||
if ([folderName hasPrefix:@"/"]) {
|
||||
folderName = [folderName substringFromIndex:1];
|
||||
}
|
||||
folder = [account folderWithTraversal: folderName andClassName: nil];
|
||||
// Disable clean for trash folder
|
||||
if (![folderName isEqualToString: [account trashFolderNameInContext: [self context]]]
|
||||
&& ![folderName isEqualToString: [account templatesFolderNameInContext: [self context]]])
|
||||
[self cleanFolderWithFolder: folder
|
||||
withQualifier: searchQualifier
|
||||
recursive: isRecursive
|
||||
withTrashFolder: useTrashFolder
|
||||
exception: &exception
|
||||
counter: &counter];
|
||||
}
|
||||
|
||||
[[account imap4Connection] flushMailCaches];
|
||||
}
|
||||
|
||||
if (exception) {
|
||||
return [self responseWithStatus: 500];
|
||||
}
|
||||
|
||||
jsonResponse = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: counter]
|
||||
forKey: @"nbMessageDeleted"];
|
||||
return [self responseWithStatus: 200 andJSONRepresentation: jsonResponse];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -611,6 +611,17 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL) isCleanMailboxEnabled {
|
||||
BOOL result;
|
||||
SOGoSystemDefaults *sd;
|
||||
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
|
||||
result = [sd enableMailCleaning];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end /* UIxMailMainFrame */
|
||||
|
||||
@interface UIxMailFolderTemplate : UIxComponent
|
||||
|
||||
@@ -49,6 +49,11 @@
|
||||
actionClass = "UIxMailFolderActions";
|
||||
actionName = "expunge";
|
||||
};
|
||||
cleanMailbox = {
|
||||
protectedBy = "View";
|
||||
actionClass = "UIxMailFolderActions";
|
||||
actionName = "cleanMailbox";
|
||||
};
|
||||
createFolder = {
|
||||
protectedBy = "View";
|
||||
actionClass = "UIxMailFolderActions";
|
||||
@@ -417,6 +422,11 @@
|
||||
protectedBy = "View";
|
||||
pageName = "UIxMailUserDelegationEditor";
|
||||
};
|
||||
cleanMailbox = {
|
||||
protectedBy = "View";
|
||||
actionClass = "UIxMailFolderActions";
|
||||
actionName = "cleanMailbox";
|
||||
};
|
||||
addDelegate = {
|
||||
protectedBy = "View";
|
||||
actionClass = "UIxMailAccountActions";
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"Domain" = "Domain";
|
||||
"Remember username" = "Remember username";
|
||||
"Connect" = "Connect";
|
||||
"Create an account" = "Create an account";
|
||||
|
||||
/* Appears while authentication is in progress */
|
||||
"Authenticating" = "Authenticating";
|
||||
@@ -87,6 +88,7 @@ See <a href=\"http://www.sogo.nu/en/support/community.html\">this page</a> for v
|
||||
"Change your Password" = "Change your Password";
|
||||
"The password was changed successfully." = "The password was changed successfully.";
|
||||
"Your password has expired, please enter a new one below" = "Your password has expired, please enter a new one below";
|
||||
"Your password is too weak. Please choose a stronger password to enhance your security" = "Your password is too weak. Please choose a stronger password to enhance your security";
|
||||
"Password must not be empty." = "Password must not be empty.";
|
||||
"The passwords do not match. Please try again." = "The passwords do not match. Please try again.";
|
||||
"Password Grace Period" = "Password Grace Period";
|
||||
@@ -129,4 +131,4 @@ See <a href=\"http://www.sogo.nu/en/support/community.html\">this page</a> for v
|
||||
"Invalid configuration for email password recovery" = "Invalid configuration for email password recovery";
|
||||
"Password recovery email in error" = "Password recovery email in error";
|
||||
"Password reset" = "Password reset";
|
||||
"Hi %{0},\nThere was a request to change your password!\n\nIf you did not make this request then please ignore this email.\n\nOtherwise, please click this link to change your password: %{1}" = "Hi %{0},\nThere was a request to change your password!\n\nIf you did not make this request then please ignore this email.\n\nOtherwise, please click this link to change your password: %{1}";
|
||||
"Hi %{0},\nThere was a request to change your password!\n\nIf you did not make this request then please ignore this email.\n\nOtherwise, please click this link to change your password: %{1}" = "Hi %{0},\nThere was a request to change your password!\n\nIf you did not make this request then please ignore this email.\n\nOtherwise, please click this link to change your password: %{1}";
|
||||
@@ -6,6 +6,7 @@
|
||||
"Domain" = "Domaine";
|
||||
"Remember username" = "Se souvenir de moi";
|
||||
"Connect" = "Connexion";
|
||||
"Create an account" = "Créer un compte";
|
||||
|
||||
/* Appears while authentication is in progress */
|
||||
"Authenticating" = "Authentification en cours";
|
||||
@@ -84,6 +85,7 @@
|
||||
"Change your Password" = "Changez votre mot de passe";
|
||||
"The password was changed successfully." = "Votre mot de passe a bien été changé.";
|
||||
"Your password has expired, please enter a new one below" = "Votre mot de passe est expiré, veuillez entrer un nouveau mot de passe";
|
||||
"Your password is too weak. Please choose a stronger password to enhance your security" = "Votre mot de passe est trop faible. Veuillez choisir un mot de passe plus sécurisé pour renforcer votre protection";
|
||||
"Password must not be empty." = "Le mot de passe ne doit pas être vide.";
|
||||
"The passwords do not match. Please try again." = "Les mots de passe ne sont pas identiques. Essayez de nouveau.";
|
||||
"Password Grace Period" = "Période de grâce pour le mot de passe";
|
||||
@@ -126,4 +128,4 @@
|
||||
"Invalid configuration for email password recovery" = "Configuration invalide pour la récupération de mot de passe par e-mail";
|
||||
"Password recovery email in error" = "Erreur lors de l'envoi de l'email de récupération";
|
||||
"Password reset" = "Réinitialisation de mot de passe";
|
||||
"Hi %{0},\nThere was a request to change your password!\n\nIf you did not make this request then please ignore this email.\n\nOtherwise, please click this link to change your password: %{1}" = "Bonjour %{0},\nUne demande de changement de mot de passe a été initiée.\n\nSi vous n'êtes pas à l'origine de cet e-mail, n'en tenez pas compte.\n\nSi vous en êtes bien à l'origine, veuillez cliquer sur le lien ci-dessous pour modifier votre mot de passe: %{1}";
|
||||
"Hi %{0},\nThere was a request to change your password!\n\nIf you did not make this request then please ignore this email.\n\nOtherwise, please click this link to change your password: %{1}" = "Bonjour %{0},\nUne demande de changement de mot de passe a été initiée.\n\nSi vous n'êtes pas à l'origine de cet e-mail, n'en tenez pas compte.\n\nSi vous en êtes bien à l'origine, veuillez cliquer sur le lien ci-dessous pour modifier votre mot de passe: %{1}";
|
||||
+60
-10
@@ -52,6 +52,7 @@
|
||||
#import <SOGo/SOGoEmptyAuthenticator.h>
|
||||
#import <SOGo/SOGoMailer.h>
|
||||
#import <SOGo/SOGoAdmin.h>
|
||||
#import <SOGo/SOGoPasswordPolicy.h>
|
||||
|
||||
#if defined(MFA_CONFIG)
|
||||
#include <liboath/oath.h>
|
||||
@@ -167,14 +168,23 @@ static const NSString *kJwtKey = @"jwt";
|
||||
//
|
||||
//
|
||||
//
|
||||
- (WOResponse *) _responseWithLDAPPolicyError: (int) error
|
||||
- (WOResponse *) _responseWithLDAPPolicyError: (int) error additionalInfos: (NSDictionary *) additionalInfos
|
||||
{
|
||||
NSDictionary *jsonError;
|
||||
|
||||
jsonError = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: error]
|
||||
forKey: @"LDAPPasswordPolicyError"];
|
||||
return [self responseWithStatus: 403
|
||||
andJSONRepresentation: jsonError];
|
||||
if (additionalInfos) {
|
||||
jsonError = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithInt:error], @"LDAPPasswordPolicyError",
|
||||
additionalInfos, @"additionalInfos",
|
||||
nil];
|
||||
} else {
|
||||
jsonError = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithInt:error], @"LDAPPasswordPolicyError",
|
||||
nil];
|
||||
}
|
||||
|
||||
return [self responseWithStatus:403
|
||||
andJSONRepresentation:jsonError];
|
||||
}
|
||||
|
||||
- (void) _checkAutoReloadWebCalendars: (SOGoUser *) loggedInUser
|
||||
@@ -197,6 +207,27 @@ static const NSString *kJwtKey = @"jwt";
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void)translateAdditionalLoginInformations:(NSMutableDictionary **)additionalLoginInformations
|
||||
{
|
||||
NSDictionary *policy;
|
||||
NSMutableDictionary *translations;
|
||||
|
||||
if (additionalLoginInformations && *additionalLoginInformations) {
|
||||
if ([*additionalLoginInformations objectForKey:@"userPolicies"]) {
|
||||
translations = [[NSMutableDictionary alloc] init];
|
||||
for (policy in [*additionalLoginInformations objectForKey:@"userPolicies"]) {
|
||||
[translations setObject:[self commonLabelForKey: [policy objectForKey:@"label"]] forKey: [policy objectForKey:@"label"]];
|
||||
}
|
||||
[*additionalLoginInformations setObject:[SOGoPasswordPolicy createPasswordPolicyLabels: [*additionalLoginInformations objectForKey:@"userPolicies"] withTranslations: translations]
|
||||
forKey:@"userPolicies"];
|
||||
[translations release];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -210,6 +241,7 @@ static const NSString *kJwtKey = @"jwt";
|
||||
SOGoUserSettings *us;
|
||||
SOGoUser *loggedInUser;
|
||||
NSDictionary *params;
|
||||
NSMutableDictionary *additionalLoginInformations;
|
||||
NSString *username, *password, *language, *domain, *remoteHost;
|
||||
NSArray *supportedLanguages, *creds;
|
||||
|
||||
@@ -223,6 +255,7 @@ static const NSString *kJwtKey = @"jwt";
|
||||
auth = [[WOApplication application] authenticatorInContext: context];
|
||||
request = [context request];
|
||||
params = [[request contentAsString] objectFromJSONString];
|
||||
additionalLoginInformations = [[NSMutableDictionary alloc] init];
|
||||
|
||||
username = [params objectForKey: @"userName"];
|
||||
password = [params objectForKey: @"password"];
|
||||
@@ -232,9 +265,11 @@ static const NSString *kJwtKey = @"jwt";
|
||||
/* this will always be set to something more or less useful by
|
||||
* [WOHttpTransaction applyAdaptorHeadersWithHttpRequest] */
|
||||
remoteHost = [request headerForKey:@"x-webobjects-remote-host"];
|
||||
b = [auth checkLogin: username password: password domain: &domain
|
||||
perr: &err expire: &expire grace: &grace additionalInfo: &additionalLoginInformations useCache: NO];
|
||||
[self translateAdditionalLoginInformations: &additionalLoginInformations];
|
||||
|
||||
if ((b = [auth checkLogin: username password: password domain: &domain
|
||||
perr: &err expire: &expire grace: &grace useCache: NO])
|
||||
if (b
|
||||
&& (err == PolicyNoError)
|
||||
// no password policy
|
||||
&& ((expire < 0 && grace < 0) // no password policy or everything is alright
|
||||
@@ -334,7 +369,7 @@ static const NSString *kJwtKey = @"jwt";
|
||||
#endif
|
||||
|
||||
if ([us objectForKey: @"ForceResetPassword"]) {
|
||||
response = [self _responseWithLDAPPolicyError: PolicyPasswordExpired];
|
||||
response = [self _responseWithLDAPPolicyError: PolicyPasswordExpired additionalInfos: additionalLoginInformations];
|
||||
} else {
|
||||
[self _checkAutoReloadWebCalendars: loggedInUser];
|
||||
|
||||
@@ -377,7 +412,7 @@ static const NSString *kJwtKey = @"jwt";
|
||||
[self logWithFormat: @"Login from '%@' for user '%@' might not have worked - password policy: %d grace: %d expire: %d bound: %d",
|
||||
remoteHost, username, err, grace, expire, b];
|
||||
|
||||
response = [self _responseWithLDAPPolicyError: err];
|
||||
response = [self _responseWithLDAPPolicyError: err additionalInfos: additionalLoginInformations];
|
||||
}
|
||||
|
||||
if (rememberLogin)
|
||||
@@ -385,6 +420,8 @@ static const NSString *kJwtKey = @"jwt";
|
||||
else
|
||||
[response addCookie: [self _cookieWithUsername: nil]];
|
||||
|
||||
[additionalLoginInformations release];
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -808,7 +845,7 @@ static const NSString *kJwtKey = @"jwt";
|
||||
}
|
||||
}
|
||||
else
|
||||
response = [self _responseWithLDAPPolicyError: error];
|
||||
response = [self _responseWithLDAPPolicyError: error additionalInfos: nil];
|
||||
}
|
||||
|
||||
return response;
|
||||
@@ -1060,4 +1097,17 @@ static const NSString *kJwtKey = @"jwt";
|
||||
return [[SOGoAdmin sharedInstance] getMotd] && [[[SOGoAdmin sharedInstance] getMotd] length] > 1;
|
||||
}
|
||||
|
||||
- (BOOL) hasUrlCreateAccount
|
||||
{
|
||||
return ([[SOGoSystemDefaults sharedSystemDefaults]
|
||||
urlCreateAccount] != nil);
|
||||
}
|
||||
|
||||
- (NSString *) urlCreateAccount
|
||||
{
|
||||
return [[SOGoSystemDefaults sharedSystemDefaults]
|
||||
urlCreateAccount];
|
||||
}
|
||||
|
||||
|
||||
@end /* SOGoRootPage */
|
||||
@@ -274,11 +274,6 @@
|
||||
"Confirmation" = "Confirmation";
|
||||
"Change" = "Change";
|
||||
"Passwords don't match" = "Passwords don't match";
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Minimum of %{0} lowercase letter";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Minimum of %{0} uppercase letter";
|
||||
"POLICY_MIN_DIGIT" = "Minimum of %{0} digit";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Minimum of %{0} special symbols";
|
||||
"POLICY_MIN_LENGTH" = "Minimum length of %{0} characters";
|
||||
|
||||
|
||||
/* Event+task classifications */
|
||||
|
||||
@@ -274,11 +274,7 @@
|
||||
"Confirmation" = "Confirmation";
|
||||
"Change" = "Changer";
|
||||
"Passwords don't match" = "Les mots de passe ne correspondent pas";
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Au moins %{0} lettre(s) minuscule(s)";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Au moins %{0} lettre(s) majuscule(s)";
|
||||
"POLICY_MIN_DIGIT" = "Au moins %{0} chiffre(s)";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Au moins %{0} caractère(s) special(aux)";
|
||||
"POLICY_MIN_LENGTH" = "Longueur d'au moins %{0} caractère(s)";
|
||||
|
||||
|
||||
|
||||
/* Event+task classifications */
|
||||
|
||||
@@ -278,7 +278,7 @@ static NSArray *reminderValues = nil;
|
||||
userSource = [user authenticationSource];
|
||||
|
||||
for(policy in [userSource userPasswordPolicy]) {
|
||||
[translations setObject:[self labelForKey:[policy objectForKey:@"label"]]
|
||||
[translations setObject:[self commonLabelForKey:[policy objectForKey:@"label"]]
|
||||
forKey: [policy objectForKey:@"label"]];
|
||||
}
|
||||
translatedUserPolicy = [SOGoPasswordPolicy createPasswordPolicyLabels: [userSource userPasswordPolicy]
|
||||
|
||||
@@ -350,6 +350,7 @@ static NSArray *tasksFields = nil;
|
||||
//NSLog(@"***[UIxCalListingActions _fixDates:] %@ = %@ (%i)", aDateField, aDate, daylightOffset);
|
||||
if (daylightOffset)
|
||||
{
|
||||
[self logWithFormat: @"Changing date (aDate '%@'), (startDate '%@'), (daylightOffset %d)", aDate, startDate, daylightOffset];
|
||||
// If it is the end date and allday, we need to remove the offset
|
||||
if ([fields[count * 2] isEqualToString: @"endDate"] && [[theRecord objectForKey: @"c_isallday"] boolValue] && daylightOffset > 0)
|
||||
aDate = [aDate dateByAddingYears: 0 months: 0 days: 0 hours: 0
|
||||
|
||||
@@ -495,7 +495,7 @@
|
||||
</md-autocomplete>
|
||||
<md-chip-template>
|
||||
<div class="sg-tile-content">
|
||||
{{$chip.c_cn}}
|
||||
{{$chip.c_cn || $chip.email}}
|
||||
</div>
|
||||
</md-chip-template>
|
||||
</md-chips>
|
||||
|
||||
@@ -87,11 +87,16 @@
|
||||
<md-icon label:aria-label="Subject">{{ mailbox.sortedBy('subject') ? 'check' : null }}</md-icon> <var:string label:value="Subject"/>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
<md-menu-item>
|
||||
<md-menu-item ng-if="!mailbox.selectedFolder.isSentFolder">
|
||||
<md-button ng-click="mailbox.sort('from')">
|
||||
<md-icon label:aria-label="From">{{ mailbox.sortedBy('from') ? 'check' : null }}</md-icon> <var:string label:value="From"/>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
<md-menu-item ng-if="mailbox.selectedFolder.isSentFolder">
|
||||
<md-button ng-click="mailbox.sort('to')">
|
||||
<md-icon label:aria-label="To">{{ mailbox.sortedBy('to') ? 'check' : null }}</md-icon> <var:string label:value="To"/>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
<md-menu-item>
|
||||
<md-button ng-click="mailbox.sort('date')">
|
||||
<md-icon label:aria-label="Date">{{ mailbox.sortedBy('date') ? 'check' : null }}</md-icon> <var:string label:value="Date"/>
|
||||
@@ -143,7 +148,8 @@
|
||||
</md-input-container>
|
||||
<md-input-container flex="25">
|
||||
<md-select label:aria-label="Search scope">
|
||||
<md-option value="subject_or_from" selected="selected"><var:string label:value="Subject or Sender"/></md-option>
|
||||
<md-option value="subject_or_from" selected="selected" ng-if="!mailbox.selectedFolder.isSentFolder"><var:string label:value="Subject or Sender"/></md-option>
|
||||
<md-option value="subject_or_to" selected="selected" ng-if="mailbox.selectedFolder.isSentFolder"><var:string label:value="Subject or Recipient"/></md-option>
|
||||
<md-option value="subject"><var:string label:value="Subject"/></md-option>
|
||||
<md-option value="from"><var:string label:value="Sender"/></md-option>
|
||||
<md-option value="to_or_cc"><var:string label:value="To or Cc"/></md-option>
|
||||
@@ -265,7 +271,7 @@
|
||||
<md-button class="sg-no-wrap"
|
||||
aria-label="{{folder.$displayName}}"
|
||||
ng-disabled="::(mailbox.service.selectedFolder.id == folder.id)"
|
||||
ng-click="mailbox.moveSelectedMessages(folder.id)">
|
||||
ng-click="mailbox.moveSelectedMessages(folder.id, null)">
|
||||
<span ng-class="::('sg-child-level-' + folder.level)"
|
||||
ng-bind="folder.$displayName"><!-- mailbox name --></span>
|
||||
</md-button>
|
||||
@@ -632,4 +638,87 @@
|
||||
</md-dialog-actions>
|
||||
</md-dialog>
|
||||
</script>
|
||||
<!-- Remove old emails -->
|
||||
<script type="text/ng-template" id="cleanMailbox">
|
||||
<md-dialog flex="50" flex-sm="80" flex-xs="100">
|
||||
<!-- Toolbar -->
|
||||
<md-toolbar>
|
||||
<div class="md-toolbar-tools">
|
||||
<md-icon class="material-icons sg-icon-toolbar-bg">delete</md-icon>
|
||||
<div class="pseudo-input-container md-flex" ng-if="::!dialogCtrl.isMailbox">
|
||||
<var:string label:value="Clean folder"/>
|
||||
</div>
|
||||
<div class="pseudo-input-container md-flex" ng-if="::dialogCtrl.isMailbox">
|
||||
<var:string label:value="Clean mailbox"/>
|
||||
</div>
|
||||
<md-button class="md-icon-button" ng-click="dialogCtrl.closeDialog()">
|
||||
<md-icon aria-label="Close dialog">close</md-icon>
|
||||
</md-button>
|
||||
</div>
|
||||
</md-toolbar>
|
||||
|
||||
<!-- Dialog Content -->
|
||||
<md-dialog-content class="md-dialog-content">
|
||||
<div class="md-dialog-content">
|
||||
<h4>
|
||||
{{ dialogCtrl.name }}
|
||||
</h4>
|
||||
|
||||
<md-input-container class="md-block">
|
||||
<md-checkbox ng-model="dialogCtrl.form.permanentlyDelete" label:aria-label="Delete permanently (do not use trash)">
|
||||
<var:string label:value="Delete permanently (do not use trash)"/>
|
||||
</md-checkbox>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container class="md-block">
|
||||
<md-checkbox ng-model="dialogCtrl.form.applyToSubfolders" label:aria-label="Apply to subfolders">
|
||||
<var:string label:value="Apply to subfolders"/>
|
||||
</md-checkbox>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container class="md-block">
|
||||
<label><var:string label:value="Delete e-mails older than"/></label>
|
||||
<md-select ng-model="dialogCtrl.form.filterDuration">
|
||||
<md-option value="3m"><var:string label:value="3 months"/></md-option>
|
||||
<md-option value="6m"><var:string label:value="6 months"/></md-option>
|
||||
<md-option value="9m"><var:string label:value="9 months"/></md-option>
|
||||
<md-option value="1y"><var:string label:value="1 year"/></md-option>
|
||||
<md-option value="custom"><var:string label:value="Custom"/></md-option>
|
||||
</md-select>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container class="md-block" ng-show="['custom'].indexOf(dialogCtrl.form.filterDuration) != -1">
|
||||
<label><var:string label:value="Date"/></label>
|
||||
<md-datepicker class="md-text"
|
||||
ng-model="dialogCtrl.form.filterDurationDate"
|
||||
md-hide-icons="calendar"
|
||||
md-max-date="dialogCtrl.maxDate"
|
||||
ng-change="dialogCtrl.mainController.changeDate()">
|
||||
</md-datepicker>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container class="md-block" ng-show="dialogCtrl.isWarningDisplayed()">
|
||||
<md-checkbox ng-model="dialogCtrl.form.confirmDelete" label:aria-label="You are about to permanently delete some messages. Are you sure you want to proceed with this action?">
|
||||
<span class="clean-mailbox-warn"><var:string label:value="You are about to permanently delete some messages. Are you sure you want to proceed with this action?" /></span>
|
||||
</md-checkbox>
|
||||
</md-input-container>
|
||||
</div>
|
||||
</md-dialog-content>
|
||||
|
||||
<!-- Dialog Actions -->
|
||||
<md-dialog-actions>
|
||||
<md-button class="md-warn" ng-click="dialogCtrl.closeDialog()">
|
||||
<var:string label:value="Cancel" />
|
||||
</md-button>
|
||||
<div class="sg-progress-linear-bottom"
|
||||
ng-show="dialogCtrl.isLoading()">
|
||||
<md-progress-linear class="md-accent"
|
||||
md-mode="indeterminate"><!-- progress --></md-progress-linear>
|
||||
</div>
|
||||
<md-button class="md-primary" ng-disabled="dialogCtrl.isApplyDisabled()" ng-click="dialogCtrl.apply()">
|
||||
<var:string label:value="Apply" />
|
||||
</md-button>
|
||||
</md-dialog-actions>
|
||||
</md-dialog>
|
||||
</script>
|
||||
</container>
|
||||
@@ -69,6 +69,13 @@
|
||||
<var:string label:value="New Folder..."/>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
<var:if condition="isCleanMailboxEnabled">
|
||||
<md-menu-item>
|
||||
<md-button type="button" ng-click="app.showCleanMailboxPanel(null, account)">
|
||||
<var:string label:value="Clean mailbox"/>...
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
</var:if>
|
||||
<md-menu-item ng-show="::account.id == 0">
|
||||
<md-button
|
||||
label:aria-label="Search"
|
||||
@@ -179,6 +186,13 @@
|
||||
<var:string label:value="Compact"/>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
<var:if condition="isCleanMailboxEnabled">
|
||||
<md-menu-item ng-show="::($menuCtrl.folder.type != 'trash')">
|
||||
<md-button type="button" ng-click="$menuCtrl.cleanMailbox()">
|
||||
<var:string label:value="Clean folder"/>...
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
</var:if>
|
||||
<md-menu-item ng-show="::$menuCtrl.folder.$isEditable">
|
||||
<md-button type="button" ng-click="$menuCtrl.confirmDelete()">
|
||||
<var:string label:value="Delete"/>
|
||||
|
||||
@@ -75,6 +75,53 @@
|
||||
<md-tooltip md-direction="bottom"><var:string label:value="Delete selected message or folder"/></md-tooltip>
|
||||
<md-icon>delete</md-icon>
|
||||
</md-button>
|
||||
|
||||
<md-menu>
|
||||
<md-button class="sg-icon-button" label:aria-label="Move To"
|
||||
ng-click="$mdMenu.open($event)">
|
||||
<md-tooltip md-direction="bottom"><var:string label:value="Move To"/></md-tooltip>
|
||||
<md-icon>call_split</md-icon>
|
||||
</md-button>
|
||||
<md-menu-content width="4">
|
||||
<md-menu-item>
|
||||
<md-menu>
|
||||
<md-button label:aria-label="Move To" ng-click="$mdMenu.open($event)">
|
||||
<var:string label:value="Move To"/>
|
||||
</md-button>
|
||||
<md-menu-content width="4">
|
||||
<div ng-repeat="account in ::mailbox.accounts track by account.id">
|
||||
<md-menu-item>
|
||||
<md-menu>
|
||||
<md-button class="md-primary"
|
||||
aria-label="{{ ::account.name }}"
|
||||
ng-click="$mdMenu.open($event)"
|
||||
ng-bind="::account.name"><!-- account name --></md-button>
|
||||
<md-menu-content class="md-dense" width="4">
|
||||
<div ng-repeat="folder in
|
||||
account.$flattenMailboxes({ all: true })
|
||||
track by folder.path">
|
||||
<md-menu-item>
|
||||
<md-button class="sg-no-wrap"
|
||||
aria-label="{{folder.$displayName}}"
|
||||
ng-disabled="::(mailbox.service.selectedFolder.id == folder.id)"
|
||||
ng-click="mailbox.moveSelectedMessages(folder.id, viewer.message)">
|
||||
<span ng-class="::('sg-child-level-' + folder.level)"
|
||||
ng-bind="folder.$displayName"><!-- mailbox name --></span>
|
||||
</md-button>
|
||||
</md-menu-item>
|
||||
</div>
|
||||
</md-menu-content>
|
||||
</md-menu>
|
||||
</md-menu-item>
|
||||
</div>
|
||||
</md-menu-content>
|
||||
</md-menu>
|
||||
</md-menu-item>
|
||||
</md-menu-content>
|
||||
</md-menu>
|
||||
|
||||
|
||||
|
||||
<md-button class="sg-icon-button hide show-gt-md" label:aria-label="'Open in New Mail Window'.asSafeJSString"
|
||||
ng-hide="::isPopup"
|
||||
ng-click="viewer.openInPopup()">
|
||||
|
||||
@@ -106,6 +106,11 @@
|
||||
<var:string label:value="Remember username"/>
|
||||
</md-switch>
|
||||
</div>
|
||||
<var:if condition="hasUrlCreateAccount">
|
||||
<div layout="row" layout-align="center center">
|
||||
<a var:href="urlCreateAccount" target="_blank" class="create-account-link"><var:string label:value="Create an account"/></a>
|
||||
</div>
|
||||
</var:if>
|
||||
</div>
|
||||
|
||||
<!-- Password recovery -->
|
||||
@@ -208,17 +213,18 @@
|
||||
<!-- Password policy: Password is expired / password recovery-->
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="passwordchange">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large" ng-if="!app.isInPasswordRecoveryMode()">watch_later</md-icon>
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large" ng-if="app.isInPasswordRecoveryMode()">vpn_key</md-icon>
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large" ng-if="!(app.isInPasswordRecoveryMode() || app.isPasswordExpiredSecurity())">watch_later</md-icon>
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large" ng-if="app.isInPasswordRecoveryMode() || app.isPasswordExpiredSecurity()">vpn_key</md-icon>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding" ng-if="!app.isInPasswordRecoveryMode()">
|
||||
<var:string label:value="Your password has expired, please enter a new one below"/>
|
||||
<span ng-if="!app.isPasswordExpiredSecurity()"><var:string label:value="Your password has expired, please enter a new one below"/></span>
|
||||
<span ng-if="app.isPasswordExpiredSecurity()"><var:string label:value="Your password is too weak. Please choose a stronger password to enhance your security"/></span>
|
||||
</div>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding" ng-if="app.isInPasswordRecoveryMode()">
|
||||
<var:string label:value="Please enter a new password below"/>
|
||||
</div>
|
||||
<div flex="100">
|
||||
<div layout="row" layout-xs="column">
|
||||
<md-input-container class="md-block" flex="flex" ng-if="!app.isInPasswordRecoveryMode()">
|
||||
<md-input-container class="md-block" flex="flex" ng-if="!(app.isInPasswordRecoveryMode())">
|
||||
<label><var:string label:value="Current password"/>
|
||||
</label>
|
||||
<input type="password" sg-no-dirty-check="true" ng-model="app.passwords.oldPassword"/>
|
||||
@@ -227,6 +233,13 @@
|
||||
<label><var:string label:value="New password"/>
|
||||
</label>
|
||||
<input type="password" sg-no-dirty-check="true" ng-model="app.passwords.newPassword"/>
|
||||
<div class="sg-hint">
|
||||
<ul class="sg-padded">
|
||||
<li ng-repeat="item in app.passwordPolicy">
|
||||
{{ item.label }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block" flex="flex">
|
||||
<label><var:string label:value="Confirmation"/>
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
@charset "UTF-8";.ng-cloak,.x-ng-cloak,[data-ng-cloak],[ng-cloak],[ng\:cloak],[x-ng-cloak]{display:none!important}.sg-hide{opacity:0}@-moz-document url-prefix(){[layout-fill]{margin:0;width:100%;min-height:100%;height:100%}}[flex-order]{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}[flex-order="-20"]{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}[flex-order="-19"]{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}[flex-order="-18"]{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}[flex-order="-17"]{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}[flex-order="-16"]{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}[flex-order="-15"]{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}[flex-order="-14"]{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}[flex-order="-13"]{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}[flex-order="-12"]{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}[flex-order="-11"]{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}[flex-order="-10"]{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}[flex-order="-9"]{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}[flex-order="-8"]{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}[flex-order="-7"]{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}[flex-order="-6"]{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}[flex-order="-5"]{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}[flex-order="-4"]{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}[flex-order="-3"]{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}[flex-order="-2"]{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}[flex-order="-1"]{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}[flex-order="0"]{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}[flex-order="1"]{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}[flex-order="2"]{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}[flex-order="3"]{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}[flex-order="4"]{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}[flex-order="5"]{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}[flex-order="6"]{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}[flex-order="7"]{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}[flex-order="8"]{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}[flex-order="9"]{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}[flex-order="10"]{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}[flex-order="11"]{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}[flex-order="12"]{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}[flex-order="13"]{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}[flex-order="14"]{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}[flex-order="15"]{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}[flex-order="16"]{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}[flex-order="17"]{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}[flex-order="18"]{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}[flex-order="19"]{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}[flex-order="20"]{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}[flex-offset="0"]{margin-left:0}[flex-offset="5"]{margin-left:5%}[flex-offset="10"]{margin-left:10%}[flex-offset="15"]{margin-left:15%}[flex-offset="20"]{margin-left:20%}[flex-offset="25"]{margin-left:25%}[flex-offset="30"]{margin-left:30%}[flex-offset="35"]{margin-left:35%}[flex-offset="40"]{margin-left:40%}[flex-offset="45"]{margin-left:45%}[flex-offset="50"]{margin-left:50%}[flex-offset="55"]{margin-left:55%}[flex-offset="60"]{margin-left:60%}[flex-offset="65"]{margin-left:65%}[flex-offset="70"]{margin-left:70%}[flex-offset="75"]{margin-left:75%}[flex-offset="80"]{margin-left:80%}[flex-offset="85"]{margin-left:85%}[flex-offset="90"]{margin-left:90%}[flex-offset="95"]{margin-left:95%}[flex-offset="33"]{margin-left:33.3333333333%}[flex-offset="66"]{margin-left:66.6666666667%}[layout-align="start stretch"],[layout-align]{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}[layout-align="start center"],[layout-align="start end"],[layout-align="start start"],[layout-align="start stretch"],[layout-align=start]{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}[layout-align="center center"],[layout-align="center end"],[layout-align="center start"],[layout-align="center stretch"],[layout-align=center]{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}[layout-align="end center"],[layout-align="end end"],[layout-align="end start"],[layout-align="end stretch"],[layout-align=end]{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}[layout-align="spacLine truncated
|
||||
@charset "UTF-8";.ng-cloak,.x-ng-cloak,[data-ng-cloak],[ng-cloak],[ng\:cloak],[x-ng-cloak]{display:none!important}.sg-hide{opacity:0}@-moz-document url-prefix(){[layout-fill]{margin:0;width:100%;min-height:100%;height:100%}}[flex-order]{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}[flex-order="-20"]{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}[flex-order="-19"]{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}[flex-order="-18"]{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}[flex-order="-17"]{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}[flex-order="-16"]{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}[flex-order="-15"]{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}[flex-order="-14"]{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}[flex-order="-13"]{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}[flex-order="-12"]{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}[flex-order="-11"]{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}[flex-order="-10"]{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}[flex-order="-9"]{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}[flex-order="-8"]{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}[flex-order="-7"]{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}[flex-order="-6"]{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}[flex-order="-5"]{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}[flex-order="-4"]{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}[flex-order="-3"]{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}[flex-order="-2"]{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}[flex-order="-1"]{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}[flex-order="0"]{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}[flex-order="1"]{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}[flex-order="2"]{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}[flex-order="3"]{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}[flex-order="4"]{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}[flex-order="5"]{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}[flex-order="6"]{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}[flex-order="7"]{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}[flex-order="8"]{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}[flex-order="9"]{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}[flex-order="10"]{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}[flex-order="11"]{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}[flex-order="12"]{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}[flex-order="13"]{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}[flex-order="14"]{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}[flex-order="15"]{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}[flex-order="16"]{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}[flex-order="17"]{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}[flex-order="18"]{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}[flex-order="19"]{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}[flex-order="20"]{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}[flex-offset="0"]{margin-left:0}[flex-offset="5"]{margin-left:5%}[flex-offset="10"]{margin-left:10%}[flex-offset="15"]{margin-left:15%}[flex-offset="20"]{margin-left:20%}[flex-offset="25"]{margin-left:25%}[flex-offset="30"]{margin-left:30%}[flex-offset="35"]{margin-left:35%}[flex-offset="40"]{margin-left:40%}[flex-offset="45"]{margin-left:45%}[flex-offset="50"]{margin-left:50%}[flex-offset="55"]{margin-left:55%}[flex-offset="60"]{margin-left:60%}[flex-offset="65"]{margin-left:65%}[flex-offset="70"]{margin-left:70%}[flex-offset="75"]{margin-left:75%}[flex-offset="80"]{margin-left:80%}[flex-offset="85"]{margin-left:85%}[flex-offset="90"]{margin-left:90%}[flex-offset="95"]{margin-left:95%}[flex-offset="33"]{margin-left:33.3333333333%}[flex-offset="66"]{margin-left:66.6666666667%}[layout-align="start stretch"],[layout-align]{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}[layout-align="start center"],[layout-align="start end"],[layout-align="start start"],[layout-align="start stretch"],[layout-align=start]{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}[layout-align="center center"],[layout-align="center end"],[layout-align="center start"],[layout-align="center stretch"],[layout-align=center]{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}[layout-align="end center"],[layout-align="end end"],[layout-align="end start"],[layout-align="end stretch"],[layout-align=end]{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}[layout-align="spacLine truncated
|
||||
/*# sourceMappingURL=styles.css.map */
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"sources":["css/styles.css"],"names":[],"mappings":"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 truncated
|
||||
{"version":3,"sources":["css/styles.css"],"names":[],"mappings":"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 truncated
|
||||
@@ -149,12 +149,20 @@
|
||||
perr == passwordPolicyConfig.PolicyChangeAfterReset) {
|
||||
response = {
|
||||
passwordexpired: 1,
|
||||
userPolicies: data.additionalInfos.userPolicies,
|
||||
url: redirectUrl(username, domain)
|
||||
};
|
||||
}
|
||||
else if (perr == passwordPolicyConfig.PolicyChangeAfterReset) {
|
||||
response = {
|
||||
passwordexpired: 1,
|
||||
userPolicies: data.additionalInfos.userPolicies,
|
||||
url: redirectUrl(username, domain)
|
||||
};
|
||||
} else if (perr == passwordPolicyConfig.PolicyInsufficientPasswordQuality) {
|
||||
response = {
|
||||
passwordexpired: 2,
|
||||
userPolicies: data.additionalInfos.userPolicies,
|
||||
url: redirectUrl(username, domain)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
!function(){"use strict";function c(e){var t=this;"function"!=typeof e.then&&(angular.extend(this,e),_.forEach(this.identities,function(e){var t;e.fullName&&e.email?e.full=e.fullName+" <"+e.email+">":e.email?e.full="<"+e.email+">":e.full="",e.signature&&(t=angular.element("<div>"+e.signature+"</div>"),e.textSignature=_.map(t.contents(),"textContent").join(" ").trim())}),this.$mailboxes)&&c.$Mailbox.$unwrapCollection(this,c.$q.when({mailboxes:this.$mailboxes})).then(function(e){t.$mailboxes=e})}c.$factory=["$q","$timeout","$log","sgSettings","Resource","Preferences","Mailbox","Message",function(e,t,s,n,i,a,o,r){return angular.extend(c,{$q:e,$timeout:t,$log:s,$$resource:new i(n.activeUser("folderURL")+"Mail",n.activeUser()),$Preferences:a,$Mailbox:o,$Message:r}),c}];try{angular.module("SOGo.MailerUI")}catch(e){angular.module("SOGo.MailerUI",["SOGo.Common"])}angular.module("SOGo.MailerUI").factory("Account",c.$factory),c.$findAll=function(e){return e?c.$unwrapCollection(e):c.$accounts?c.$q.when(c.$accounts):c.$$resource.fetch("","mailAccounts").then(function(e){return c.$unwrapCollection(e)})},c.$unwrapCollection=function(e){var s=[];return angular.forEach(e,function(e,t){e.id=t,s[t]=new c(e)}),c.$accounts=s},c.refreshUnseenCount=function(e){var t,s=1===c.$Preferences.defaults.SOGoMailFetchAllUnseenCountFolders,n=c.$Preferences.defaults.SOGoRefreshViewCheck;if(s)t=[];else{if(!e)throw Error("SOGoMailFetchAllUnseenCountFolders is disabled and no folders list provided");t=e}_.forEach(c.$accounts,function(e){s?_.forEach(e.$$flattenMailboxes,function(e){t.push(e.id)}):(_.includes(t,e.id+"/folderINBOX")||t.push(e.id+"/folderINBOX"),_.forEach(e.$$flattenMailboxes,function(e){angular.isDefined(e.unseenCount)&&!_.includes(t,e.id)&&t.push(e.id)}))}),c.$$resource.post("","unseenCount",{mailboxes:t}).then(function(t){_.forEach(c.$accounts,function(e){_.forEach(e.$$flattenMailboxes,function(e){angular.isDefined(t[e.id])&&(e.unseenCount=t[e.id])})})}),n&&"manually"!=n&&(c.$refreshUnseenCount&&c.$timeout.cancel(c.$refreshUnseenCount),c.$refreshUnseenCount=c.$timeout(angular.bind(this,c.refreshUnseenCount,e),1e3*n.timeInterval()))},c.prototype.getLength=function(){return this.$expanded?this.$flattenMailboxes().length:0},c.prototype.getItemAtIndex=function(e){var t=this.$flattenMailboxes();return 0<=e&&e<t.length?t[e]:null},c.prototype.$getMailboxes=function(e){var a=this,t=e&&e.reload;return this.$mailboxes&&!t?c.$q.when(this.$mailboxes):(!t&&this.$futureMailboxesData||(this.$futureMailboxesData=c.$Mailbox.$find(this,e).then(function(e){function s(e){_.forEach(e,function(e){var t=_.find(n,["id",e.id]);t&&(e.unseenCount=t.unseenCount),e.children&&0<e.children.length&&s(e.children)})}var n=a.$flattenMailboxes({all:!0});a.$mailboxes=e,a.$expanded=!1;s(a.$mailboxes);function t(e){_.forEach(e,function(e){e.$expanded=0<=i.indexOf("/"+e.id),e.children&&0<e.children.length&&t(e.children)})}var i;if(c.$Preferences.settings.Mail.ExpandedFolders){if(angular.isString(c.$Preferences.settings.Mail.ExpandedFolders))try{i=angular.fromJson(c.$Preferences.settings.Mail.ExpandedFolders)}catch(e){c.$log.warn("Can't parse list of expanded folders. String was: "+c.$Preferences.settings.Mail.ExpandedFolders),i=[]}else i=c.$Preferences.settings.Mail.ExpandedFolders;a.$expanded=0<=i.indexOf("/"+a.id),0<i.length&&t(a.$mailboxes)}return c.$accounts&&(a.$expanded|=1==c.$accounts.length),a.$flattenMailboxes({reload:!0}),a.$mailboxes})),this.$futureMailboxesData)},c.prototype.$flattenMailboxes=function(t){function s(e){_.forEach(e,function(e){n.push(e),(t&&t.all||e.$expanded)&&e.children&&0<e.children.length&&s(e.children)})}var n=[],i=[];return!this.$$flattenMailboxes||t&&(t.reload||t.all)?(s(this.$mailboxes),t&&t.all||(this.$$flattenMailboxes=n,t&&t.saveState&&(_.forEach(c.$accounts,function(e){e.$expanded&&i.push("/"+e.id),_.reduce(e.$$flattenMailboxes,function(e,t){return t.$expanded&&e.push("/"+t.id),e},i)}),c.$$resource.post(null,"saveFoldersState",i)))):n=this.$$flattenMailboxes,n},c.prototype.$getMailboxByType=function(s){function n(e){var t=_.find(e,function(e){return e.type==s});return t||angular.forEach(e,function(e){!t&&e.children&&0<e.children.length&&(t=n(e.children))}),t}return n(this.$mailboxes)},c.prototype.$getMailboxByPath=function(s){function n(e){var t=_.find(e,function(e){return e.path==s});return t||angular.forEach(e,function(e){!t&&e.children&&0<e.children.length&&(t=n(e.children))}),t}var e;if(null==(e=n(this.$mailboxes)))throw Error("No mailbox found matching path "+s);return e},c.prototype.$newMailbox=function(e,t){var s=this;return c.$$resource.post(e.toString(),"createFolder",{name:t}).then(function(){s.$getMailboxes({reload:!0})})},c.prototype.getTextSignature=function(e){var t;return e.signature?(t=angular.element("<div>"+e.signature+"</div>"),e.textSignature=_.map(t.contents(),"textContent").join(" ").trim()):e.textSignature="",e.textSignature},c.prototype.$hasCertificate=function(){return this.security&&this.security.hasCLine truncated
|
||||
!function(){"use strict";function c(e){var t=this;"function"!=typeof e.then&&(angular.extend(this,e),_.forEach(this.identities,function(e){var t;e.fullName&&e.email?e.full=e.fullName+" <"+e.email+">":e.email?e.full="<"+e.email+">":e.full="",e.signature&&(t=angular.element("<div>"+e.signature+"</div>"),e.textSignature=_.map(t.contents(),"textContent").join(" ").trim())}),this.$mailboxes)&&c.$Mailbox.$unwrapCollection(this,c.$q.when({mailboxes:this.$mailboxes})).then(function(e){t.$mailboxes=e})}c.$factory=["$q","$timeout","$log","sgSettings","Resource","Preferences","Mailbox","Message",function(e,t,s,n,i,a,o,r){return angular.extend(c,{$q:e,$timeout:t,$log:s,$$resource:new i(n.activeUser("folderURL")+"Mail",n.activeUser()),$Preferences:a,$Mailbox:o,$Message:r}),c}];try{angular.module("SOGo.MailerUI")}catch(e){angular.module("SOGo.MailerUI",["SOGo.Common"])}angular.module("SOGo.MailerUI").factory("Account",c.$factory),c.$findAll=function(e){return e?c.$unwrapCollection(e):c.$accounts?c.$q.when(c.$accounts):c.$$resource.fetch("","mailAccounts").then(function(e){return c.$unwrapCollection(e)})},c.$unwrapCollection=function(e){var s=[];return angular.forEach(e,function(e,t){e.id=t,s[t]=new c(e)}),c.$accounts=s},c.refreshUnseenCount=function(e){var t,s=1===c.$Preferences.defaults.SOGoMailFetchAllUnseenCountFolders,n=c.$Preferences.defaults.SOGoRefreshViewCheck;if(s)t=[];else{if(!e)throw Error("SOGoMailFetchAllUnseenCountFolders is disabled and no folders list provided");t=e}_.forEach(c.$accounts,function(e){s?_.forEach(e.$$flattenMailboxes,function(e){t.push(e.id)}):(_.includes(t,e.id+"/folderINBOX")||t.push(e.id+"/folderINBOX"),_.forEach(e.$$flattenMailboxes,function(e){angular.isDefined(e.unseenCount)&&!_.includes(t,e.id)&&t.push(e.id)}))}),c.$$resource.post("","unseenCount",{mailboxes:t}).then(function(t){_.forEach(c.$accounts,function(e){_.forEach(e.$$flattenMailboxes,function(e){angular.isDefined(t[e.id])&&(e.unseenCount=t[e.id])})})}),n&&"manually"!=n&&(c.$refreshUnseenCount&&c.$timeout.cancel(c.$refreshUnseenCount),c.$refreshUnseenCount=c.$timeout(angular.bind(this,c.refreshUnseenCount,e),1e3*n.timeInterval()))},c.prototype.getLength=function(){return this.$expanded?this.$flattenMailboxes().length:0},c.prototype.getItemAtIndex=function(e){var t=this.$flattenMailboxes();return 0<=e&&e<t.length?t[e]:null},c.prototype.$getMailboxes=function(e){var a=this,t=e&&e.reload;return this.$mailboxes&&!t?c.$q.when(this.$mailboxes):(!t&&this.$futureMailboxesData||(this.$futureMailboxesData=c.$Mailbox.$find(this,e).then(function(e){function s(e){_.forEach(e,function(e){var t=_.find(n,["id",e.id]);t&&(e.unseenCount=t.unseenCount),e.children&&0<e.children.length&&s(e.children)})}var n=a.$flattenMailboxes({all:!0});a.$mailboxes=e,a.$expanded=!1;s(a.$mailboxes);function t(e){_.forEach(e,function(e){e.$expanded=0<=i.indexOf("/"+e.id),e.children&&0<e.children.length&&t(e.children)})}var i;if(c.$Preferences.settings.Mail.ExpandedFolders){if(angular.isString(c.$Preferences.settings.Mail.ExpandedFolders))try{i=angular.fromJson(c.$Preferences.settings.Mail.ExpandedFolders)}catch(e){c.$log.warn("Can't parse list of expanded folders. String was: "+c.$Preferences.settings.Mail.ExpandedFolders),i=[]}else i=c.$Preferences.settings.Mail.ExpandedFolders;a.$expanded=0<=i.indexOf("/"+a.id),0<i.length&&t(a.$mailboxes)}return c.$accounts&&(a.$expanded|=1==c.$accounts.length),a.$flattenMailboxes({reload:!0}),a.$mailboxes})),this.$futureMailboxesData)},c.prototype.$flattenMailboxes=function(t){function s(e){_.forEach(e,function(e){n.push(e),(t&&t.all||e.$expanded)&&e.children&&0<e.children.length&&s(e.children)})}var n=[],i=[];return!this.$$flattenMailboxes||t&&(t.reload||t.all)?(s(this.$mailboxes),t&&t.all||(this.$$flattenMailboxes=n,t&&t.saveState&&(_.forEach(c.$accounts,function(e){e.$expanded&&i.push("/"+e.id),_.reduce(e.$$flattenMailboxes,function(e,t){return t.$expanded&&e.push("/"+t.id),e},i)}),c.$$resource.post(null,"saveFoldersState",i)))):n=this.$$flattenMailboxes,n},c.prototype.$getMailboxByType=function(s){function n(e){var t=_.find(e,function(e){return e.type==s});return t||angular.forEach(e,function(e){!t&&e.children&&0<e.children.length&&(t=n(e.children))}),t}return n(this.$mailboxes)},c.prototype.$getMailboxByPath=function(s){function n(e){var t=_.find(e,function(e){return e.path==s});return t||angular.forEach(e,function(e){!t&&e.children&&0<e.children.length&&(t=n(e.children))}),t}var e;if(null==(e=n(this.$mailboxes)))throw Error("No mailbox found matching path "+s);return e},c.prototype.$newMailbox=function(e,t){var s=this;return c.$$resource.post(e.toString(),"createFolder",{name:t}).then(function(){s.$getMailboxes({reload:!0})})},c.prototype.getTextSignature=function(e){var t;return e.signature?(t=angular.element("<div>"+e.signature+"</div>"),e.textSignature=_.map(t.contents(),"textContent").join(" ").trim()):e.textSignature="",e.textSignature},c.prototype.$hasCertificate=function(){return this.security&&this.security.hasCLine truncated
|
||||
//# sourceMappingURL=Mailer.services.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"Mailer.services.js","sources":["Mailer/Account.service.js","Mailer/Mailbox.service.js","Mailer/Message.service.js","Mailer/sgImageGallery.service.js","Mailer/VirtualMailbox.service.js","Mailer/MailboxController.js","Mailer/MailboxesController.js","Mailer/MessageController.js","Mailer/MessageEditorController.js","Mailer/sgAccountSection.directive.js","Mailer/sgIMIP.directive.js","Mailer/sgMailboxListItem.directive.js","Mailer/sgMessageListItem.directive.js","Mailer/sgMessageListItemMain.directive.js","Mailer/sgZoomableImage.directive.js"],"names":["Account","futureAccountData","_this","this","then","angular","extend","_","forEach","identities","identity","element","fullName","email","full","signature","textSignature","map","contents","join","trim","$mailboxes","$Mailbox","$unwrapCollection","$q","when","mailboxes","collection","$factory","$timeout","$log","Settings","Resource","Preferences","Mailbox","Message","$$resource","activeUser","$Preferences","$Message","module","e","factory","$findAll","data","$accounts","fetch","o","i","id","refreshUnseenCount","folders","unseenCountFolders","fetchAllUnseenCountFolders","defaults","SOGoMailFetchAllUnseenCountFolders","refreshViewCheck","SOGoRefreshViewCheck","Error","account","$$flattenMailboxes","mailbox","push","includes","isDefined","unseenCount","post","$refreshUnseenCount","cancel","bind","timeInterval","prototype","getLength","$expanded","$flattenMailboxes","length","getItemAtIndex","index","expandedMailboxes","$getMailboxes","options","reload","$futureMailboxesData","$find","_visitForUnseencount","previousMailbox","find","previousMailboxes","children","all","_visitForExpanded","expandedFolders","indexOf","settings","Mail","ExpandedFolders","isString","fromJson","warn","_visit","allMailboxes","saveState","reduce","$getMailboxByType","type","_find","$getMailboxByPath","path","$newMailbox","name","toString","getTextSignature","$hasCertificate","security","hasCertificate","$certificate","$$certificate","reject","$removeCertificate","updateQuota","percent","description","maxQuota","Math","round","usedSpace","l","formatted","maxMessages","messagesCount","$quota","$newMessage","debug","JSON","stringify","undefined","accountId","mailboxPath","message","$absolutePath","asDraft","accountDefaults","AuxiliaryMailAccounts","alwaysSign","sign","alwaysEncrypt","encrypt","editable","isNew","mailto","isObject","$parseMailto","$addDelegate","user","deferred","defer","param","uid","delegates","resolve","users","status","promise","$removeDelegate","splice","$omit","deep","defaultIdentity","value","key","copy","isReadOnly","pick","isDefault","forceDefaultIdentity","futureMailboxData","$account","init","newMailboxData","create","$unwrap","$rootScope","Acl","PRELOAD","BATCH_DELETE_LIMIT","$$Acl","$query","sort","asc","selectedFolder","$refreshTimeout","$virtualMode","$virtualPath","$searchMode","SortingState","parseInt","constant","LOOKAHEAD","SIZE","createMailboxes","level","isSentFolder","isDraftsFolder","quotas","split","component","asCSSIdentifier","isUndefined","uidsMap","headers","$isLoading","$messages","$visibleMessages","$selectedMessages","$highlightWords","$id","$acl","threaded","$collapsedThreads","threadsCollapsed","$displayName","$isEditable","isEditable","$isSpecial","$icon","$isNoInferiors","isNoInferiors","$shadowData","selectFolder","setSearchMode","searchMode","$lastVisibleIndex","max","$loadMessage","selectedMessages","updateCache","filter","selected","selectedCount","$unselectMessages","isSelectedMessage","messageId","$selectedMessage","selectedMessage","$selectedMessageIndex","hasSelectedMessage","$filter","sortingAttributes","filters","action","labels","searchBy","searchInput","word","cleanedWord","toLowerCase","match","secondFilter","$flaggedOnly","$unseenOnly","$syncToken","syncToken","unseenOnly","flaggedOnly","keys","$filteredLabels","k","f","endIndex","uids","startIndex","loaded","subject","min","loading","futureHeadersData","$unwrapHeaders","flags","isNoSelect","isWritable","getClassName","base","$rename","findParent","parent","parentMailbox","$save","_updateChildren","child","replace","pathRE","oldPath","sibling","localeCompare","RegExp","$compact","$canFolderAs","$setFolderAs","$empty","capitalize","substring","$markAsRead","isread","getLabels","$labels","filteredByLabel","$flagMessages","messages","operation","msgUIDs","forwardMessages","saveSelectedMessages","selectedUIDs","download","exportFolder","filename","open","$delete","$_deleteMessages","firstIndex","forEachRight","selectedIndex","findIndex","updateVisibleMessages","$deleteMessages","batchSize","_deleteMessages","start","end","currentUids","slice","$markOrUnMarkMessagesAsJunk","method","$copyMessages","folder","$moveMessages","$move","parentPath","finally","save","response","error","$reset","Object","assign","childrenArray","collapsedThread","msg","first","collapsed","$broadcast","$futureMailboxData","headersFields","msgObject","hasNewMessages","$topIndex","deleted","jLine truncated
|
||||
{"version":3,"file":"Mailer.services.js","sources":["Mailer/Account.service.js","Mailer/Mailbox.service.js","Mailer/Message.service.js","Mailer/sgImageGallery.service.js","Mailer/VirtualMailbox.service.js","Mailer/MailboxController.js","Mailer/MailboxesController.js","Mailer/MessageController.js","Mailer/MessageEditorController.js","Mailer/sgAccountSection.directive.js","Mailer/sgIMIP.directive.js","Mailer/sgMailboxListItem.directive.js","Mailer/sgMessageListItem.directive.js","Mailer/sgMessageListItemMain.directive.js","Mailer/sgZoomableImage.directive.js"],"names":["Account","futureAccountData","_this","this","then","angular","extend","_","forEach","identities","identity","element","fullName","email","full","signature","textSignature","map","contents","join","trim","$mailboxes","$Mailbox","$unwrapCollection","$q","when","mailboxes","collection","$factory","$timeout","$log","Settings","Resource","Preferences","Mailbox","Message","$$resource","activeUser","$Preferences","$Message","module","e","factory","$findAll","data","$accounts","fetch","o","i","id","refreshUnseenCount","folders","unseenCountFolders","fetchAllUnseenCountFolders","defaults","SOGoMailFetchAllUnseenCountFolders","refreshViewCheck","SOGoRefreshViewCheck","Error","account","$$flattenMailboxes","mailbox","push","includes","isDefined","unseenCount","post","$refreshUnseenCount","cancel","bind","timeInterval","prototype","getLength","$expanded","$flattenMailboxes","length","getItemAtIndex","index","expandedMailboxes","$getMailboxes","options","reload","$futureMailboxesData","$find","_visitForUnseencount","previousMailbox","find","previousMailboxes","children","all","_visitForExpanded","expandedFolders","indexOf","settings","Mail","ExpandedFolders","isString","fromJson","warn","_visit","allMailboxes","saveState","reduce","$getMailboxByType","type","_find","$getMailboxByPath","path","$newMailbox","name","toString","getTextSignature","$hasCertificate","security","hasCertificate","$certificate","$$certificate","reject","$removeCertificate","updateQuota","percent","description","maxQuota","Math","round","usedSpace","l","formatted","maxMessages","messagesCount","$quota","$newMessage","debug","JSON","stringify","undefined","accountId","mailboxPath","message","$absolutePath","asDraft","accountDefaults","AuxiliaryMailAccounts","alwaysSign","sign","alwaysEncrypt","encrypt","editable","isNew","mailto","isObject","$parseMailto","$addDelegate","user","deferred","defer","param","uid","delegates","resolve","users","status","promise","$removeDelegate","splice","$omit","deep","defaultIdentity","value","key","copy","isReadOnly","pick","isDefault","forceDefaultIdentity","futureMailboxData","$account","init","newMailboxData","create","$unwrap","$rootScope","Acl","PRELOAD","BATCH_DELETE_LIMIT","$$Acl","$query","sort","asc","selectedFolder","$refreshTimeout","$virtualMode","$virtualPath","$searchMode","SortingState","parseInt","constant","LOOKAHEAD","SIZE","createMailboxes","level","isSentFolder","isDraftsFolder","quotas","split","component","asCSSIdentifier","isUndefined","uidsMap","headers","$isLoading","$messages","$visibleMessages","$selectedMessages","$highlightWords","$id","$acl","threaded","$collapsedThreads","threadsCollapsed","$displayName","$isEditable","isEditable","$isSpecial","$icon","$isNoInferiors","isNoInferiors","$shadowData","selectFolder","setSearchMode","searchMode","$lastVisibleIndex","max","$loadMessage","selectedMessages","updateCache","filter","selected","selectedCount","$unselectMessages","isSelectedMessage","messageId","$selectedMessage","selectedMessage","$selectedMessageIndex","hasSelectedMessage","$filter","sortingAttributes","filters","action","labels","searchBy","searchInput","word","cleanedWord","toLowerCase","match","secondFilter","$flaggedOnly","$unseenOnly","$syncToken","syncToken","unseenOnly","flaggedOnly","keys","$filteredLabels","k","f","endIndex","uids","startIndex","loaded","subject","min","loading","futureHeadersData","$unwrapHeaders","flags","isNoSelect","isWritable","getClassName","base","$rename","findParent","parent","parentMailbox","$save","_updateChildren","child","replace","pathRE","oldPath","sibling","localeCompare","RegExp","$compact","$canFolderAs","$setFolderAs","$empty","capitalize","substring","$markAsRead","isread","getLabels","$labels","filteredByLabel","$flagMessages","messages","operation","msgUIDs","forwardMessages","saveSelectedMessages","selectedUIDs","download","exportFolder","filename","open","$delete","$_deleteMessages","firstIndex","forEachRight","selectedIndex","findIndex","updateVisibleMessages","$deleteMessages","batchSize","_deleteMessages","start","end","currentUids","slice","$markOrUnMarkMessagesAsJunk","method","$copyMessages","folder","$moveMessages","$move","parentPath","finally","save","response","error","$reset","Object","assign","childrenArray","collapsedThread","msg","first","collapsed","$broadcast","$futureMailboxData","headersFields","msgObject","hasNewMessages","$topIndex","deleted","jLine truncated
|
||||
@@ -405,6 +405,7 @@
|
||||
this.$highlightWords = [];
|
||||
filters.forEach(filter => {
|
||||
if ("subject_or_from" == filter.searchBy
|
||||
|| "subject_or_to" == filter.searchBy
|
||||
|| "contains" == filter.searchBy
|
||||
|| "body" == filter.searchBy
|
||||
|| "from" == filter.searchBy
|
||||
@@ -1312,4 +1313,21 @@
|
||||
Mailbox.prototype.getHighlightWords = function () {
|
||||
return this.$highlightWords;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function cleanMailbox
|
||||
* @memberof Mailbox.prototype
|
||||
* @desc Cleans up the mailbox by applying the specified parameters.
|
||||
* This can include operations such as moving emails to trash,
|
||||
* filtering emails based on a duration, and applying actions to subfolders.
|
||||
* @param {Object} parameters - An object containing the parameters for cleaning the mailbox.
|
||||
* @param {boolean} [parameters.applyToSubfolders=false] - Whether to apply the cleaning operation to subfolders.
|
||||
* @param {boolean} [parameters.moveToTrash=false] - Whether to move the emails to the trash folder.
|
||||
* @param {string|null} [parameters.filterDuration=null] - A duration filter (e.g., "3m", "6m") to select emails older than the specified duration.
|
||||
* @returns {Promise} A promise that resolves when the cleaning operation is completed, or rejects with an error if the operation fails.
|
||||
*/
|
||||
Mailbox.prototype.cleanMailbox = function (parameters) {
|
||||
return parameters.folders.length > 0 ? Mailbox.$$resource.post(this.id.split("/")[0], 'cleanMailbox', parameters) : Mailbox.$$resource.post(this.id, 'cleanMailbox', parameters);
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -589,9 +589,12 @@
|
||||
});
|
||||
};
|
||||
|
||||
this.moveSelectedMessages = function(dstFolder) {
|
||||
this.moveSelectedMessages = function(dstFolder, message) {
|
||||
var moveSelectedMessage = vm.selectedFolder.hasSelectedMessage();
|
||||
var selectedMessages = vm.selectedFolder.selectedMessages();
|
||||
if (message) {
|
||||
selectedMessages.push(message);
|
||||
}
|
||||
var count = vm.selectedFolder.selectedCount();
|
||||
if (_.size(selectedMessages) > 0)
|
||||
vm.selectedFolder.$moveMessages(selectedMessages, '/' + dstFolder).then(function(index) {
|
||||
|
||||
@@ -53,6 +53,10 @@
|
||||
$rootScope.$on('resetMailAdvancedSearchPanel', function () {
|
||||
vm.reset();
|
||||
});
|
||||
|
||||
$rootScope.$on('showCleanMailboxPanel', function (e, d) {
|
||||
vm.showCleanMailboxPanel(d.folder, d.account);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -447,6 +451,128 @@
|
||||
});
|
||||
};
|
||||
|
||||
this.showCleanMailboxPanel = function (folder, account) {
|
||||
// Close sidenav on small devices
|
||||
if (!$mdMedia(sgConstant['gt-md']))
|
||||
$mdSidenav('left').close();
|
||||
|
||||
$mdDialog.show({
|
||||
template: document.getElementById('cleanMailbox').innerHTML,
|
||||
parent: angular.element(document.body),
|
||||
controller: function () {
|
||||
var dialogCtrl = this;
|
||||
|
||||
this.$onInit = function () {
|
||||
this.mainController = vm;
|
||||
this.folder = folder;
|
||||
this.isMailbox = (folder ? false : true);
|
||||
this.name = folder ? folder.$displayName : account.name;
|
||||
this.loading = false;
|
||||
this.date = null;
|
||||
this.form = {
|
||||
filterDuration: "3m",
|
||||
permanentlyDelete: false,
|
||||
confirmDelete: false,
|
||||
filterDurationDate: null
|
||||
};
|
||||
|
||||
var today = new Date();
|
||||
var maxDate = new Date(today);
|
||||
maxDate.setMonth(today.getMonth() - 3);
|
||||
this.maxDate = maxDate;
|
||||
};
|
||||
|
||||
dialogCtrl.closeDialog = function () {
|
||||
$mdDialog.hide();
|
||||
};
|
||||
|
||||
dialogCtrl.isLoading = function () {
|
||||
return this.loading;
|
||||
}
|
||||
|
||||
dialogCtrl.isWarningDisplayed = function () {
|
||||
return (this.form && this.form.permanentlyDelete);
|
||||
}
|
||||
|
||||
dialogCtrl.isApplyDisabled = function () {
|
||||
return !(!this.loading
|
||||
&& (!this.form.permanentlyDelete || (this.form.permanentlyDelete && this.form.confirmDelete))
|
||||
&& (this.form.filterDuration != 'custom' || (this.form.filterDuration == 'custom' && this.form.filterDurationDate))
|
||||
);
|
||||
}
|
||||
|
||||
dialogCtrl.apply = function () {
|
||||
var folders = [];
|
||||
var i;
|
||||
if (account) {
|
||||
for (i = 0; i < account.$mailboxes.length ; i++) {
|
||||
folders.push(account.$mailboxes[i].id);
|
||||
}
|
||||
this.folder = account.$mailboxes[0];
|
||||
}
|
||||
var date = '';
|
||||
var durationMonth = 12;
|
||||
var date = new Date();
|
||||
switch (this.form.filterDuration) {
|
||||
case '3m':
|
||||
durationMonth = 3;
|
||||
date.setMonth(date.getMonth() - durationMonth);
|
||||
break;
|
||||
case '6m':
|
||||
durationMonth = 6;
|
||||
date.setMonth(date.getMonth() - durationMonth);
|
||||
break;
|
||||
case '9m':
|
||||
durationMonth = 9;
|
||||
date.setMonth(date.getMonth() - durationMonth);
|
||||
break;
|
||||
case '1y':
|
||||
durationMonth = 12;
|
||||
date.setMonth(date.getMonth() - durationMonth);
|
||||
break;
|
||||
case 'custom':
|
||||
date = this.form.filterDurationDate;
|
||||
break;
|
||||
}
|
||||
var year = date.getFullYear();
|
||||
var month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
var day = String(date.getDate()).padStart(2, '0');
|
||||
this.date = `${year}-${month}-${day}`;
|
||||
this.folder.cleanMailbox({
|
||||
'applyToSubfolders': (this.form && this.form.applyToSubfolders) ? this.form.applyToSubfolders : false,
|
||||
'permanentlyDelete': (this.form && this.form.permanentlyDelete) ? this.form.permanentlyDelete : false,
|
||||
'date': this.date,
|
||||
'folders': folders
|
||||
}).then(function (data) {
|
||||
dialogCtrl.loading = true;
|
||||
Mailbox.selectedFolder.$filter({
|
||||
"sort": "date",
|
||||
"asc": false,
|
||||
"match": "OR"
|
||||
}).then(function () {
|
||||
$state.go('mail.account.mailbox', { accountId: vm.accounts[0].id, mailboxId: encodeUriFilter(Mailbox.selectedFolder.path) });
|
||||
dialogCtrl.loading = false;
|
||||
$mdDialog.hide();
|
||||
|
||||
$mdToast.show(
|
||||
$mdToast.simple()
|
||||
.textContent(l('%{0} message(s) deleted', data.nbMessageDeleted))
|
||||
.position(sgConstant.toastPosition)
|
||||
.hideDelay(2000));
|
||||
});
|
||||
}).catch(function () {
|
||||
dialogCtrl.loading = false;
|
||||
$mdDialog.hide();
|
||||
});
|
||||
};
|
||||
},
|
||||
controllerAs: 'dialogCtrl',
|
||||
clickOutsideToClose: false,
|
||||
escapeToClose: false,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
this.delegate = function(account) {
|
||||
$mdDialog.show({
|
||||
templateUrl: account.id + '/delegation', // UI/Templates/MailerUI/UIxMailUserDelegation.wox
|
||||
|
||||
@@ -271,6 +271,14 @@
|
||||
});
|
||||
};
|
||||
|
||||
this.cleanMailbox = function () {
|
||||
// Close sidenav on small devices
|
||||
if (!$mdMedia(sgConstant['gt-md']))
|
||||
$mdSidenav('left').close();
|
||||
|
||||
$rootScope.$broadcast('showCleanMailboxPanel', {folder: this.folder, account: null}); // Show remove old emails panel (broadcast event to MailboxesController)
|
||||
};
|
||||
|
||||
this.emptyJunkFolder = function() {
|
||||
return this.emptyFolder(l('Junk folder emptied'));
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for MainUI (SOGoRootPage) */
|
||||
(function() {
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.MainUI', ['SOGo.Common', 'SOGo.Authentication']);
|
||||
@@ -9,8 +9,8 @@
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
LoginController.$inject = ['$scope', '$window', '$timeout', 'Dialog', '$mdDialog', 'Authentication', 'sgFocus', 'sgRippleClick'];
|
||||
function LoginController($scope, $window, $timeout, Dialog, $mdDialog, Authentication, focus, rippleDo) {
|
||||
LoginController.$inject = ['$scope', '$window', '$timeout', 'Dialog', '$mdDialog', 'Authentication', 'sgFocus', 'sgRippleClick', 'sgConstant', '$mdToast'];
|
||||
function LoginController($scope, $window, $timeout, Dialog, $mdDialog, Authentication, focus, rippleDo, sgConstant, $mdToast) {
|
||||
var vm = this;
|
||||
|
||||
this.$onInit = function () {
|
||||
@@ -69,10 +69,9 @@
|
||||
vm.passwordRecovery.passwordRecoveryEnabled = true;
|
||||
|
||||
vm.loginState = 'passwordchange';
|
||||
vm.showLogin = false;
|
||||
rippleDo('loginContent');
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
vm.retrievePasswordRecoveryEnabled();
|
||||
}
|
||||
@@ -83,14 +82,14 @@
|
||||
el.parentElement.classList.add("md-input-has-value");
|
||||
});
|
||||
}
|
||||
}, 100);
|
||||
|
||||
}, 100);
|
||||
|
||||
};
|
||||
|
||||
this.login = function() {
|
||||
this.login = function () {
|
||||
vm.loginState = 'authenticating';
|
||||
Authentication.login(vm.creds)
|
||||
.then(function(data) {
|
||||
.then(function (data) {
|
||||
|
||||
if (data.totpmissingkey) {
|
||||
vm.loginState = 'totpcode';
|
||||
@@ -107,11 +106,11 @@
|
||||
vm.url = data.url;
|
||||
|
||||
// Let the user see the succesfull message before reloading the page
|
||||
$timeout(function() {
|
||||
$timeout(function () {
|
||||
vm.continueLogin();
|
||||
}, 1000);
|
||||
}
|
||||
}, function(msg) {
|
||||
}, function (msg) {
|
||||
vm.loginState = 'error';
|
||||
|
||||
if (msg.error) {
|
||||
@@ -122,21 +121,22 @@
|
||||
vm.loginState = 'passwordwillexpire';
|
||||
vm.cn = msg.cn;
|
||||
vm.url = msg.url;
|
||||
vm.passwordPolicy = msg.userPolicies ? msg.userPolicies : [];
|
||||
vm.errorMessage = l('You have %{0} logins remaining before your account is locked. Please change your password in the preference dialog.', msg.grace);
|
||||
}
|
||||
else if (msg.expire > 0) {
|
||||
// Password will soon expire
|
||||
var value, string;
|
||||
if (msg.expire > 86400) {
|
||||
value = Math.round(msg.expire/86400);
|
||||
value = Math.round(msg.expire / 86400);
|
||||
string = l("days");
|
||||
}
|
||||
else if (msg.expire > 3600) {
|
||||
value = Math.round(msg.expire/3600);
|
||||
value = Math.round(msg.expire / 3600);
|
||||
string = l("hours");
|
||||
}
|
||||
else if (msg.expire > 60) {
|
||||
value = Math.round(msg.expire/60);
|
||||
value = Math.round(msg.expire / 60);
|
||||
string = l("minutes");
|
||||
}
|
||||
else {
|
||||
@@ -148,34 +148,40 @@
|
||||
vm.url = msg.url;
|
||||
vm.errorMessage = l('Your password is going to expire in %{0} %{1}.', value, string);
|
||||
}
|
||||
else if (msg.passwordexpired) {
|
||||
else if (msg.passwordexpired && msg.passwordexpired == 2) {
|
||||
vm.loginState = 'passwordchange';
|
||||
vm.passwordPolicy = msg.userPolicies ? msg.userPolicies : [];
|
||||
vm.url = msg.url;
|
||||
vm.passwordexpired = msg.passwordexpired;
|
||||
} else if (msg.passwordexpired) {
|
||||
vm.loginState = 'passwordchange';
|
||||
vm.passwordPolicy = msg.userPolicies ? msg.userPolicies : [];
|
||||
vm.url = msg.url;
|
||||
vm.passwordexpired = msg.passwordexpired;
|
||||
}
|
||||
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
this.restoreLogin = function() {
|
||||
vm.showLogin = false;
|
||||
this.restoreLogin = function () {
|
||||
if ('SecretQuestion' === vm.passwordRecovery.passwordRecoveryMode) {
|
||||
rippleDo('loginContent');
|
||||
vm.passwordRecoveryInfo();
|
||||
vm.passwordRecoveryAbort();
|
||||
} else {
|
||||
delete vm.creds.verificationCode;
|
||||
vm.passwordRecoveryAbort();
|
||||
}
|
||||
};
|
||||
|
||||
this.continueLogin = function() {
|
||||
this.continueLogin = function () {
|
||||
if ($window.location.href === vm.url)
|
||||
$window.location.reload(true);
|
||||
else
|
||||
$window.location.href = vm.url;
|
||||
};
|
||||
|
||||
this.showAbout = function($event) {
|
||||
this.showAbout = function ($event) {
|
||||
$mdDialog.show({
|
||||
targetEvent: $event,
|
||||
templateUrl: 'aboutBox.html',
|
||||
@@ -184,24 +190,20 @@
|
||||
});
|
||||
AboutDialogController.$inject = ['$mdDialog'];
|
||||
function AboutDialogController($mdDialog) {
|
||||
this.closeDialog = function() {
|
||||
this.closeDialog = function () {
|
||||
$mdDialog.hide();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
this.changeLanguage = function($event) {
|
||||
this.changeLanguage = function ($event) {
|
||||
// Reload page
|
||||
$window.location.href = ApplicationBaseURL + 'login?language=' + this.creds.language;
|
||||
};
|
||||
|
||||
this.hello = function (form) {
|
||||
return !true;
|
||||
}
|
||||
|
||||
this.canChangePassword = function(form) {
|
||||
this.canChangePassword = function (form) {
|
||||
if (this.passwords.newPasswordConfirmation && this.passwords.newPasswordConfirmation.length &&
|
||||
this.passwords.newPassword != this.passwords.newPasswordConfirmation) {
|
||||
this.passwords.newPassword != this.passwords.newPasswordConfirmation) {
|
||||
form.newPasswordConfirmation.$setValidity('newPasswordMismatch', false);
|
||||
return false;
|
||||
}
|
||||
@@ -209,25 +211,29 @@
|
||||
form.newPasswordConfirmation.$setValidity('newPasswordMismatch', true);
|
||||
}
|
||||
if (this.passwords.newPassword && this.passwords.newPassword.length > 0 &&
|
||||
this.passwords.newPasswordConfirmation && this.passwords.newPasswordConfirmation.length &&
|
||||
this.passwords.newPassword == this.passwords.newPasswordConfirmation &&
|
||||
((this.isInPasswordRecoveryMode()) ||
|
||||
(!this.loginState && this.passwords.oldPassword && this.passwords.oldPassword.length > 0) ||
|
||||
this.passwords.newPasswordConfirmation && this.passwords.newPasswordConfirmation.length &&
|
||||
this.passwords.newPassword == this.passwords.newPasswordConfirmation &&
|
||||
((this.isInPasswordRecoveryMode()) ||
|
||||
(!this.loginState && this.passwords.oldPassword && this.passwords.oldPassword.length > 0) ||
|
||||
('passwordchange' == this.loginState && this.passwords.oldPassword && this.passwords.oldPassword.length > 0)
|
||||
))
|
||||
))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
this.changePassword = function() {
|
||||
Authentication.changePassword(this.creds.username, this.creds.domain, this.passwords.newPassword, this.passwords.oldPassword, this.passwordRecovery.passwordRecoveryToken).then(function(data) {
|
||||
this.changePassword = function () {
|
||||
Authentication.changePassword(this.creds.username, this.creds.domain, this.passwords.newPassword, this.passwords.oldPassword, this.passwordRecovery.passwordRecoveryToken).then(function (data) {
|
||||
vm.loginState = 'message';
|
||||
vm.url = data.url;
|
||||
vm.errorMessage = l('The password was changed successfully.');
|
||||
}, function(msg) {
|
||||
vm.loginState = 'error';
|
||||
vm.errorMessage = msg;
|
||||
}, function (msg) {
|
||||
$mdToast.show(
|
||||
$mdToast.simple()
|
||||
.textContent(msg)
|
||||
.position(sgConstant.toastPosition)
|
||||
.hideDelay(2000)
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -260,38 +266,42 @@
|
||||
, this.passwordRecovery.passwordRecoveryMailDomain).then(function () {
|
||||
vm.loginState = 'sendrecoverymail';
|
||||
vm.passwordRecovery.showLoader = false;
|
||||
}, function (msg) {
|
||||
vm.loginState = 'error';
|
||||
vm.errorMessage = msg;
|
||||
}, function (msg) {
|
||||
vm.loginState = 'error';
|
||||
vm.errorMessage = msg;
|
||||
vm.passwordRecovery.showLoader = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.passwordRecoveryCheck = function () {
|
||||
vm.passwordRecovery.showLoader = true;
|
||||
Authentication.passwordRecoveryCheck(this.creds.username, this.creds.domain
|
||||
, this.passwordRecovery.passwordRecoveryMode
|
||||
, this.passwordRecovery.passwordRecoveryQuestionKey
|
||||
, this.passwordRecovery.passwordRecoveryQuestionAnswer
|
||||
, this.passwordRecovery.passwordRecoveryMailDomain).then(function (token) {
|
||||
if ("SecretQuestion" == vm.passwordRecovery.passwordRecoveryMode) {
|
||||
vm.passwordRecovery.passwordRecoveryToken = token;
|
||||
vm.loginState = 'passwordchange';
|
||||
} else if ("SecondaryEmail" == vm.passwordRecovery.passwordRecoveryMode) {
|
||||
vm.loginState = 'sendrecoverymail';
|
||||
}
|
||||
vm.passwordRecovery.showLoader = false;
|
||||
}, function (msg) {
|
||||
vm.loginState = 'error';
|
||||
vm.errorMessage = msg;
|
||||
vm.passwordRecovery.showLoader = false;
|
||||
});
|
||||
, this.passwordRecovery.passwordRecoveryMode
|
||||
, this.passwordRecovery.passwordRecoveryQuestionKey
|
||||
, this.passwordRecovery.passwordRecoveryQuestionAnswer
|
||||
, this.passwordRecovery.passwordRecoveryMailDomain).then(function (token) {
|
||||
if ("SecretQuestion" == vm.passwordRecovery.passwordRecoveryMode) {
|
||||
vm.passwordRecovery.passwordRecoveryToken = token;
|
||||
vm.loginState = 'passwordchange';
|
||||
} else if ("SecondaryEmail" == vm.passwordRecovery.passwordRecoveryMode) {
|
||||
vm.loginState = 'sendrecoverymail';
|
||||
}
|
||||
vm.passwordRecovery.showLoader = false;
|
||||
}, function (msg) {
|
||||
vm.loginState = 'error';
|
||||
vm.errorMessage = msg;
|
||||
vm.passwordRecovery.showLoader = false;
|
||||
});
|
||||
};
|
||||
|
||||
this.isPasswordExpiredSecurity = function () {
|
||||
return (this.passwordexpired && 2 === this.passwordexpired);
|
||||
};
|
||||
|
||||
this.isInPasswordRecoveryMode = function () {
|
||||
return (("SecretQuestion" == this.passwordRecovery.passwordRecoveryMode ||
|
||||
"SecondaryEmail" == this.passwordRecovery.passwordRecoveryMode) &&
|
||||
this.passwordRecovery.passwordRecoveryToken) ? true : false;
|
||||
return (("SecretQuestion" == this.passwordRecovery.passwordRecoveryMode) ||
|
||||
("SecondaryEmail" == this.passwordRecovery.passwordRecoveryMode &&
|
||||
this.passwordRecovery.passwordRecoveryToken)) ? true : false;
|
||||
};
|
||||
|
||||
this.passwordRecoveryAbort = function () {
|
||||
|
||||
@@ -18,6 +18,8 @@ $sg-login-width: grid-step(5);
|
||||
.sg-logo {
|
||||
// Center image
|
||||
margin: auto;
|
||||
margin-top: 60px;
|
||||
margin-bottom: 60px;
|
||||
img {
|
||||
height: 100%;
|
||||
width: grid-step(5);
|
||||
@@ -50,6 +52,13 @@ $sg-login-width: grid-step(5);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.create-account-link {
|
||||
color: rgb(255, 255, 255);
|
||||
font-size: 1em;
|
||||
text-decoration: none;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.password-lost-link {
|
||||
color: rgb(255, 255, 255);
|
||||
font-size: 0.9em;
|
||||
|
||||
@@ -452,6 +452,10 @@ md-dialog md-dialog-actions.sg-mail-editor-attachments {
|
||||
.sogo-raw-html-embed .raw-html-embed__preview-placeholder {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.ck-content p {
|
||||
margin: revert;
|
||||
}
|
||||
}
|
||||
|
||||
// Search highlight
|
||||
@@ -527,4 +531,10 @@ mark {
|
||||
cursor: pointer;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
/* Clean mailbox */
|
||||
|
||||
.clean-mailbox-warn {
|
||||
color: #f44336;
|
||||
}
|
||||
Reference in new issue
Block a user