Compare commits
62
Commits
SOGo-5.12.0
...
fix_pkg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb42f1fd07 | ||
|
|
bc6b849d66 | ||
|
|
51f1521dba | ||
|
|
516606baff | ||
|
|
a782424a30 | ||
|
|
f53d7b73db | ||
|
|
8766b7c6b3 | ||
|
|
8a907737de | ||
|
|
1a6f2825b6 | ||
|
|
9954c3607b | ||
|
|
085fc4a9eb | ||
|
|
e36d0d219b | ||
|
|
c5fb3482e2 | ||
|
|
bc4c9ba0e6 | ||
|
|
54debcf47d | ||
|
|
6d8d4f7c39 | ||
|
|
4b397f68f5 | ||
|
|
fdb88abc12 | ||
|
|
d3e5a004db | ||
|
|
9f4440b07f | ||
|
|
3e61a52673 | ||
|
|
532b8dc202 | ||
|
|
828f85c720 | ||
|
|
aa6575c42b | ||
|
|
1ba83ec57d | ||
|
|
bbc04913b9 | ||
|
|
1dcf475d3b | ||
|
|
1bf955d193 | ||
|
|
264f94b64d | ||
|
|
d7fc5a52b8 | ||
|
|
5f6168d536 | ||
|
|
c792ddb601 | ||
|
|
c31b3f4592 | ||
|
|
f4adf6267d | ||
|
|
aae9e6065f | ||
|
|
20e7c890de | ||
|
|
961702de67 | ||
|
|
3ac01f7051 | ||
|
|
bbd17f5531 | ||
|
|
8c4f56c971 | ||
|
|
1d0b6a622c | ||
|
|
ade923d21d | ||
|
|
54f8af30ce | ||
|
|
5c48745c94 | ||
|
|
4ec3d2091a | ||
|
|
3616e56289 | ||
|
|
47548f0939 | ||
|
|
068f1f3154 | ||
|
|
c88f95586a | ||
|
|
07c75280bb | ||
|
|
0fadd4cb72 | ||
|
|
eb7f551e88 | ||
|
|
148fab9409 | ||
|
|
7c59e6b3bf | ||
|
|
ca425e6752 | ||
|
|
9e431d08a2 | ||
|
|
788ece452b | ||
|
|
696b8eed4d | ||
|
|
ab9f0c1bf1 | ||
|
|
4a68909060 | ||
|
|
1f8dc12929 | ||
|
|
7c6b6743e0 |
No files matched your search
@@ -10,6 +10,7 @@
|
||||
*/obj/
|
||||
.scss-lint-config.yml_
|
||||
ActiveSync/ActiveSync.SOGo
|
||||
API/API.SOGo
|
||||
Documentation/*.docbook
|
||||
Documentation/*.pdf
|
||||
Documentation/*.html
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[submodule "UI/WebServerResources/angular-material"]
|
||||
path = UI/WebServerResources/angular-material
|
||||
url = https://github.com/angular/material
|
||||
url = https://github.com/Alinto/material.git
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
# GNUstep makefile
|
||||
|
||||
include common.make
|
||||
|
||||
BUNDLE_NAME = API
|
||||
|
||||
API_PRINCIPAL_CLASS = SOGoAPIProduct
|
||||
|
||||
API_OBJC_FILES = \
|
||||
SOGoAPIProduct.m \
|
||||
SOGoAPI.m \
|
||||
SOGoAPIVersion.m \
|
||||
SOGoAPIUserFolder.m \
|
||||
SOGoAPIDispatcher.m
|
||||
|
||||
API_RESOURCE_FILES += \
|
||||
product.plist
|
||||
|
||||
API_LANGUAGES = $(SOGO_LANGUAGES)
|
||||
|
||||
API_LOCALIZED_RESOURCE_FILES = Localizable.strings
|
||||
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../SOPE/ -I../SoObjects/
|
||||
|
||||
-include GNUmakefile.preamble
|
||||
include $(GNUSTEP_MAKEFILES)/bundle.make
|
||||
-include GNUmakefile.postamble
|
||||
@@ -0,0 +1,16 @@
|
||||
# compile settings
|
||||
|
||||
ADDITIONAL_CPPFLAGS += \
|
||||
-DSOGO_MAJOR_VERSION=$(MAJOR_VERSION) \
|
||||
-DSOGO_MINOR_VERSION=$(MINOR_VERSION) \
|
||||
-DSOGO_PATCH_VERSION=$(SUBMINOR_VERSION) \
|
||||
-DSOGO_LIBDIR="@\"$(SOGO_LIBDIR)\""
|
||||
|
||||
ADDITIONAL_INCLUDE_DIRS += \
|
||||
-D_GNU_SOURCE -I../SOPE/ -I../SoObjects/
|
||||
|
||||
ADDITIONAL_LIB_DIRS += \
|
||||
-L../SoObjects/SOGo/SOGo.framework/sogo -lSOGo \
|
||||
-L../SOPE/GDLContentStore/$(GNUSTEP_OBJ_DIR)/ -lGDLContentStore \
|
||||
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ -lNGCards \
|
||||
-lEOControl -lNGStreams -lNGMime -lNGExtensions -lNGObjWeb -lWEExtensions
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOPE.
|
||||
|
||||
SOPE is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with SOPE; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
|
||||
@class WOContext;
|
||||
|
||||
@interface SOGoAPI : NSObject
|
||||
- (NSArray *) methodAllowed;
|
||||
- (BOOL) needAuth;
|
||||
- (NSArray *) paramNeeded;
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright (C) todo...
|
||||
*/
|
||||
|
||||
#import <SOGoAPI.h>
|
||||
|
||||
|
||||
@implementation SOGoAPI
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSArray *) methodAllowed
|
||||
{
|
||||
NSArray *result;
|
||||
|
||||
result = [NSArray arrayWithObjects:@"GET",nil];
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL) needAuth
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSArray *) paramNeeded
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param
|
||||
{
|
||||
NSDictionary* result;
|
||||
|
||||
result = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
@"API not defined", @"error",
|
||||
nil];
|
||||
[result autorelease];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@end /* SOGoAPI */
|
||||
Whitespace-only changes.
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014-2015, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <SOGo/WORequest+SOGo.h>
|
||||
#import <SOGo/WOResponse+SOGo.h>
|
||||
|
||||
@class NSCalendarDate;
|
||||
@class NSException;
|
||||
@class NSMutableDictionary;
|
||||
@class NSURL;
|
||||
@class NSNumber;
|
||||
|
||||
static volatile BOOL apiShouldTerminate = NO;
|
||||
|
||||
@interface SOGoAPIDispatcher : NSObject
|
||||
{
|
||||
|
||||
id context;
|
||||
BOOL debugOn;
|
||||
}
|
||||
|
||||
- (NSException *) dispatchRequest: (WORequest*) theRequest
|
||||
inResponse: (WOResponse*) theResponse
|
||||
context: (id) theContext;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "SOGoAPIDispatcher.h"
|
||||
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WOCoreApplication.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGExtensions/NSString+Encoding.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/WORequest+SOGo.h>
|
||||
#import <SOGo/WOResponse+SOGo.h>
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/SOGoOpenIdSession.h>
|
||||
|
||||
|
||||
void handle_api_terminate(int signum)
|
||||
{
|
||||
NSLog(@"Forcing termination of API loop.");
|
||||
apiShouldTerminate = YES;
|
||||
[[WOCoreApplication application] terminateAfterTimeInterval: 1];
|
||||
}
|
||||
|
||||
@implementation SOGoAPIDispatcher
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] apiDebugEnabled];
|
||||
apiShouldTerminate = NO;
|
||||
|
||||
signal(SIGTERM, handle_api_terminate);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) _sendAPIErrorResponse: (WOResponse* ) response
|
||||
withMessage: (NSString *) message
|
||||
withStatus: (unsigned int) status
|
||||
{
|
||||
NSDictionary *msg;
|
||||
msg = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
message, @"error",
|
||||
nil];
|
||||
[response setStatus: status];
|
||||
[response setContent: [msg jsonRepresentation]];
|
||||
}
|
||||
|
||||
- (NSString *) _getActionFromUri: (NSString *) _uri
|
||||
{
|
||||
/*
|
||||
_uri always start with /SOGo/SOGoAPI
|
||||
full _uri example /SOGo/SOGoAPI/Action/subaction1?param1¶m2
|
||||
*/
|
||||
|
||||
NSString *uriWithoutParams, *action, *prefix;
|
||||
NSArray *uriSplits;
|
||||
|
||||
prefix = @"/SOGo/SOGoAPI";
|
||||
action = @"";
|
||||
|
||||
uriWithoutParams = [_uri urlWithoutParameters];
|
||||
if(![uriWithoutParams hasPrefix: prefix])
|
||||
{
|
||||
[self errorWithFormat: @"Uri for API request does not start with /SOGo/SOGoAPI: %@", uriWithoutParams];
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
uriWithoutParams = [uriWithoutParams substringFromIndex:[prefix length]];
|
||||
}
|
||||
|
||||
//remove first and last '/'' if needed
|
||||
if([uriWithoutParams hasPrefix: @"/"])
|
||||
{
|
||||
uriWithoutParams = [uriWithoutParams substringFromIndex:1];
|
||||
}
|
||||
if([uriWithoutParams hasSuffix: @"/"])
|
||||
{
|
||||
uriWithoutParams = [uriWithoutParams substringToIndex:([uriWithoutParams length] -1)];
|
||||
}
|
||||
if([uriWithoutParams length] == 0)
|
||||
{
|
||||
[self warnWithFormat: @"Uri for API request has no action, make Version instead: %@", uriWithoutParams];
|
||||
return @"SOGoAPIVersion";
|
||||
}
|
||||
else
|
||||
{
|
||||
uriSplits = [uriWithoutParams componentsSeparatedByString: @"/"];
|
||||
action = [@"SOGoAPI" stringByAppendingString: [uriSplits objectAtIndex: 0]];
|
||||
if(debugOn)
|
||||
[self logWithFormat: @"API request, action made is %@", action];
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
- (NSDictionary *) _authBasicCheck: (NSString *) auth
|
||||
{
|
||||
NSDictionary *user;
|
||||
NSRange rng;
|
||||
NSString *decodeCred, *domain, *login, *pwd;
|
||||
SOGoUserManager *lm;
|
||||
SOGoPasswordPolicyError perr;
|
||||
int expire, grace;
|
||||
BOOL rc;
|
||||
|
||||
user = nil;
|
||||
|
||||
decodeCred = [[auth substringFromIndex:5] stringByTrimmingLeadWhiteSpaces];
|
||||
decodeCred = [decodeCred stringByDecodingBase64];
|
||||
|
||||
rng = [decodeCred rangeOfString:@":"];
|
||||
login = [decodeCred substringToIndex:rng.location];
|
||||
pwd = [decodeCred substringFromIndex:(rng.location + rng.length)];
|
||||
|
||||
domain = nil;
|
||||
perr = PolicyNoError;
|
||||
rc = ([[SOGoUserManager sharedUserManager]
|
||||
checkLogin: [login stringByReplacingString: @"%40"
|
||||
withString: @"@"]
|
||||
password: pwd
|
||||
domain: &domain
|
||||
perr: &perr
|
||||
expire: &expire
|
||||
grace: &grace
|
||||
additionalInfo: nil]
|
||||
&& perr == PolicyNoError);
|
||||
|
||||
if(rc)
|
||||
{
|
||||
//Fecth user info
|
||||
lm = [SOGoUserManager sharedUserManager];
|
||||
user = [lm contactInfosForUserWithUIDorEmail: login];
|
||||
}
|
||||
else
|
||||
user = nil;
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
- (NSDictionary *) _authOpenId: (NSString *) auth withDomain: (NSString *) domain
|
||||
{
|
||||
NSDictionary *user;
|
||||
NSString *token, *login;
|
||||
SOGoOpenIdSession *openIdSession;
|
||||
SOGoUserManager *lm;
|
||||
|
||||
user = nil;
|
||||
token = [[auth substringFromIndex:6] stringByTrimmingLeadWhiteSpaces];
|
||||
|
||||
openIdSession = [SOGoOpenIdSession OpenIdSession: domain];
|
||||
if(![openIdSession sessionIsOk])
|
||||
{
|
||||
[self errorWithFormat: @"API - OpenId server not found or has unexpected behavior, contact your admin."];
|
||||
return nil;
|
||||
}
|
||||
|
||||
[openIdSession setAccessToken: token];
|
||||
login = [openIdSession login: @""];
|
||||
|
||||
if(login && ![login isEqualToString: @"anonymous"])
|
||||
{
|
||||
//Fecth user info
|
||||
lm = [SOGoUserManager sharedUserManager];
|
||||
user = [lm contactInfosForUserWithUIDorEmail: login];
|
||||
}
|
||||
else
|
||||
user = nil;
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
- (NSException *) dispatchRequest: (WORequest*) theRequest
|
||||
inResponse: (WOResponse*) theResponse
|
||||
context: (id) theContext
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
id activeUser;
|
||||
NSString *method, *action, *error;
|
||||
NSDictionary *form;
|
||||
NSArray *paramNeeded;
|
||||
NSMutableDictionary *paramInjected, *ret;
|
||||
NSBundle *bundle;
|
||||
id classAction;
|
||||
Class clazz;
|
||||
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
ASSIGN(context, theContext);
|
||||
|
||||
//Get the api action, check it
|
||||
action = [self _getActionFromUri: [theRequest uri]];
|
||||
if(!action)
|
||||
{
|
||||
error = [NSString stringWithFormat: @"No actions found for request to API: %@", [theRequest uri]];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 400];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
|
||||
//Get the class for this action, check it
|
||||
bundle = [NSBundle bundleForClass: NSClassFromString(@"SOGoAPIProduct")];
|
||||
clazz = [bundle classNamed: action];
|
||||
if(!clazz)
|
||||
{
|
||||
error = [NSString stringWithFormat: @"No backend API found for action: %@", action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 400];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
|
||||
//try to instantiate the class
|
||||
NS_DURING
|
||||
{
|
||||
classAction = [[clazz alloc] init];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Can't alloc and init class: %@", classAction];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 500];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
|
||||
//Check method
|
||||
method = [theRequest method];
|
||||
if(![[classAction methodAllowed] containsObject: method])
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Method %@ not allowed for action %@", method, action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 400];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
paramInjected = [NSMutableDictionary dictionary];
|
||||
//Check parameters
|
||||
if((paramNeeded = [classAction paramNeeded]) && [paramNeeded count] >= 1)
|
||||
{
|
||||
NSDictionary* formAndQuery = [theRequest formValues];
|
||||
for(NSString *param in paramNeeded)
|
||||
{
|
||||
id value;
|
||||
if((value = [formAndQuery objectForKey: param]))
|
||||
{
|
||||
NSString* trueValue;
|
||||
if ([value isKindOfClass: [NSArray class]])
|
||||
trueValue = [value lastObject];
|
||||
else
|
||||
trueValue = value;
|
||||
[paramInjected setObject: trueValue forKey: param];
|
||||
}
|
||||
else
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Missing param %@ for action %@", param, action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 400];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if([classAction needAuth])
|
||||
{
|
||||
if(debugOn)
|
||||
[self logWithFormat: @"Check auth for action %@", action];
|
||||
//check auth
|
||||
NSString *auth = [theRequest headerForKey: @"authorization"];
|
||||
if(auth)
|
||||
{
|
||||
NSDictionary* user;
|
||||
if([[auth lowercaseString] hasPrefix: @"basic"])
|
||||
{
|
||||
//basic auth
|
||||
user = [self _authBasicCheck: auth];
|
||||
}
|
||||
else if([[auth lowercaseString] hasPrefix: @"bearer"])
|
||||
{
|
||||
//openid auth, we may need to know the user-domain to know which openid server to fetch
|
||||
NSString *domain = [theRequest headerForKey: @"user-domain"];
|
||||
user = [self _authOpenId: auth withDomain: domain];
|
||||
}
|
||||
else
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Authorization method incorrect: %@ for action %@", auth, action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 401];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
|
||||
//add current user in paramInjected
|
||||
if(user){
|
||||
if(debugOn)
|
||||
[self logWithFormat: @"User authenticated %@", user];
|
||||
[paramInjected setObject: user forKey: @"user"];
|
||||
}
|
||||
else
|
||||
{
|
||||
error = [NSString stringWithFormat: @"User wrong login or not found for action %@", action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 401];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = [NSString stringWithFormat: @"No authorization header found for action %@", action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 401];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
//Execute action
|
||||
// NS_DURING
|
||||
// {
|
||||
ret = [classAction action: context withParam: paramInjected];
|
||||
// }
|
||||
// NS_HANDLER
|
||||
// {
|
||||
// error = [NSString stringWithFormat: @"Internal error during: %@", action];
|
||||
// [self errorWithFormat: error];
|
||||
// [self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 500];
|
||||
// RELEASE(context);
|
||||
// RELEASE(pool);
|
||||
// return nil;
|
||||
// }
|
||||
// NS_ENDHANDLER;
|
||||
|
||||
|
||||
//Make the response
|
||||
[theResponse setContent: [ret jsonRepresentation]];
|
||||
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Copyright (C) todo...
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@interface SOGoAPIProduct : NSObject
|
||||
@end
|
||||
|
||||
@implementation SOGoAPIProduct
|
||||
@end /* SOGoAPIProduct */
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOPE.
|
||||
|
||||
SOPE is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with SOPE; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <SOGoAPI.h>
|
||||
|
||||
@class WOContext;
|
||||
|
||||
@interface SOGoAPIUserFolder : SOGoAPI
|
||||
- (NSArray *) methodAllowed;
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param;
|
||||
@end
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright (C) todo...
|
||||
*/
|
||||
|
||||
#import <SOGoAPIUserFolder.h>
|
||||
|
||||
#import <GDLContentStore/GCSFolderManager.h>
|
||||
#import <GDLContentStore/GCSFolder.h>
|
||||
|
||||
@implementation SOGoAPIUserFolder
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
|
||||
|
||||
{
|
||||
"calendar":[
|
||||
{
|
||||
"name":"DidyShared",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Calendar/12509-67F67D00-1-3105AF40"
|
||||
},
|
||||
{
|
||||
"name":"LocalDidy",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Calendar/1BC38-67B60000-1-6E4B6880"
|
||||
},
|
||||
{
|
||||
"name":"Personal Calendar",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Calendar/personal"
|
||||
}
|
||||
],
|
||||
"username":"sogo-tests1@example.org",
|
||||
"contact":[
|
||||
{
|
||||
"name":"Personal Address Book",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Contacts/personal"
|
||||
}
|
||||
]
|
||||
}
|
||||
**/
|
||||
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param
|
||||
{
|
||||
NSDictionary* result;
|
||||
NSArray *folders;
|
||||
NSMutableArray *cardavLinks, *caldavLinks;
|
||||
NSString *serverUrl, *basePath, *c_uid, *url;
|
||||
GCSFolderManager *fm;
|
||||
GCSFolder *folder;
|
||||
|
||||
int max, i;
|
||||
|
||||
//Should be a user
|
||||
c_uid = [[[param objectForKey: @"user"] objectForKey: @"emails"] objectAtIndex: 0];
|
||||
|
||||
//fetch folders
|
||||
fm = [GCSFolderManager defaultFolderManager];
|
||||
basePath = [NSString stringWithFormat: @"/Users/%@", c_uid];
|
||||
folders = [fm listSubFoldersAndNamesAtPath: basePath recursive: YES];
|
||||
|
||||
//Generate dav link
|
||||
max = [folders count];
|
||||
serverUrl = [[ctx serverURL] absoluteString];
|
||||
|
||||
cardavLinks = [NSMutableArray array];
|
||||
caldavLinks = [NSMutableArray array];
|
||||
serverUrl = [[ctx serverURL] absoluteString];
|
||||
for (i = 0; i < max; i++)
|
||||
{
|
||||
NSMutableDictionary *folderRet;
|
||||
folderRet = [NSMutableDictionary dictionary];
|
||||
folder = [folders objectAtIndex: i];
|
||||
url = [NSString stringWithFormat: @"%@/SOGo/dav/%@/%@", serverUrl, c_uid, [folder objectForKey: @"path"]];
|
||||
[folderRet setObject: url forKey: @"url"];
|
||||
[folderRet setObject: [folder objectForKey: @"name"] forKey: @"name"];
|
||||
if([url rangeOfString:@"/Calendar/"].location == NSNotFound)
|
||||
{
|
||||
//Contacts
|
||||
[cardavLinks addObject: folderRet];
|
||||
}
|
||||
else
|
||||
{
|
||||
//Calendar
|
||||
[caldavLinks addObject: folderRet];
|
||||
}
|
||||
}
|
||||
|
||||
result = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
c_uid, @"username",
|
||||
cardavLinks, @"contact",
|
||||
caldavLinks, @"calendar",
|
||||
nil];
|
||||
|
||||
[result autorelease];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@end /* SOGoAPIVersion */
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOPE.
|
||||
|
||||
SOPE is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with SOPE; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <SOGoAPI.h>
|
||||
|
||||
@class WOContext;
|
||||
|
||||
@interface SOGoAPIVersion : SOGoAPI
|
||||
- (NSArray *) methodAllowed;
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param;
|
||||
@end
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright (C) todo...
|
||||
*/
|
||||
|
||||
#import <SOGoAPIVersion.h>
|
||||
|
||||
|
||||
@implementation SOGoAPIVersion
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL) needAuth
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param
|
||||
{
|
||||
NSDictionary* result;
|
||||
|
||||
result = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
[NSNumber numberWithInt:SOGO_MAJOR_VERSION], @"major",
|
||||
[NSNumber numberWithInt:SOGO_MINOR_VERSION], @"minor",
|
||||
[NSNumber numberWithInt:SOGO_PATCH_VERSION], @"patch",
|
||||
nil];
|
||||
|
||||
[result autorelease];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@end /* SOGoAPIVersion */
|
||||
@@ -0,0 +1,34 @@
|
||||
include ../config.make
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
include ../Version
|
||||
|
||||
NEEDS_GUI=no
|
||||
BUNDLE_EXTENSION = .SOGo
|
||||
BUNDLE_INSTALL_DIR = $(SOGO_LIBDIR)
|
||||
WOBUNDLE_EXTENSION = $(BUNDLE_EXTENSION)
|
||||
WOBUNDLE_INSTALL_DIR = $(BUNDLE_INSTALL_DIR)
|
||||
|
||||
# SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
|
||||
|
||||
ADDITIONAL_INCLUDE_DIRS += \
|
||||
-I.. \
|
||||
-I../.. \
|
||||
-I../../SOPE
|
||||
|
||||
ADDITIONAL_LIB_DIRS += \
|
||||
-L../SoObjects/SOGo/SOGo.framework/Versions/Current/sogo \
|
||||
-L../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L/usr/local/lib \
|
||||
-Wl,-rpath,$(SOGO_SYSLIBDIR)/sogo
|
||||
|
||||
BUNDLE_LIBS += \
|
||||
-lSOGo \
|
||||
-lGDLContentStore \
|
||||
-lGDLAccess \
|
||||
-lNGObjWeb \
|
||||
-lNGCards -lNGMime -lNGLdap \
|
||||
-lNGStreams -lNGExtensions -lEOControl \
|
||||
-lDOM -lSaxObjC -lSBJson
|
||||
|
||||
ADDITIONAL_BUNDLE_LIBS += $(BUNDLE_LIBS)
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
requires = ( MAIN, Appointments, Contacts, Mailer );
|
||||
|
||||
publicResources = ();
|
||||
|
||||
factories = {};
|
||||
|
||||
classes = {
|
||||
SOGoAPI = {
|
||||
protectedBy = "<public>";
|
||||
defaultRoles = {
|
||||
"View" = ( "Authenticated", "PublicUser" );
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
categories = {
|
||||
SOGoAPI = {
|
||||
slots = {
|
||||
};
|
||||
methods = {
|
||||
Version = {
|
||||
protectedBy = "View";
|
||||
pageName = "SOGoAPI";
|
||||
actionName = "sogoVersion";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -2,6 +2,64 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [5.12.1](https://github.com/Alinto/sogo/compare/SOGo-5.12.0...SOGo-5.12.1) (2025-04-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **calendar:** Make the Jitsi meeting room prefix configurable ([4a68909](https://github.com/Alinto/sogo/commit/4a689090607bc6c4e6385202e9fdaef7308a94fe))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **calendar:** Fix typo Jisti × Jitsi ([ab9f0c1](https://github.com/Alinto/sogo/commit/ab9f0c1bf1f8930b9cbbf592efe69c68654f35c2))
|
||||
* **calendar:** properly show the URL property in iCalendar ([eb7f551](https://github.com/Alinto/sogo/commit/eb7f551e88f2c6693354b6c3b617861d4b63a1bb))
|
||||
* **calendar:** put valarm at the end of vevent block to satisfy outlook.office.com which is too lazy to follow the spec ([148fab9](https://github.com/Alinto/sogo/commit/148fab9409abf703f56ae8ed701547f23d685711))
|
||||
* **db:** log an error if the table sogo_folder_info is malformed ([3616e56](https://github.com/Alinto/sogo/commit/3616e562894be63fcdb7007b5f172d99f5ff59eb))
|
||||
* **folder:** fix folders sorting for special folders ([1f8dc12](https://github.com/Alinto/sogo/commit/1f8dc1292924672489a4a1c76f557a9f0bc65662))
|
||||
* **iOS:** iOS 18.4 encodes caldav url and put %40 instead of @ for username. Fix that. ([9e431d0](https://github.com/Alinto/sogo/commit/9e431d08a273f519ff833b15189d2d3ebef4fc79))
|
||||
* **ldap:** update baseDN with correct domain if needed ([ca425e6](https://github.com/Alinto/sogo/commit/ca425e6752fd28d68e35cc4c1b7dd6f7b3c43ab4))
|
||||
* **sieve:** Correctly update default sieve filter for new users ([7c59e6b](https://github.com/Alinto/sogo/commit/7c59e6b3bf4684c2884e5f0bd39009719e5ba1b9))
|
||||
* **smtp:** fix string type ([788ece4](https://github.com/Alinto/sogo/commit/788ece452b80a0270169178d5e596972797d0906))
|
||||
* **tnef:** add protection against malformed winmail.dat ([7c6b674](https://github.com/Alinto/sogo/commit/7c6b6743e017effcc0078c9ebc026d628f4b71af))
|
||||
* **typo:** Fix typo 'attachements' ([#367](https://bugs.sogo.nu/view.php?id=367)) ([4ec3d20](https://github.com/Alinto/sogo/commit/4ec3d2091a8f5c26b4c4463b4fa9c89ef26f63ba))
|
||||
* **ui:** Change angular material to fix issues with Safari iOS 18+ ([068f1f3](https://github.com/Alinto/sogo/commit/068f1f315498c9bc5a0513e62c7a3fd250d974ad))
|
||||
* **ui:** Change angular material to fix issues with Safari iOS 18+ ([07c7528](https://github.com/Alinto/sogo/commit/07c75280bb06816562b1fb5747acf8efa39cb4a0))
|
||||
|
||||
|
||||
### Localization
|
||||
|
||||
* **ar:** Update Arabic translations ([5c48745](https://github.com/Alinto/sogo/commit/5c48745c94380bfa02f36c751b0389e06d676493))
|
||||
* **bg_BG:** Update Bulgarian translations ([1d0b6a6](https://github.com/Alinto/sogo/commit/1d0b6a622c30b8f55ac17db0d131992a733d356b))
|
||||
* **bs_BA:** Update Bosnian translations ([ade923d](https://github.com/Alinto/sogo/commit/ade923d21d409a9bffca609826a630480ea561dc))
|
||||
* **ca:** Update Catalan translations ([8c4f56c](https://github.com/Alinto/sogo/commit/8c4f56c971002c4e0bb9764c0d7c24fc5cfd3a92))
|
||||
* **cy:** Update Welsh translations ([54debcf](https://github.com/Alinto/sogo/commit/54debcf47d5896b58917705ff85bada391a26919))
|
||||
* **es_AR:** Update SpanishArgentina translations ([4b397f6](https://github.com/Alinto/sogo/commit/4b397f68f51f00945cab57bdec77ab5d68e68753))
|
||||
* **eu:** Update Basque translations ([54f8af3](https://github.com/Alinto/sogo/commit/54f8af30cefe4024d6697a35de25fb1d7896785e))
|
||||
* **fi:** Update Finnish translations ([aae9e60](https://github.com/Alinto/sogo/commit/aae9e6065fda25803c37a43ca2e067df88aba166))
|
||||
* **he:** Update Hebrew translations ([f4adf62](https://github.com/Alinto/sogo/commit/f4adf6267d271d91a75d2176424e98862662e9f8))
|
||||
* **hr_HR:** Update Croatian translations ([961702d](https://github.com/Alinto/sogo/commit/961702de6706531817818063a4a96b40862aa05d))
|
||||
* **hu:** Update Hungarian translations ([c31b3f4](https://github.com/Alinto/sogo/commit/c31b3f4592c6564c4f372cf4e63c4be3564c75bf))
|
||||
* **id_ID:** Update Indonesian translations ([5f6168d](https://github.com/Alinto/sogo/commit/5f6168d5365450e40f6e289be694fab5585ba0cc))
|
||||
* **is:** Update Icelandic translations ([c792ddb](https://github.com/Alinto/sogo/commit/c792ddb601830896cd936e21bb69c17f8d11e705))
|
||||
* **it:** Update Italian translations ([d7fc5a5](https://github.com/Alinto/sogo/commit/d7fc5a52b8284594a6be4050b6c56cffc0fea472))
|
||||
* **ja:** Update Japanese translations ([264f94b](https://github.com/Alinto/sogo/commit/264f94b64d5ea1147d45b7040fc5c3c0bc1d368b))
|
||||
* **kk:** Update Kazakh translations ([1bf955d](https://github.com/Alinto/sogo/commit/1bf955d1930caf920c34be8ffb3e46b47eb0f232))
|
||||
* **lt:** Update Lithuanian translations ([bbc0491](https://github.com/Alinto/sogo/commit/bbc04913b9a3219cd31cfcfc4b0ec79fbee76713))
|
||||
* **lv:** Update Latvian translations ([1dcf475](https://github.com/Alinto/sogo/commit/1dcf475d3b0394474950eb73169fcfeab55305cf))
|
||||
* **mk_MK:** Update Macedonian translations ([1ba83ec](https://github.com/Alinto/sogo/commit/1ba83ec57d7e65f6f28542a89222ec58570d5cef))
|
||||
* **nl:** Update Dutch translations ([20e7c89](https://github.com/Alinto/sogo/commit/20e7c890dea0a52925b18be2a5ae09ccd4c23dd9))
|
||||
* **nn_NO:** Update NorwegianNynorsk translations ([828f85c](https://github.com/Alinto/sogo/commit/828f85c7204c86951db4654f2d254a1361ad0d98))
|
||||
* **ro_RO:** Update Romanian translations ([532b8dc](https://github.com/Alinto/sogo/commit/532b8dc2028b1a1db26566df7baa964daf9bd6b7))
|
||||
* **sk:** Update Slovak translations ([d3e5a00](https://github.com/Alinto/sogo/commit/d3e5a004dbdd80c6bba405a34dcbbb28819a0fa7))
|
||||
* **sl_SI:** Update Slovenian translations ([fdb88ab](https://github.com/Alinto/sogo/commit/fdb88abc1251a8763e4c8e5dacf38e3191180fba))
|
||||
* **sr_ME@latin:** Update Montenegrin translations ([aa6575c](https://github.com/Alinto/sogo/commit/aa6575c42b54b27ca9510ea0f02426a7657ed519))
|
||||
* **sr@latin:** Update SerbianLatin translations ([9f4440b](https://github.com/Alinto/sogo/commit/9f4440b07f142cc0c68561b4413e56fe5c5322ff))
|
||||
* **sr:** Update Serbian translations ([3e61a52](https://github.com/Alinto/sogo/commit/3e61a52673092c38ce2f7a32ebd855afab61782a))
|
||||
* **sv:** Update Swedish translations ([6d8d4f7](https://github.com/Alinto/sogo/commit/6d8d4f7c39fb1c1e9373a9268589b8e6546617ed))
|
||||
* **zh_CN:** Update ChineseChina translations ([bbd17f5](https://github.com/Alinto/sogo/commit/bbd17f55310e5b2e163eeaaf2cb259ae042f8557))
|
||||
* **zh_TW:** Update ChineseTaiwan translations ([3ac01f7](https://github.com/Alinto/sogo/commit/3ac01f70516a25f6db65ffa5c03d6d5a833479fe))
|
||||
|
||||
## [5.12.0](https://github.com/Alinto/sogo/compare/SOGo-5.11.2...SOGo-5.12.0) (2025-03-24)
|
||||
|
||||
|
||||
|
||||
@@ -193,6 +193,9 @@ should apply to all supported operating systems.
|
||||
Software Downloads
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**In order to access the community build, go to https://www.sogo.nu/download.html[SOGo website]
|
||||
and select "Development (nightly builds)" at the bottom of the page.**
|
||||
|
||||
[NOTE]
|
||||
In order to access the production builds, you need a proper support contract
|
||||
from https://sogo.nu/support/index_new.html#support-plans[Alinto]. Continue
|
||||
@@ -490,6 +493,12 @@ the jitsi server used for creating the meeting link.
|
||||
|
||||
Defaults to `https://meet.jit.si` when unset.
|
||||
|
||||
|D |SOGoCalendarJitsiRoomPrefix
|
||||
|Only used if SOGoCalendarEnableJitsiLink is set to YES. The string for
|
||||
the Jitsi room prefix used for creating the meeting link.
|
||||
|
||||
Defaults to `SOGo_meeting/` when unset.
|
||||
|
||||
|S |SOGoSAML2PrivateKeyLocation
|
||||
|The location of the SSL private key file on the filesystem that is used
|
||||
by SOGo to sign and encrypt communications with the SAML2 identity
|
||||
@@ -1606,7 +1615,7 @@ Defaults to `0` when unset.
|
||||
|
||||
|S |SOGoOpenIdLogoutEnabled
|
||||
|Allow user to end their openId with the webmail. Meaning that will disconnect them from
|
||||
the others applicaitons as well.
|
||||
the others applicaitons as well. The openid server must have a end_session_endpoint.
|
||||
|
||||
Defaults to `NO` when unset.
|
||||
|=======================================================================
|
||||
@@ -2750,7 +2759,7 @@ Defaults to `inline` when unset.
|
||||
|Show recipients or sender full email in mailboxes if set to `YES`. Default value is `NO`.
|
||||
|
||||
|U |SOGoMailHideInlineAttachments
|
||||
|Hide attachements for inline images if set to `YES`. Default value is `NO`.
|
||||
|Hide attachments for inline images if set to `YES`. Default value is `NO`.
|
||||
|
||||
|
||||
|U |SOGoMailCustomFullName
|
||||
|
||||
@@ -9,6 +9,7 @@ SUBPROJECTS = \
|
||||
SoObjects \
|
||||
Main \
|
||||
UI \
|
||||
API \
|
||||
Tools \
|
||||
Tests/Unit \
|
||||
|
||||
|
||||
+14
-3
@@ -383,7 +383,12 @@ static BOOL debugLeaks;
|
||||
if([login isEqualToString: @"changeLanguage"])
|
||||
user = nil;
|
||||
else
|
||||
{
|
||||
//Here the user is expected to be name or name@domain.com
|
||||
//However iOS 18.4 sanitize the caldav url and put %40 instead of @
|
||||
login = [login stringByReplacingOccurrencesOfString: @"%40" withString: @"@"];
|
||||
user = [SOGoUser userWithLogin: login roles: nil];
|
||||
}
|
||||
if (user)
|
||||
userFolder = [$(@"SOGoUserFolder") objectWithName: login
|
||||
inContainer: self];
|
||||
@@ -412,7 +417,7 @@ static BOOL debugLeaks;
|
||||
{
|
||||
id obj;
|
||||
WORequest *request;
|
||||
BOOL isDAVRequest;
|
||||
BOOL isDAVRequest, isAPIRequest;
|
||||
SOGoSystemDefaults *sd;
|
||||
|
||||
/* put locale info into the context in case it's not there */
|
||||
@@ -420,8 +425,14 @@ static BOOL debugLeaks;
|
||||
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
request = [_ctx request];
|
||||
isAPIRequest = [[request requestHandlerKey] isEqualToString:@"SOGoAPI"];
|
||||
isDAVRequest = [[request requestHandlerKey] isEqualToString:@"dav"];
|
||||
if (isDAVRequest || [sd isWebAccessEnabled])
|
||||
if(isAPIRequest && ![_key isEqualToString:@"SOGo"] && ![_key isEqualToString:@"SOGoAPI"])
|
||||
{
|
||||
//The request will be handle by the API Dispatcher
|
||||
obj = nil;
|
||||
}
|
||||
else if (isDAVRequest || [sd isWebAccessEnabled])
|
||||
{
|
||||
if (isDAVRequest)
|
||||
{
|
||||
@@ -451,7 +462,7 @@ static BOOL debugLeaks;
|
||||
{
|
||||
obj = [self lookupUser: _key inContext: _ctx];
|
||||
if (!obj && ![_key isEqualToString: @"public"])
|
||||
obj = [self lookupUser: @"anonymous" inContext: _ctx];
|
||||
obj = [self lookupUser: @"anonymous" inContext: _ctx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
|
||||
- (BOOL)folderExistsAtPath:(NSString *)_path;
|
||||
- (NSArray *)listSubFoldersAtPath:(NSString *)_path recursive:(BOOL)_flag;
|
||||
- (NSArray *)listSubFoldersAndNamesAtPath:(NSString *)_path recursive:(BOOL)_recursive;
|
||||
|
||||
- (NSDictionary *) recordAtPath: (NSString *) _path;
|
||||
- (GCSFolder *)folderAtPath:(NSString *)_path;
|
||||
|
||||
@@ -598,6 +598,27 @@ static BOOL _singleStoreMode = NO;
|
||||
return sql;
|
||||
}
|
||||
|
||||
- (NSString *)generateSQLPathAndNameFetchForInternalNames:(NSArray *)_names
|
||||
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
|
||||
{
|
||||
/* fetches the 'path' subset for a given quick-names */
|
||||
NSMutableString *sql;
|
||||
NSString *ws;
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:_names
|
||||
exactMatch:_beExact orDirectSubfolderMatch:_directSubs];
|
||||
if ([ws length] == 0)
|
||||
return nil;
|
||||
|
||||
sql = [NSMutableString stringWithCapacity:256];
|
||||
[sql appendString:@"SELECT c_path, c_foldername FROM "];
|
||||
[sql appendString:[self folderInfoTableName]];
|
||||
[sql appendString:@" WHERE "];
|
||||
[sql appendString:ws];
|
||||
if (debugSQLGen) [self logWithFormat:@"PathFetch-SQL: %@", sql];
|
||||
return sql;
|
||||
}
|
||||
|
||||
/* handling folder names */
|
||||
|
||||
- (BOOL)_isStandardizedPath:(NSString *)_path {
|
||||
@@ -806,6 +827,72 @@ static BOOL _singleStoreMode = NO;
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSArray *)listSubFoldersAndNamesAtPath:(NSString *)_path recursive:(BOOL)_recursive{
|
||||
NSMutableArray *result;
|
||||
NSString *fname;
|
||||
NSArray *fnames, *records;
|
||||
NSString *sql;
|
||||
unsigned i, count;
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
sql = [self generateSQLPathAndNameFetchForInternalNames:fnames
|
||||
exactMatch:NO orDirectSubfolderMatch:(_recursive ? NO : YES)];
|
||||
if ([sql length] == 0) {
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((count = [records count]) == 0)
|
||||
return emptyArray;
|
||||
|
||||
result = [NSMutableArray arrayWithCapacity:(count > 128 ? 128 : count)];
|
||||
|
||||
fname = [self internalNameFromPath:_path];
|
||||
fname = [fname stringByAppendingString:@"/"]; /* add slash */
|
||||
for (i = 0; i < count; i++) {
|
||||
NSDictionary *record, *folderInfo;
|
||||
NSString *sname, *spath, *foldername;
|
||||
|
||||
record = [records objectAtIndex:i];
|
||||
sname = [record objectForKey:GCSPathRecordName];
|
||||
if (![sname hasPrefix:fname]) /* does not match at all ... */
|
||||
continue;
|
||||
|
||||
/* strip prefix and following slash */
|
||||
sname = [sname substringFromIndex:[fname length]];
|
||||
spath = [self pathPartFromInternalName:sname];
|
||||
|
||||
if (_recursive) {
|
||||
if ([spath length] > 0){
|
||||
foldername = [record objectForKey: @"c_foldername"];
|
||||
folderInfo = [NSDictionary dictionaryWithObjectsAndKeys: spath, @"path", foldername, @"name", nil];
|
||||
[result addObject:folderInfo];
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* direct children only, so exclude everything with a slash */
|
||||
if ([sname rangeOfString:@"/"].length == 0 && [spath length] > 0)
|
||||
{
|
||||
foldername = [record objectForKey: @"c_foldername"];
|
||||
folderInfo = [NSDictionary dictionaryWithObjectsAndKeys: spath, @"path", foldername, @"name", nil];
|
||||
[result addObject:folderInfo];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSDictionary *) recordAtPath: (NSString *) _path
|
||||
{
|
||||
NSMutableString *sql;
|
||||
|
||||
@@ -303,8 +303,8 @@ static NSString *openIdFolderURLString = nil;
|
||||
newRecord = [NSDictionary dictionaryWithObjectsAndKeys: _user_session, @"c_user_session",
|
||||
_old_session, @"c_old_session",
|
||||
[NSNumber numberWithInt:now], @"c_session_started",
|
||||
_refresh_token, @"c_refresh_token",
|
||||
[NSNumber numberWithInt:nowExpire] , @"c_access_token_expires_in",
|
||||
_refresh_token, @"c_refresh_token",
|
||||
[NSNumber numberWithInt:nowRefreshExpire] , @"c_refresh_token_expires_in",
|
||||
nil];
|
||||
record = [self recordForSession: _user_session useOldSession: NO];
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
@" c_old_session VARCHAR(4096) NULL,"
|
||||
@" c_session_started INT4 NOT NULL,"
|
||||
@" c_refresh_token VARCHAR(4096) NULL,"
|
||||
@" c_access_token_expires_in INT4 NOT NULL,"
|
||||
@" c_access_token_expires_in INT4 NULL,"
|
||||
@" c_refresh_token_expires_in INT4 NULL)");
|
||||
|
||||
return [NSString stringWithFormat: sqlFolderFormat, tableName];
|
||||
@@ -379,7 +379,7 @@
|
||||
@" c_old_session VARCHAR(4096) NULL,"
|
||||
@" c_session_started INT4 NOT NULL,"
|
||||
@" c_refresh_token VARCHAR(4096) NULL,"
|
||||
@" c_access_token_expires_in INT4 NOT NULL,"
|
||||
@" c_access_token_expires_in INT4 NULL,"
|
||||
@" c_refresh_token_expires_in INT4 NULL)");
|
||||
|
||||
return [NSString stringWithFormat: sqlFolderFormat, tableName];
|
||||
@@ -540,7 +540,7 @@
|
||||
@" c_old_session VARCHAR2(4096) NULL,"
|
||||
@" c_session_started INTEGER NOT NULL,"
|
||||
@" c_refresh_token VARCHAR2(4096) NULL,"
|
||||
@" c_access_token_expires_in INTEGER NOT NULL,"
|
||||
@" c_access_token_expires_in INTEGER NULL,"
|
||||
@" c_refresh_token_expires_in INTEGER NULL)");
|
||||
|
||||
return [NSString stringWithFormat: sqlFolderFormat, tableName];
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
- (NSArray *) recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
|
||||
{
|
||||
NSMutableArray *ranges;
|
||||
NSCalendarDate *firStart, *startDate, *endDate, *currentStartDate, *currentEndDate;
|
||||
NSCalendarDate *firStart, *firEnd, *startDate, *endDate, *currentStartDate, *currentEndDate;
|
||||
iCalByDayMask *dayMask;
|
||||
long i, count, repeatCount;
|
||||
unsigned interval;
|
||||
@@ -63,6 +63,7 @@
|
||||
//[self logWithFormat: @"Recurrence rule is %@", rrule];
|
||||
|
||||
firStart = [firstRange startDate];
|
||||
firEnd = [firstRange endDate];
|
||||
startDate = [_r startDate];
|
||||
endDate = [_r endDate];
|
||||
dayMask = nil;
|
||||
@@ -84,13 +85,14 @@
|
||||
// If rule is bound, check the bounds
|
||||
if (![rrule isInfinite])
|
||||
{
|
||||
NSCalendarDate *until, *lastDate;
|
||||
NSCalendarDate *until, *lastStartDate, *lastEndDate;
|
||||
|
||||
lastDate = nil;
|
||||
lastStartDate = nil;
|
||||
lastEndDate = nil;
|
||||
until = [rrule untilDate];
|
||||
if (until)
|
||||
{
|
||||
lastDate = until;
|
||||
lastStartDate = until;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -98,20 +100,23 @@
|
||||
if (dayMask == nil)
|
||||
// If there's no day mask, we can compute the date of the last
|
||||
// occurrence of the recurrent rule.
|
||||
lastDate = [firStart dateByAddingYears: 0 months: 0
|
||||
lastStartDate = [firStart dateByAddingYears: 0 months: 0
|
||||
days: (interval
|
||||
* (repeatCount - 1))];
|
||||
lastEndDate = [firEnd dateByAddingYears: 0 months: 0
|
||||
days: (interval
|
||||
* (repeatCount - 1))];
|
||||
}
|
||||
|
||||
if (lastDate != nil)
|
||||
if (lastStartDate != nil && lastEndDate != nil)
|
||||
{
|
||||
if ([lastDate compare: startDate] == NSOrderedAscending)
|
||||
if ([lastEndDate compare: startDate] == NSOrderedAscending)
|
||||
// Range starts after last occurrence
|
||||
return nil;
|
||||
|
||||
if ([lastDate compare: endDate] == NSOrderedAscending)
|
||||
if ([lastStartDate compare: endDate] == NSOrderedAscending)
|
||||
// Range ends after last occurence; adjust end date
|
||||
endDate = lastDate;
|
||||
endDate = lastStartDate;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ static inline unsigned iCalDoWForNSDoW (int dow)
|
||||
// TODO: check whether this is OK for multiday-events!
|
||||
NSMutableArray *ranges;
|
||||
NSTimeZone *timeZone;
|
||||
NSCalendarDate *eventStartDate, *rStart, *rEnd, *until, *referenceDate;
|
||||
NSCalendarDate *eventStartDate, *eventEndDate, *rStart, *rEnd, *untilStart, *untilEnd, *referenceDate;
|
||||
int eventDayOfMonth;
|
||||
unsigned monthIdxInRange, numberOfMonthsInRange, interval, repeatCount;
|
||||
int diff, count;
|
||||
@@ -199,12 +199,14 @@ static inline unsigned iCalDoWForNSDoW (int dow)
|
||||
iCalByDayMask *byDayMask;
|
||||
|
||||
eventStartDate = [firstRange startDate];
|
||||
eventEndDate = [firstRange endDate];
|
||||
eventDayOfMonth = [eventStartDate dayOfMonth];
|
||||
timeZone = [eventStartDate timeZone];
|
||||
rStart = [_r startDate];
|
||||
rEnd = [_r endDate];
|
||||
interval = [rrule repeatInterval];
|
||||
until = nil;
|
||||
untilStart = nil;
|
||||
untilEnd = nil;
|
||||
repeatCount = [rrule repeatCount];
|
||||
byMonth = [rrule byMonth];
|
||||
byMonthDay = [rrule byMonthDay];
|
||||
@@ -218,24 +220,27 @@ static inline unsigned iCalDoWForNSDoW (int dow)
|
||||
{
|
||||
// When there's no BYxxx mask, we can find the date of the last
|
||||
// occurrence.
|
||||
until = [eventStartDate dateByAddingYears: 0
|
||||
untilStart = [eventStartDate dateByAddingYears: 0
|
||||
months: (interval * (repeatCount - 1))
|
||||
days: 0];
|
||||
untilEnd = [eventEndDate dateByAddingYears: 0
|
||||
months: (interval * (repeatCount - 1))
|
||||
days: 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
until = [rrule untilDate];
|
||||
untilStart = [rrule untilDate];
|
||||
}
|
||||
}
|
||||
|
||||
if (until != nil)
|
||||
if (untilStart != nil)
|
||||
{
|
||||
if ([until compare: rStart] == NSOrderedAscending)
|
||||
if ([untilEnd compare: rStart] == NSOrderedAscending)
|
||||
// Range starts after last occurrence
|
||||
return nil;
|
||||
if ([until compare: rEnd] == NSOrderedAscending)
|
||||
if ([untilStart compare: rEnd] == NSOrderedAscending)
|
||||
// Range ends after last occurence; adjust end date
|
||||
rEnd = until;
|
||||
rEnd = untilStart;
|
||||
}
|
||||
|
||||
if (byMonth && [byMonth count] > 0)
|
||||
@@ -441,7 +446,7 @@ static inline unsigned iCalDoWForNSDoW (int dow)
|
||||
|
||||
start = [cursor dateByAddingYears: 0 months: 0 days: (dom - 1)];
|
||||
doCont = [self _addInstanceWithStartDate: start
|
||||
limitDate: until
|
||||
limitDate: untilStart
|
||||
limitRange: _r
|
||||
toArray: ranges];
|
||||
//NSLog(@"*** MONTHLY [%i/%i] adding %@%@ (count = %i)", dom, numDaysInMonth, start, (doCont?@"":@" .. NOT!"), count);
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
- (NSArray *) recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
|
||||
{
|
||||
NSMutableArray *ranges;
|
||||
NSCalendarDate *firStart, *startDate, *endDate, *currentStartDate, *currentEndDate;
|
||||
NSCalendarDate *firStart, *firEnd, *startDate, *endDate, *currentStartDate, *currentEndDate;
|
||||
long i, repeatCount, count;
|
||||
unsigned interval;
|
||||
iCalByDayMask *dayMask;
|
||||
@@ -73,6 +73,7 @@
|
||||
//[self logWithFormat: @"Recurrence rule is %@", rrule];
|
||||
|
||||
firStart = [firstRange startDate];
|
||||
firEnd = [firstRange endDate];
|
||||
startDate = [_r startDate];
|
||||
endDate = [_r endDate];
|
||||
dayMask = nil;
|
||||
@@ -95,31 +96,35 @@
|
||||
// If rule is bound, check the bounds
|
||||
if (![rrule isInfinite])
|
||||
{
|
||||
NSCalendarDate *until, *lastDate;
|
||||
NSCalendarDate *until, *lastStartDate, *lastEndDate;
|
||||
|
||||
lastDate = nil;
|
||||
lastStartDate = nil;
|
||||
lastEndDate = nil;
|
||||
until = [rrule untilDate];
|
||||
if (until)
|
||||
lastDate = until;
|
||||
lastStartDate = until;
|
||||
else
|
||||
{
|
||||
repeatCount = [rrule repeatCount];
|
||||
if (dayMask == nil)
|
||||
// When there's no BYxxx mask, we can find the date of the last
|
||||
// occurrence.
|
||||
lastDate = [firStart dateByAddingYears: 0 months: 0
|
||||
lastStartDate = [firStart dateByAddingYears: 0 months: 0
|
||||
days: (interval
|
||||
* (repeatCount - 1) * 7)];
|
||||
lastEndDate = [firEnd dateByAddingYears: 0 months: 0
|
||||
days: (interval
|
||||
* (repeatCount - 1) * 7)];
|
||||
}
|
||||
|
||||
if (lastDate != nil)
|
||||
if (lastStartDate != nil && lastEndDate != nil)
|
||||
{
|
||||
if ([lastDate compare: startDate] == NSOrderedAscending)
|
||||
if ([lastEndDate compare: startDate] == NSOrderedAscending)
|
||||
// Range starts after last occurrence
|
||||
return nil;
|
||||
if ([lastDate compare: endDate] == NSOrderedAscending)
|
||||
if ([lastStartDate compare: endDate] == NSOrderedAscending)
|
||||
// Range ends after last occurence; adjust end date
|
||||
endDate = [lastDate addTimeInterval: [firstRange duration]];
|
||||
endDate = [lastStartDate addTimeInterval: [firstRange duration]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,13 +44,14 @@
|
||||
{
|
||||
NSMutableArray *ranges;
|
||||
NSArray *byMonth;
|
||||
NSCalendarDate *firStart, *lastDate, *rStart, *rEnd, *until, *referenceDate, *rTemp;
|
||||
NSCalendarDate *firStart, *firEnd, *lastStartDate, *lastEndDate, *rStart, *rEnd, *until, *referenceDate, *rTemp;
|
||||
NSInteger *hoursOfOffset;
|
||||
iCalMonthlyRecurrenceCalculator *monthlyCalc;
|
||||
unsigned j, yearIdxInRange, numberOfYearsInRange, count, interval, monthDiff;
|
||||
int diff, repeatCount, currentMonth, origNbDaysInMonth;
|
||||
|
||||
firStart = [firstRange startDate];
|
||||
firEnd = [firstRange endDate];
|
||||
rStart = [_r startDate];
|
||||
rEnd = [_r endDate];
|
||||
interval = [rrule repeatInterval];
|
||||
@@ -71,33 +72,37 @@
|
||||
// If rule is bound, check the bounds
|
||||
if (![rrule isInfinite])
|
||||
{
|
||||
lastDate = nil;
|
||||
lastStartDate = nil;
|
||||
lastEndDate = nil;
|
||||
until = [rrule untilDate];
|
||||
repeatCount = [rrule repeatCount];
|
||||
|
||||
if (until)
|
||||
{
|
||||
lastDate = until;
|
||||
lastStartDate = until;
|
||||
}
|
||||
if (repeatCount > 0)
|
||||
{
|
||||
if (lastDate == nil && ![rrule hasByMask])
|
||||
if (lastStartDate == nil && ![rrule hasByMask])
|
||||
// When there's no BYxxx mask, we can find the date of the last
|
||||
// occurrence.
|
||||
lastDate = [firStart dateByAddingYears: (interval * (repeatCount - 1))
|
||||
lastStartDate = [firStart dateByAddingYears: (interval * (repeatCount - 1))
|
||||
months: 0
|
||||
days: 0];
|
||||
lastEndDate = [firEnd dateByAddingYears: (interval * (repeatCount - 1))
|
||||
months: 0
|
||||
days: 0];
|
||||
referenceDate = firStart;
|
||||
}
|
||||
|
||||
if (lastDate != nil)
|
||||
if (lastStartDate != nil)
|
||||
{
|
||||
if ([lastDate compare: rStart] == NSOrderedAscending)
|
||||
if ([lastEndDate compare: rStart] == NSOrderedAscending)
|
||||
// Range starts after last occurrence
|
||||
return nil;
|
||||
if ([lastDate compare: rEnd] == NSOrderedAscending)
|
||||
if ([lastStartDate compare: rEnd] == NSOrderedAscending)
|
||||
// Range ends after last occurence; adjust end date
|
||||
rEnd = [lastDate addTimeInterval: [firstRange duration]];
|
||||
rEnd = [lastStartDate addTimeInterval: [firstRange duration]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ CREATE TABLE sogo_opend_id (
|
||||
c_old_session varchar(4096) DEFAULT '',
|
||||
c_session_started int(11) NOT NULL,
|
||||
c_refresh_token varchar(4096) DEFAULT '',
|
||||
c_access_token_expires_in int(11) NOT NULL,
|
||||
c_access_token_expires_in int(11) DEFAULT '',
|
||||
c_refresh_token_expires_in int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (c_user_session)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
@@ -355,12 +355,12 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||
if ([o isKindOfClass: [NSArray class]])
|
||||
[self _setAttendees: o];
|
||||
|
||||
o = [data objectForKey: @"alarm"];
|
||||
if ([o isKindOfClass: [NSDictionary class]])
|
||||
{
|
||||
owner = [data objectForKey: @"owner"];
|
||||
[self _setAlarm: o forOwner: owner];
|
||||
}
|
||||
// o = [data objectForKey: @"alarm"];
|
||||
// if ([o isKindOfClass: [NSDictionary class]])
|
||||
// {
|
||||
// owner = [data objectForKey: @"owner"];
|
||||
// [self _setAlarm: o forOwner: owner];
|
||||
// }
|
||||
|
||||
// Other attributes depend on the client object and therefore are set in [UIxComponentEditor setAttributes:]:
|
||||
// - organizer & "created-by"
|
||||
|
||||
@@ -372,6 +372,7 @@
|
||||
{
|
||||
NSCalendarDate *aptStartDate, *aptEndDate, *allDayStartDate;
|
||||
NSInteger offset, nbrDays;
|
||||
NSString *owner;
|
||||
NSTimeZone *timeZone;
|
||||
iCalDateTime *startDate;
|
||||
iCalTimeZone *tz;
|
||||
@@ -454,6 +455,16 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//To make an ics conforme with outlook live (bouh), valarm must be the last element of vevent
|
||||
//Try to set it here
|
||||
o = [data objectForKey: @"alarm"];
|
||||
if ([o isKindOfClass: [NSDictionary class]])
|
||||
{
|
||||
owner = [data objectForKey: @"owner"];
|
||||
[self _setAlarm: o forOwner: owner];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (iCalTimeZone *) adjustInContext: (WOContext *) context
|
||||
|
||||
@@ -291,6 +291,11 @@ unsigned char GetRruleMonthNum(unsigned char a, unsigned char b) {
|
||||
partName = nil;
|
||||
data = [self fetchBLOB];
|
||||
|
||||
if((int)[data length] < sizeof(DWORD)) {
|
||||
NSLog(@"TNEF: ERROR try to decode empty data where it should'nt");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&signature, [data bytes], sizeof(DWORD));
|
||||
if (TNEFCheckForSignature(signature) == 0)
|
||||
{
|
||||
|
||||
@@ -231,7 +231,7 @@ endif
|
||||
ADDITIONAL_TOOL_LIBS += -Lobj -lSOGo$(LIBRARY_NAME_SUFFIX)
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../../SOPE/
|
||||
ADDITIONAL_LIB_DIRS += -L../../SOPE/GDLContentStore/obj/
|
||||
ADDITIONAL_LDFLAGS += -lmemcached -lzip -lytnef
|
||||
ADDITIONAL_LDFLAGS += -lmemcached -lzip -lytnef -lcurl
|
||||
|
||||
-include GNUmakefile.preamble
|
||||
ifneq ($(FHS_INSTALL_ROOT),)
|
||||
|
||||
@@ -784,6 +784,8 @@ groupObjectClasses: (NSArray *) newGroupObjectClasses
|
||||
|
||||
didChange = NO;
|
||||
|
||||
[self updateBaseDNFromLogin: login];
|
||||
|
||||
NS_DURING
|
||||
if ([login length] > 0)
|
||||
{
|
||||
|
||||
@@ -78,7 +78,8 @@
|
||||
- (BOOL) appointmentSendEMailNotifications;
|
||||
- (BOOL) foldersSendEMailNotifications;
|
||||
- (NSArray *) calendarDefaultRoles;
|
||||
- (NSString *) calendarJistiBaseUrl;
|
||||
- (NSString *) calendarJitsiBaseUrl;
|
||||
- (NSString *) calendarJitsiRoomPrefix;
|
||||
- (NSArray *) contactsDefaultRoles;
|
||||
- (NSArray *) refreshViewIntervals;
|
||||
- (NSString *) subscriptionFolderFormat;
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
return [self stringArrayForKey: @"SOGoCalendarDefaultRoles"];
|
||||
}
|
||||
|
||||
- (NSString *) calendarJistiBaseUrl
|
||||
- (NSString *) calendarJitsiBaseUrl
|
||||
{
|
||||
NSString *jitsiBaseUrl;
|
||||
jitsiBaseUrl = [self stringForKey: @"SOGoCalendarJitsiBaseUrl"];
|
||||
@@ -179,6 +179,16 @@
|
||||
return jitsiBaseUrl;
|
||||
}
|
||||
|
||||
- (NSString *) calendarJitsiRoomPrefix
|
||||
{
|
||||
NSString *jitsiRoomPrefix;
|
||||
jitsiRoomPrefix = [self stringForKey: @"SOGoCalendarJitsiRoomPrefix"];
|
||||
if(!jitsiRoomPrefix)
|
||||
jitsiRoomPrefix = @"SOGo_meeting/";
|
||||
|
||||
return jitsiRoomPrefix;
|
||||
}
|
||||
|
||||
- (NSArray *) contactsDefaultRoles
|
||||
{
|
||||
return [self stringArrayForKey: @"SOGoContactsDefaultRoles"];
|
||||
|
||||
@@ -325,7 +325,7 @@
|
||||
{
|
||||
login = [currentAcount objectForKey: @"userName"];
|
||||
password = [currentAcount objectForKey: @"password"];
|
||||
smtpAuthMethod = "plain"; //Only support plain for auxiliary account
|
||||
smtpAuthMethod = @"plain"; //Only support plain for auxiliary account
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -33,6 +33,25 @@
|
||||
@class NSURL;
|
||||
@class NSJSONSerialization;
|
||||
|
||||
size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer);
|
||||
|
||||
@interface SimpleOpenIdResponse: NSObject
|
||||
{
|
||||
unsigned int status;
|
||||
NSString *content;
|
||||
NSString *headers;
|
||||
}
|
||||
|
||||
- (id)initWithResponse: (NSString *)_data andHeaders: (NSString *)_headers andStatus:(unsigned int )_status;
|
||||
|
||||
- (void)setStatus:(unsigned int)_status;
|
||||
- (unsigned int)status;
|
||||
- (void)setContent:(NSString *)_data;
|
||||
- (NSString *)contentString;
|
||||
- (void)setHearders:(NSString *)_data;
|
||||
- (NSString *)headers;
|
||||
|
||||
@end
|
||||
|
||||
@interface SOGoOpenIdSession : SOGoObject
|
||||
{
|
||||
@@ -47,6 +66,7 @@
|
||||
NSString *openIdClient;
|
||||
NSString *openIdClientSecret;
|
||||
NSString *openIdEmailParam;
|
||||
NSString *openIdHttpVersion;
|
||||
BOOL openIdEnableRefreshToken;
|
||||
BOOL sendDomainInfo;
|
||||
|
||||
@@ -80,12 +100,12 @@
|
||||
- (void) initialize;
|
||||
- (void) initializeWithConfig: (NSDictionary *) _config;
|
||||
- (BOOL) sessionIsOK;
|
||||
- (WOResponse *) _performOpenIdRequest: (NSString *) endpoint
|
||||
- (SimpleOpenIdResponse *) _performOpenIdRequest: (NSString *) endpoint
|
||||
method: (NSString *) method
|
||||
headers: (NSDictionary *) headers
|
||||
body: (NSData *) body;
|
||||
- (NSMutableDictionary *) fecthConfiguration: (NSString *) _domain;
|
||||
- (void) setAccessToken;
|
||||
- (void) setAccessToken: (NSString* ) token;
|
||||
- (NSString *) getRefreshToken;
|
||||
- (NSString *) getToken;
|
||||
- (NSString *) getCurrentToken;
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#import <Foundation/NSProcessInfo.h>
|
||||
|
||||
#import <curl/curl.h>
|
||||
|
||||
#import <NGObjWeb/WOHTTPConnection.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
@@ -25,12 +30,12 @@
|
||||
|
||||
#import <SOGo/SOGoUser.h>
|
||||
|
||||
|
||||
#import <GDLContentStore/GCSOpenIdFolder.h>
|
||||
#import <GDLContentStore/GCSFolderManager.h>
|
||||
|
||||
#import "NSDictionary+Utilities.h"
|
||||
#import "NSString+Utilities.h"
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/NSString+Crypto.h>
|
||||
#import "SOGoCache.h"
|
||||
#import "SOGoSystemDefaults.h"
|
||||
|
||||
@@ -38,6 +43,88 @@
|
||||
|
||||
static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
|
||||
|
||||
size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
{
|
||||
size_t total;
|
||||
|
||||
total = size * nmemb;
|
||||
[(NSMutableData *)buffer appendBytes: ptr length: total];
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
@implementation SimpleOpenIdResponse
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResponse: (NSString *)_data andHeaders: (NSString *)_headers andStatus:(unsigned int )_status{
|
||||
if ((self = [self init])) {
|
||||
[self setStatus: _status];
|
||||
[self setContent: _data];
|
||||
[self setHeaders: _headers];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setStatus:(unsigned int)_status
|
||||
{
|
||||
self->status = _status;
|
||||
}
|
||||
|
||||
- (unsigned int)status
|
||||
{
|
||||
if(self->status)
|
||||
return self->status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)setContent:(NSString *)_data
|
||||
{
|
||||
self->content = _data;
|
||||
}
|
||||
|
||||
- (NSString *)contentString
|
||||
{
|
||||
if(self->content)
|
||||
return self->content;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setHeaders:(NSString *)_data
|
||||
{
|
||||
self->headers = _data;
|
||||
}
|
||||
|
||||
- (NSString *)headers
|
||||
{
|
||||
if(self->headers)
|
||||
return self->headers;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString*)description {
|
||||
NSString *co, *hd;
|
||||
unsigned int st;
|
||||
st = 0;
|
||||
co = @"nil";
|
||||
hd = @"nil";
|
||||
if(self->status)
|
||||
st = self->status;
|
||||
if(self->headers)
|
||||
hd = self->headers;
|
||||
if(self->content)
|
||||
co = self->content;
|
||||
return [NSString stringWithFormat: @"<SimpleOpenIdResponse> <status: %d>, <headers: %@>, <content: %@>", st, hd, co];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation SOGoOpenIdSession
|
||||
|
||||
/// Check if all required parameters to set up a OpenIdSession are in sogo.conf
|
||||
@@ -52,6 +139,13 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
return NO;
|
||||
}
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
|
||||
if(![[sd authenticationType] isEqualToString: @"openid"])
|
||||
{
|
||||
[self errorWithFormat: @"Sogo SOGoAuthenticationType is not openid"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
return ([sd openIdConfigUrl] && [sd openIdScope] && [sd openIdClient] && [sd openIdClientSecret]);
|
||||
}
|
||||
|
||||
@@ -70,6 +164,7 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
openIdClient = [_config objectForKey: @"SOGoOpenIdClient"];
|
||||
openIdClientSecret = [_config objectForKey: @"SOGoOpenIdClientSecret"];
|
||||
openIdEmailParam = [_config objectForKey: @"SOGoOpenIdEmailParam"];
|
||||
openIdHttpVersion = [_config objectForKey: @"SOGoOpenIdHttpVersion"];
|
||||
|
||||
openIdEnableRefreshToken = NO;
|
||||
refreshTokenBool = [_config objectForKey: @"SOGoOpenIdEnableRefreshToken"];
|
||||
@@ -118,7 +213,7 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"Missing parameters from sogo.conf"];
|
||||
[self errorWithFormat: @"LoginTypebyDOmain - Openid not found or missing parameters for domain", _domain];
|
||||
}
|
||||
}
|
||||
else if ([[self class] checkUserConfig])
|
||||
@@ -128,6 +223,7 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
openIdClient = [sd openIdClient];
|
||||
openIdClientSecret = [sd openIdClientSecret];
|
||||
openIdEmailParam = [sd openIdEmailParam];
|
||||
openIdHttpVersion = [sd openIdHttpVersion];
|
||||
openIdEnableRefreshToken = [sd openIdEnableRefreshToken];
|
||||
userTokenInterval = [sd openIdTokenCheckInterval];
|
||||
sendDomainInfo = [sd openIdSendDomainInfo];
|
||||
@@ -147,66 +243,147 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (WOResponse *) _performOpenIdRequest: (NSString *) endpoint
|
||||
- (SimpleOpenIdResponse *) _performOpenIdRequest: (NSString *) endpoint
|
||||
method: (NSString *) method
|
||||
headers: (NSDictionary *) headers
|
||||
body: (NSData *) body
|
||||
{
|
||||
NSURL *url;
|
||||
NSMutableData *buffer, *buffHeaders;
|
||||
SimpleOpenIdResponse *response;
|
||||
|
||||
CURL *curl;
|
||||
struct curl_slist *headerlist=NULL;
|
||||
NSUInteger status;
|
||||
WORequest *request;
|
||||
WOResponse *response;
|
||||
WOHTTPConnection *httpConnection;
|
||||
|
||||
|
||||
url = [NSURL URLWithString: endpoint];
|
||||
if (url)
|
||||
{
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
{
|
||||
NSLog(@"OpenId perform request: %@ %@", method, endpoint);
|
||||
NSLog(@"OpenId perform request, headers %@", headers);
|
||||
// if(body)
|
||||
// NSLog(@"OpenId perform request: content %@", [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]);
|
||||
}
|
||||
|
||||
httpConnection = [[WOHTTPConnection alloc] initWithURL: url];
|
||||
[httpConnection autorelease];
|
||||
NSString *content, *headerResp;
|
||||
CURLcode rc;
|
||||
char error[CURL_ERROR_SIZE];
|
||||
|
||||
request = [[WORequest alloc] initWithMethod: method
|
||||
uri: [endpoint hostlessURL]
|
||||
httpVersion: @"HTTP/1.1"
|
||||
headers: headers content: body
|
||||
userInfo: nil];
|
||||
[request autorelease];
|
||||
[httpConnection sendRequest: request];
|
||||
response = [httpConnection readResponse];
|
||||
status = [response status];
|
||||
if(status >= 200 && status <500 && status != 404)
|
||||
return response;
|
||||
else if (status == 404)
|
||||
{
|
||||
[self errorWithFormat: @"OpenID endpoint not found (404): %@", endpoint];
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"OpenID server internal error during %@: %@", endpoint, response];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
url = [NSURL URLWithString: endpoint];
|
||||
if(!url)
|
||||
{
|
||||
[self errorWithFormat: @"OpenID can't handle endpoint (not a url): '%@'", endpoint];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
{
|
||||
NSLog(@"OpenId perform request: %@ %@", method, endpoint);
|
||||
NSLog(@"OpenId perform request, headers %@", headers);
|
||||
}
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
NSLog(@"OpenId perform request, body raw %@", body);
|
||||
|
||||
curl_global_init(CURL_GLOBAL_SSL);
|
||||
curl = curl_easy_init();
|
||||
|
||||
if (curl)
|
||||
{
|
||||
error[0] = 0;
|
||||
curl_easy_setopt(curl, CURLOPT_URL, [endpoint UTF8String]);
|
||||
|
||||
//add form
|
||||
if(body)
|
||||
{
|
||||
//Trick because sometimes NSData bytes don't add the \0 at the end and junk character may be added
|
||||
const char *myBodyTmp = (const char*)[body bytes];
|
||||
char myBody[[body length]+1];
|
||||
strncpy(myBody, myBodyTmp, [body length]);
|
||||
myBody[[body length]]='\0';
|
||||
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
NSLog(@"OpenId perform request, myBodyTmp %s", myBodyTmp);
|
||||
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
NSLog(@"OpenId perform request, myBody %s", myBody);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, myBody);
|
||||
}
|
||||
|
||||
//add headers
|
||||
if(headers)
|
||||
{
|
||||
NSEnumerator *enumerator = [headers keyEnumerator];
|
||||
NSString *key, *header;
|
||||
while((key = [enumerator nextObject]))
|
||||
{
|
||||
header = [NSString stringWithFormat: @"%@: %@", key, [headers objectForKey: key]];
|
||||
headerlist = curl_slist_append(headerlist, [header UTF8String]);
|
||||
}
|
||||
}
|
||||
if(headerlist != NULL)
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
|
||||
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
|
||||
buffer = [NSMutableData data];
|
||||
buffHeaders = [NSMutableData data];
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_body_function);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_body_function);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERDATA, buffHeaders);
|
||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error);
|
||||
|
||||
// Perform SOAP request
|
||||
rc = curl_easy_perform(curl);
|
||||
if (rc == CURLE_OK)
|
||||
{
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
|
||||
|
||||
response = [SimpleOpenIdResponse alloc];
|
||||
headerResp = [[NSString alloc] initWithData: buffHeaders
|
||||
encoding: NSUTF8StringEncoding];
|
||||
|
||||
response = [response initWithResponse: nil andHeaders: headerResp andStatus: status];
|
||||
|
||||
if(status >= 200 && status <500 && status != 404)
|
||||
{
|
||||
content = [[NSString alloc] initWithData: buffer
|
||||
encoding: NSUTF8StringEncoding];
|
||||
if (!content)
|
||||
content = [[NSString alloc] initWithData: buffer
|
||||
encoding: NSISOLatin1StringEncoding];
|
||||
[response setContent: content];
|
||||
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
NSLog(@"OpenId perform request: response is: %@", response);
|
||||
|
||||
return [response autorelease];
|
||||
}
|
||||
else if (status == 404)
|
||||
{
|
||||
[self errorWithFormat: @"OpenID endpoint not found (404): %@", endpoint];
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"OpenID server internal error during %@: %@", endpoint, response];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"CURL error while accessing %@ (%d): %@", endpoint, rc,
|
||||
[NSString stringWithCString: strlen(error) ? error : curl_easy_strerror(rc)]];
|
||||
}
|
||||
curl_easy_cleanup (curl);
|
||||
}
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"OpenID error when setting curl request for: %@", endpoint];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) fecthConfiguration: (NSString*) _domain
|
||||
{
|
||||
NSString *content;
|
||||
WOResponse * response;
|
||||
SimpleOpenIdResponse *response;
|
||||
// WOResponse * response;
|
||||
NSUInteger status;
|
||||
NSMutableDictionary *result;
|
||||
NSDictionary *config, *headers;
|
||||
@@ -238,7 +415,9 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
self->authorizationEndpoint = [config objectForKey: @"authorization_endpoint"];
|
||||
self->tokenEndpoint = [config objectForKey: @"token_endpoint"];
|
||||
self->userinfoEndpoint = [config objectForKey: @"userinfo_endpoint"];
|
||||
self->endSessionEndpoint = [config objectForKey: @"end_session_endpoint"];
|
||||
|
||||
if([config objectForKey: @"end_session_endpoint"])
|
||||
self->endSessionEndpoint = [config objectForKey: @"end_session_endpoint"];
|
||||
|
||||
//Optionnals?
|
||||
if([config objectForKey: @"introspection_endpoint"])
|
||||
@@ -346,7 +525,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
ASSIGN (authorizationEndpoint, [sessionDict objectForKey: @"authorization_endpoint"]);
|
||||
ASSIGN (tokenEndpoint, [sessionDict objectForKey: @"token_endpoint"]);
|
||||
ASSIGN (userinfoEndpoint, [sessionDict objectForKey: @"userinfo_endpoint"]);
|
||||
ASSIGN (endSessionEndpoint, [sessionDict objectForKey: @"end_session_endpoint"]);
|
||||
if([sessionDict objectForKey: @"end_session_endpoint"])
|
||||
ASSIGN (endSessionEndpoint, [sessionDict objectForKey: @"end_session_endpoint"]);
|
||||
|
||||
//Optionnals?
|
||||
if([sessionDict objectForKey: @"introspection_endpoint"])
|
||||
@@ -370,7 +550,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
[sessionDict setObject: authorizationEndpoint forKey: @"authorization_endpoint"];
|
||||
[sessionDict setObject: tokenEndpoint forKey: @"token_endpoint"];
|
||||
[sessionDict setObject: userinfoEndpoint forKey: @"userinfo_endpoint"];
|
||||
[sessionDict setObject: endSessionEndpoint forKey: @"end_session_endpoint"];
|
||||
if(endSessionEndpoint)
|
||||
[sessionDict setObject: endSessionEndpoint forKey: @"end_session_endpoint"];
|
||||
|
||||
//Optionnals?
|
||||
if(introspectionEndpoint)
|
||||
@@ -431,6 +612,12 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
nextCheckAfter: nextCheck];
|
||||
}
|
||||
|
||||
|
||||
-(NSString *) _random_state
|
||||
{
|
||||
return [[[NSProcessInfo processInfo] globallyUniqueString] asSHA1String];;
|
||||
}
|
||||
|
||||
- (NSString*) loginUrl: (NSString *) oldLocation
|
||||
{
|
||||
NSString* logUrl;
|
||||
@@ -438,6 +625,7 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
logUrl = [logUrl stringByAppendingString: @"&response_type=code"];
|
||||
logUrl = [logUrl stringByAppendingFormat: @"&client_id=%@", self->openIdClient];
|
||||
logUrl = [logUrl stringByAppendingFormat: @"&redirect_uri=%@", oldLocation];
|
||||
logUrl = [logUrl stringByAppendingFormat: @"&state=%@", [self _random_state]];
|
||||
if(self->forDomain != nil && [self->forDomain length] > 0)
|
||||
logUrl = [logUrl stringByAppendingFormat: @"&sogo_domain=%@", forDomain];
|
||||
// logurl = [self->logurl stringByAppendingFormat: @"&state=%@", state];
|
||||
@@ -485,7 +673,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
- (NSMutableDictionary *) fetchToken: (NSString * ) code redirect: (NSString *) oldLocation
|
||||
{
|
||||
NSString *location, *form, *content;
|
||||
WOResponse *response;
|
||||
SimpleOpenIdResponse *response;
|
||||
// WOResponse *response;
|
||||
NSUInteger status;
|
||||
NSMutableDictionary *result;
|
||||
NSDictionary *headers;
|
||||
@@ -510,7 +699,10 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
self->forDomain, @"sogo-user-domain", nil];
|
||||
else
|
||||
headers = [NSDictionary dictionaryWithObject: @"application/x-www-form-urlencoded" forKey: @"content-type"];
|
||||
|
||||
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
NSLog(@"OpenId fetch token, form %@", form);
|
||||
|
||||
response = [self _performOpenIdRequest: location
|
||||
method: @"POST"
|
||||
headers: headers
|
||||
@@ -553,7 +745,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
- (NSMutableDictionary *) refreshToken: (NSString * ) userRefreshToken
|
||||
{
|
||||
NSString *location, *form, *content;
|
||||
WOResponse *response;
|
||||
SimpleOpenIdResponse *response;
|
||||
// WOResponse *response;
|
||||
NSUInteger status;
|
||||
NSMutableDictionary *result;
|
||||
NSDictionary *headers;
|
||||
@@ -626,7 +819,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
- (NSMutableDictionary *) fetchUserInfo
|
||||
{
|
||||
NSString *location, *auth, *content;
|
||||
WOResponse *response;
|
||||
SimpleOpenIdResponse *response;
|
||||
// WOResponse *response;
|
||||
NSUInteger status;
|
||||
NSMutableDictionary *result;
|
||||
NSDictionary *profile, *headers;
|
||||
@@ -682,7 +876,7 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self logWithFormat: @"Error during fetching the token (status %d), response: %@", status, response];
|
||||
[self logWithFormat: @"Error fetching userInfo (status %d), response: %@", status, response];
|
||||
[result setObject: @"http-error" forKey: @"error"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,7 +569,10 @@ static SoSecurityManager *sm = nil;
|
||||
isPropfind = [requestMethod isEqualToString: @"PROPFIND"];
|
||||
|
||||
error = [self initSubFolders];
|
||||
if (error && isPropfind)
|
||||
if(error)
|
||||
{
|
||||
[self errorWithFormat: @"a database error occured when inititializing the subFolders: %@", [error reason]];
|
||||
if(isPropfind)
|
||||
{
|
||||
/* We exceptionnally raise the exception here because doPROPFIND: will
|
||||
not care for errors in its response from toManyRelationShipKeys,
|
||||
@@ -577,10 +580,16 @@ static SoSecurityManager *sm = nil;
|
||||
SOGo extensions. */
|
||||
[error raise];
|
||||
}
|
||||
}
|
||||
|
||||
error = [self initSubscribedSubFolders];
|
||||
if (error && isPropfind)
|
||||
[error raise];
|
||||
if (error)
|
||||
{
|
||||
[self errorWithFormat: @"a database error occured when subscribing to subfolders: %@", [error reason]];
|
||||
if(isPropfind)
|
||||
[error raise];
|
||||
}
|
||||
|
||||
|
||||
ma = [NSMutableArray arrayWithArray: [subFolders allValues]];
|
||||
if ([subscribedSubFolders count])
|
||||
|
||||
@@ -33,7 +33,7 @@ static const NSString *POLICY_MIN_DIGIT = @"POLICY_MIN_DIGIT";
|
||||
static const NSString *POLICY_MIN_SPECIAL_SYMBOLS = @"POLICY_MIN_SPECIAL_SYMBOLS";
|
||||
static const NSString *POLICY_MIN_LENGTH = @"POLICY_MIN_LENGTH";
|
||||
|
||||
static const NSString *SPECIAL_SYMBOL_ALLOWED = @"%$&*(){}!?\\@#.,:;+=\\[\\]\\|<>\\/-_";
|
||||
static const NSString *SPECIAL_SYMBOL_ALLOWED = @"%$&*(){}!?\\@#.,:;+=\\[\\]\\|<>\\/\\-_";
|
||||
|
||||
@implementation SOGoPasswordPolicy
|
||||
|
||||
|
||||
@@ -122,28 +122,28 @@ static NSString *productDirectoryName = @"SOGo";
|
||||
|
||||
pathes = [[self productSearchPathes] objectEnumerator];
|
||||
while ((lpath = [pathes nextObject]))
|
||||
{
|
||||
productNames = [[fm directoryContentsAtPath: lpath] objectEnumerator];
|
||||
while ((productName = [productNames nextObject]))
|
||||
{
|
||||
productNames = [[fm directoryContentsAtPath: lpath] objectEnumerator];
|
||||
while ((productName = [productNames nextObject]))
|
||||
{
|
||||
if ([[productName pathExtension] isEqualToString: @"SOGo"])
|
||||
{
|
||||
bpath = [lpath stringByAppendingPathComponent: productName];
|
||||
[registry registerProductAtPath: bpath];
|
||||
[loadedProducts addObject: productName];
|
||||
}
|
||||
}
|
||||
if ([loadedProducts count])
|
||||
if ([[productName pathExtension] isEqualToString: @"SOGo"])
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
[self logWithFormat: @"SOGo products loaded from '%@':", lpath];
|
||||
[self logWithFormat: @" %@",
|
||||
[loadedProducts componentsJoinedByString: @", "]];
|
||||
}
|
||||
[loadedProducts removeAllObjects];
|
||||
bpath = [lpath stringByAppendingPathComponent: productName];
|
||||
[registry registerProductAtPath: bpath];
|
||||
[loadedProducts addObject: productName];
|
||||
}
|
||||
}
|
||||
if ([loadedProducts count])
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
[self logWithFormat: @"SOGo products loaded from '%@':", lpath];
|
||||
[self logWithFormat: @" %@",
|
||||
[loadedProducts componentsJoinedByString: @", "]];
|
||||
}
|
||||
[loadedProducts removeAllObjects];
|
||||
}
|
||||
}
|
||||
|
||||
if (![registry loadAllProducts] && verbose)
|
||||
[self warnWithFormat: @"could not load all products !"];
|
||||
|
||||
@@ -162,11 +162,23 @@
|
||||
|
||||
// Get the key length and its bytes
|
||||
data = [theKey dataByDecodingBase64];
|
||||
key = (char *)[data bytes];
|
||||
klen = [data length];
|
||||
|
||||
|
||||
//value longer than the key, concatenate the key with itself until long enough
|
||||
if (klen < [theValue length])
|
||||
[self errorWithFormat: @"Value to be secured is too big (%i > %i) -- secured value will be corrupted", [theValue length], klen, [theKey length]];
|
||||
{
|
||||
NSMutableData *concatenatedData = [NSMutableData data];
|
||||
int j;
|
||||
int nbDuplication = [theValue length]/klen;
|
||||
for(j=0; j <= nbDuplication; j++)
|
||||
[concatenatedData appendData:data];
|
||||
|
||||
data = [NSData dataWithData: concatenatedData];
|
||||
klen = [data length];
|
||||
}
|
||||
|
||||
key = (char *)[data bytes];
|
||||
|
||||
// Get the key - padding it with 0 with key length
|
||||
pass = (char *) calloc(klen, sizeof(char));
|
||||
@@ -201,7 +213,6 @@
|
||||
|
||||
// Get the key length and its bytes
|
||||
dataKey = [theKey dataByDecodingBase64];
|
||||
key = (char *)[dataKey bytes];
|
||||
klen = [dataKey length];
|
||||
|
||||
// Get the secured value length and its bytes
|
||||
@@ -209,6 +220,20 @@
|
||||
value = (char *)[dataValue bytes];
|
||||
vlen = [dataValue length];
|
||||
|
||||
//If the key is shorer than the value, duplicate it with itself.
|
||||
if(klen < vlen)
|
||||
{
|
||||
NSMutableData *concatenatedData = [NSMutableData data];
|
||||
int j;
|
||||
int nbDuplication = [dataValue length]/klen;
|
||||
for(j=0; j <= nbDuplication; j++)
|
||||
[concatenatedData appendData:dataKey];
|
||||
|
||||
dataKey = [NSData dataWithData: concatenatedData];
|
||||
klen = [dataKey length];
|
||||
}
|
||||
key = (char *)[dataKey bytes];
|
||||
|
||||
// Target buffer
|
||||
buf = (char *) calloc(klen, sizeof(char));
|
||||
|
||||
|
||||
@@ -496,6 +496,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
}
|
||||
|
||||
- (NSString *) _extractSieveAction: (NSDictionary *) action
|
||||
withReq: (NSMutableDictionary *) req
|
||||
delimiter: (NSString *) delimiter
|
||||
{
|
||||
NSString *sieveAction, *method, *requirement, *argument, *flag, *mailbox;
|
||||
@@ -548,7 +549,9 @@ static NSString *sieveScriptName = @"sogo";
|
||||
{
|
||||
argument = [NSString stringWithFormat: @"mailto:%@", argument];
|
||||
sieveAction = [NSString stringWithFormat: @"%@ %@",
|
||||
method, [argument asSieveQuotedString]];
|
||||
method, [argument asSieveQuotedString]];
|
||||
[req addObjectUniquely: @"enotify"];
|
||||
[req addObjectUniquely: @"variables"];
|
||||
}
|
||||
else if ([method isEqualToString: @"reject"])
|
||||
sieveAction = [NSString stringWithFormat: @"%@ %@",
|
||||
@@ -575,6 +578,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
}
|
||||
|
||||
- (NSArray *) _extractSieveActions: (NSArray *) actions
|
||||
withReq: (NSMutableDictionary *) req
|
||||
delimiter: (NSString *) delimiter
|
||||
{
|
||||
NSMutableArray *sieveActions;
|
||||
@@ -586,6 +590,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
for (count = 0; !scriptError && count < max; count++)
|
||||
{
|
||||
sieveAction = [self _extractSieveAction: [actions objectAtIndex: count]
|
||||
withReq: req
|
||||
delimiter: delimiter];
|
||||
if (!scriptError)
|
||||
[sieveActions addObject: sieveAction];
|
||||
@@ -595,6 +600,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
}
|
||||
|
||||
- (NSString *) _convertScriptToSieve: (NSDictionary *) newScript
|
||||
withReq: (NSMutableDictionary *) req
|
||||
delimiter: (NSString *) delimiter
|
||||
{
|
||||
NSMutableString *sieveText;
|
||||
@@ -624,6 +630,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
scriptError = [NSString stringWithFormat: @"Bad test: %@", match];
|
||||
}
|
||||
sieveActions = [self _extractSieveActions: [newScript objectForKey: @"actions"]
|
||||
withReq: req
|
||||
delimiter: delimiter];
|
||||
if ([sieveActions count])
|
||||
[sieveText appendFormat: @" %@;\r\n",
|
||||
@@ -660,6 +667,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
if ([[currentScript objectForKey: @"active"] boolValue])
|
||||
{
|
||||
sieveText = [self _convertScriptToSieve: currentScript
|
||||
withReq: newRequirements
|
||||
delimiter: delimiter];
|
||||
[sieveScript appendString: sieveText];
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ static const NSString *kDisableSharingCalendar = @"Calendar";
|
||||
- (BOOL) uixDebugEnabled;
|
||||
- (BOOL) easDebugEnabled;
|
||||
- (BOOL) openIdDebugEnabled;
|
||||
- (BOOL) apiDebugEnabled;
|
||||
- (BOOL) tnefDecoderDebugEnabled;
|
||||
- (BOOL) xsrfValidationEnabled;
|
||||
|
||||
@@ -106,6 +107,7 @@ NSComparisonResult languageSort(id el1, id el2, void *context);
|
||||
- (NSString *) openIdClient;
|
||||
- (NSString *) openIdClientSecret;
|
||||
- (NSString *) openIdEmailParam;
|
||||
- (NSString *) openIdHttpVersion;
|
||||
- (BOOL) openIdEnableRefreshToken;
|
||||
- (BOOL) openIdLogoutEnabled: (NSString *) _domain;
|
||||
- (int) openIdTokenCheckInterval;
|
||||
|
||||
@@ -654,6 +654,11 @@ _injectConfigurationFromFile (NSMutableDictionary *defaultsDict,
|
||||
return [self boolForKey: @"SOGoOpenIDDebugEnabled"];
|
||||
}
|
||||
|
||||
- (BOOL) apiDebugEnabled
|
||||
{
|
||||
return [self boolForKey: @"SOGoAPIDebugEnabled"];
|
||||
}
|
||||
|
||||
- (BOOL) tnefDecoderDebugEnabled
|
||||
{
|
||||
return [self boolForKey: @"SOGoTnefDecoderDebugEnabled"];
|
||||
@@ -779,6 +784,15 @@ NSComparisonResult languageSort(id el1, id el2, void *context)
|
||||
return emailParam;
|
||||
}
|
||||
|
||||
- (NSString *) openIdHttpVersion
|
||||
{
|
||||
NSString *httpVersion;
|
||||
httpVersion = [self stringForKey: @"SOGoOpenIdHttpVersion"];
|
||||
if(!httpVersion)
|
||||
httpVersion = @"HTTP/1.1";
|
||||
return httpVersion;
|
||||
}
|
||||
|
||||
- (BOOL) openIdLogoutEnabled: (NSString *) _domain
|
||||
{
|
||||
if(_domain && [self doesLoginTypeByDomain])
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
@implementation UIxMailAccountActions
|
||||
|
||||
- (NSArray *)sortChildrenRecursively: (NSArray *)children {
|
||||
NSInteger i, j;
|
||||
NSInteger i, j, nbSpecial;
|
||||
NSMutableArray *sortedArray;
|
||||
NSArray *unsortedChildren, *sortedChildren;
|
||||
NSDictionary *child;
|
||||
@@ -75,15 +75,18 @@
|
||||
|
||||
sortedArray = [NSMutableArray array];
|
||||
|
||||
nbSpecial = 0;
|
||||
for (child in children) {
|
||||
unsortedChildren = [child objectForKey:@"children"];
|
||||
sortedChildren = [self sortChildrenRecursively:unsortedChildren];
|
||||
mutableChild = [child mutableCopy];
|
||||
[mutableChild setObject:sortedChildren forKey:@"children"];
|
||||
[sortedArray addObject:mutableChild];
|
||||
if(![[mutableChild objectForKey:@"type"] isEqualToString: @"folder"])
|
||||
nbSpecial++;
|
||||
}
|
||||
|
||||
for (i = 0; i < [sortedArray count] - 1; i++) {
|
||||
for (i = nbSpecial; i < [sortedArray count] - 1; i++) {
|
||||
for (j = i + 1; j < [sortedArray count]; j++) {
|
||||
name1 = [[sortedArray objectAtIndex:i] objectForKey:@"name"];
|
||||
name2 = [[sortedArray objectAtIndex:j] objectForKey:@"name"];
|
||||
|
||||
@@ -376,7 +376,7 @@
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self logWithFormat: @"Error while parsing attachements for rendering bracket"];
|
||||
[self logWithFormat: @"Error while parsing attachments for rendering bracket"];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ MainUI_OBJC_FILES += \
|
||||
SOGoUserHomePage.m \
|
||||
SOGoBrowsersPanel.m \
|
||||
SOGoMicrosoftActiveSyncActions.m \
|
||||
SOGoAPIActions.m \
|
||||
|
||||
ifeq ($(saml2_config), yes)
|
||||
MainUI_OBJC_FILES += SOGoSAML2Actions.m
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright (C) 2014-2016 Inverse inc.
|
||||
|
||||
This file is part of SOGo.
|
||||
|
||||
SOGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with SOGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#import <SOGo/SOGoCache.h>
|
||||
#import <SOGo/NSObject+Utilities.h>
|
||||
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WODirectAction.h>
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
|
||||
#import <API/SOGoAPIDispatcher.h>
|
||||
|
||||
@interface SOGoAPIActions : WODirectAction
|
||||
@end
|
||||
|
||||
@implementation SOGoAPIActions
|
||||
|
||||
|
||||
- (WOResponse *) sogoAPIAction
|
||||
{
|
||||
WOResponse *response;
|
||||
WORequest *request;
|
||||
NSBundle *bundle;
|
||||
NSException *ex;
|
||||
id dispatcher;
|
||||
Class clazz;
|
||||
|
||||
request = (WORequest *)[context request];
|
||||
response = (WOResponse *)[context response];
|
||||
[response setStatus: 200];
|
||||
[response setHeader: @"application/json; charset=utf-8" forKey: @"content-type"];
|
||||
|
||||
bundle = [NSBundle bundleForClass: NSClassFromString(@"SOGoAPIProduct")];
|
||||
clazz = [bundle classNamed: @"SOGoAPIDispatcher"];
|
||||
dispatcher = [[clazz alloc] init];
|
||||
|
||||
ex = [dispatcher dispatchRequest: request inResponse: response context: context];
|
||||
|
||||
//[[self class] memoryStatistics];
|
||||
|
||||
if (ex)
|
||||
{
|
||||
return [NSException exceptionWithHTTPStatus: 500];
|
||||
}
|
||||
|
||||
RELEASE(dispatcher);
|
||||
|
||||
//[[SOGoCache sharedCache] killCache];
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -92,7 +92,8 @@
|
||||
// We check if we must write the Sieve scripts to the server
|
||||
// upon first login if no user preferences are found, and the SOGo
|
||||
// admin has defined SOGoSieveFilters in the domain or system settings
|
||||
if ([dd sieveScriptsEnabled] && [[[ud source] values] count] == 0 &&
|
||||
//count = 1 because values will be {CDefaultsSize = 16777215; } in this case.
|
||||
if ([dd sieveScriptsEnabled] && [[[ud source] values] count] == 1 &&
|
||||
((filters = [[dd source] objectForKey: @"SOGoSieveFilters"]) || (filters = [[sd source] objectForKey: @"SOGoSieveFilters"])))
|
||||
{
|
||||
SOGoMailAccount *account;
|
||||
@@ -446,9 +447,9 @@
|
||||
}
|
||||
else if ([authType isEqualToString: @"openid"])
|
||||
{
|
||||
SOGoOpenIdSession* session;
|
||||
session = [SOGoOpenIdSession OpenIdSession: loginDomain];
|
||||
redirectURL = [session logoutUrl];
|
||||
SOGoOpenIdSession* sessionOidc;
|
||||
sessionOidc = [SOGoOpenIdSession OpenIdSession: loginDomain];
|
||||
redirectURL = [sessionOidc logoutUrl];
|
||||
}
|
||||
#if defined(SAML2_CONFIG)
|
||||
else if ([authType isEqualToString: @"saml2"])
|
||||
|
||||
@@ -118,6 +118,11 @@
|
||||
actionClass = "SOGoMicrosoftActiveSyncActions";
|
||||
actionName = "microsoftServerActiveSync";
|
||||
};
|
||||
SOGoAPI = {
|
||||
protectedBy = "<public>";
|
||||
actionClass = "SOGoAPIActions";
|
||||
actionName = "sogoAPI";
|
||||
};
|
||||
casProxy = {
|
||||
protectedBy = "<public>";
|
||||
pageName = "SOGoRootPage";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Default font size";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Default font size";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Standardna veličina fonta";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Размер на шрифта по подразбиране";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Mida per defecte del tipus de lletra";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "默认字体大小";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Default font size";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Zadana veličina slova";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Standaard lettergrootte";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Default font size";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Oletuskirjasinkoko";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "ברירת מחדל גודל גופן";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Aláírás beszúrása válasz esetén";
|
||||
"Insert signature on forward" = "Aláírás beszúrása továbbítás esetén";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Alapértelmezett betűméret";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Default font size";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Ukuran font default";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Grandezza carattere predefinita";
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
"SOGo Version" = "SOGoバージョン";
|
||||
|
||||
/* Confirmation asked when changing the language */
|
||||
"Save preferences and reload page now?" = "ユーザー設定を保存してページを再読み込みしますか? / Save preferences and reload page now?";
|
||||
"Save preferences and reload page now?" = "ユーザー設定を保存してページを再読み込みしますか? / Save preferences and reload page now? (Yes -> はい)";
|
||||
"Language" = "言語";
|
||||
"choose" = "選択...";
|
||||
"Arabic" = "العربية";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Әдепкі қаріп өлшемі";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Noklusējuma fonta lielums";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Parašas po atsakymu";
|
||||
"Insert signature on forward" = "Parašas po persiunčiamu laišku";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Numatytasis teksto dydis";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Стандардна големина на фонтот";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Podrazumijevana veličina fonta";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Default font size";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Marime font implicită";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Подразуевана величина фонта";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Podrazuevana veličina fonta";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Predvolená veľkosť písma";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Privzeta velikost črk";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Tamaño de fuente por defecto";
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Standardteckenstorlek";
|
||||
|
||||
@@ -334,12 +334,14 @@ static SoProduct *preferencesProduct = nil;
|
||||
[defaults setCalendarCategoriesColors: colors];
|
||||
}
|
||||
}
|
||||
// Add the jisti link if needed
|
||||
// Add the jitsi link if needed
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
if([sd isCalendarJitsiLinkEnabled])
|
||||
{
|
||||
if (![[defaults source] objectForKey: @"SOGoCalendarJitsiBaseUrl"])
|
||||
[[defaults source] setObject: [domainDefaults calendarJistiBaseUrl] forKey: @"SOGoCalendarJitsiBaseUrl"];
|
||||
[[defaults source] setObject: [domainDefaults calendarJitsiBaseUrl] forKey: @"SOGoCalendarJitsiBaseUrl"];
|
||||
if (![[defaults source] objectForKey: @"SOGoCalendarJitsiRoomPrefix"])
|
||||
[[defaults source] setObject: [domainDefaults calendarJitsiRoomPrefix] forKey: @"SOGoCalendarJitsiRoomPrefix"];
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"Insert signature on reply" = "Insert signature on reply";
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachements for inline images";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Maint ffont diofyn";
|
||||
|
||||
@@ -341,7 +341,7 @@
|
||||
|
||||
/* Appointment categories */
|
||||
"category_none" = "なし";
|
||||
"category_labels" = "記念日,誕生日,ビジネス,業務,呼び出し,顧客,競合,取引先,お気に入り,フォローアップ,贈り物,休日,アイデア,打ち合わせ,問題,その他,個人,プロジェクト,祝日,状態,供給者,旅行,休暇";
|
||||
"category_labels" = "記念日,誕生日,ビジネス,訪問,顧客,コンテスト,得意先,お気に入り,フォローアップ,ギフト,休日,計画,ミーティング,発行,色々,私事,プロジェクト,祝日,状態,配達,旅行,休暇";
|
||||
"repeat_NEVER" = "繰り返さない";
|
||||
"repeat_DAILY" = "毎日";
|
||||
"repeat_WEEKLY" = "毎週";
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#import <Foundation/NSValue.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
|
||||
#import <NGCards/iCalToDo.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
@@ -596,6 +597,7 @@ static NSArray *reminderValues = nil;
|
||||
NSMutableArray *attachUrls;
|
||||
NSArray *values;
|
||||
NSString *attachUrl;
|
||||
NSURL *url;
|
||||
NSUInteger count, max;
|
||||
|
||||
values = [component attach];
|
||||
@@ -613,12 +615,19 @@ static NSArray *reminderValues = nil;
|
||||
else
|
||||
attachUrls = nil;
|
||||
|
||||
url = [component url];
|
||||
if(url && attachUrls)
|
||||
[attachUrls addObject: [NSDictionary dictionaryWithObject: [url absoluteString] forKey: @"value"]];
|
||||
else
|
||||
attachUrls = [NSArray arrayWithObjects: [NSDictionary dictionaryWithObject: [url absoluteString] forKey: @"value"], nil];
|
||||
|
||||
return attachUrls;
|
||||
}
|
||||
|
||||
- (void) setAttributes: (NSDictionary *) data
|
||||
{
|
||||
NSArray *values;
|
||||
NSURL *url;
|
||||
NSCalendarDate *now;
|
||||
NSMutableArray *attachUrls;
|
||||
NSMutableDictionary *dataWithOwner;
|
||||
@@ -648,18 +657,26 @@ static NSArray *reminderValues = nil;
|
||||
|
||||
[self _handleOrganizer];
|
||||
|
||||
//Be careful. The way sogo works, it only uses the property ATTACH for the url.
|
||||
//But the other property URL, in the ics, will also be seen as an ATTACH in the UI.
|
||||
//To avoid having both ATTACH and URL with the same uri, check the presence and value of URL first.
|
||||
if ([[data objectForKey: @"attachUrls"] isKindOfClass: [NSArray class]])
|
||||
{
|
||||
values = [component childrenWithTag: @"attach"];
|
||||
[component removeChildren: values];
|
||||
values = [data objectForKey: @"attachUrls"];
|
||||
|
||||
url = [component url];
|
||||
attachUrls = [NSMutableArray arrayWithCapacity: [values count]];
|
||||
for (i = 0; i < [values count]; i++)
|
||||
{
|
||||
o = [values objectAtIndex: i];
|
||||
if ([o isKindOfClass: [NSDictionary class]])
|
||||
{
|
||||
[attachUrls addObject: [o objectForKey: @"value"]];
|
||||
if(url && [[url absoluteString] isEqualToString: [o objectForKey: @"value"]])
|
||||
continue; //this uri is already in URL property
|
||||
else
|
||||
[attachUrls addObject: [o objectForKey: @"value"]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,7 +716,7 @@
|
||||
ng-model="app.preferences.defaults.SOGoMailHideInlineAttachments"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0"
|
||||
label:aria-label="Hide attachements for inline images">
|
||||
label:aria-label="Hide attachments for inline images">
|
||||
<var:string label:value="Hide attachements for inline images"/>
|
||||
</md-checkbox>
|
||||
</div>
|
||||
@@ -748,7 +748,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hide-xs" layout="row" layout-align="start center" flex="50">
|
||||
<div layout="row" layout-align="start center" flex="50" flex-xs="100">
|
||||
<md-checkbox
|
||||
class="md-align-top-left"
|
||||
ng-model="app.preferences.defaults.SOGoMailComposeWindowEnabled"
|
||||
@@ -756,7 +756,7 @@
|
||||
<!-- SOGoMailComposeWindow -->
|
||||
</md-checkbox>
|
||||
|
||||
<md-input-container class="md-block md-flex hide-xs">
|
||||
<md-input-container class="md-block md-flex">
|
||||
<label><var:string label:value="Always open mail composer"/></label>
|
||||
<md-select
|
||||
ng-disabled="!app.preferences.defaults.SOGoMailComposeWindowEnabled"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
!function(){"use strict";function e(e,t){e.state("preferences",{abstract:!0,views:{preferences:{templateUrl:"preferences.html",controller:"PreferencesController",controllerAs:"app"}}}).state("preferences.general",{url:"/general",views:{module:{templateUrl:"generalPreferences.html"}}}).state("preferences.calendars",{url:"/calendars",views:{module:{templateUrl:"calendarsPreferences.html"}}}).state("preferences.addressbooks",{url:"/addressbooks",views:{module:{templateUrl:"addressbooksPreferences.html"}}}).state("preferences.mailer",{url:"/mailer",views:{module:{templateUrl:"mailerPreferences.html"}}}),t.rules.otherwise("/general")}function t(e,t,i,s){e.DebugEnabled||s.defaultErrorHandler(function(){}),i.onError({to:"preferences.**"},function(e){"preferences"==e.to().name||e.ignored()||(t.error("transition error to "+e.to().name+": "+e.error().detail),s.go({state:"preferences"}))})}angular.module("SOGo.PreferencesUI",["ui.router","sgCkeditor","angularFileUpload","SOGo.Common","SOGo.MailerUI","SOGo.ContactsUI","SOGo.Authentication","as.sortable"]).config(e).run(t),e.$inject=["$stateProvider","$urlServiceProvider"],t.$inject=["$window","$log","$transitions","$state"]}(),function(){"use strict";function e(a,e,t,i,r,s,n,o,c,d,f){var u=this,h=e.usesCASAuthentication||e.usesSAML2Authentication;function p(){u.account.security&&u.account.security.hasCertificate&&u.account.$certificate().then(function(e){u.certificate=e},function(){delete u.account.security.hasCertificate})}function m(e){e=0<e.type.indexOf("pkcs12")||/\.(p12|pfx)$/.test(e.name);return u.form.certificateFilename.$setValidity("fileformat",e),e}this.defaultPort=143,this.smtpDefaultPort=25,this.defaults=n,this.account=o,this.maxSize=f,this.accountId=c,this.hostnameRE=h&&0<c?/^(?!(127\.0\.0\.1|localhost(?:\.localdomain)?)$)/:/./,this.emailRE=String.emailRE,this.addressesSearchText="",this.ckConfig={autoGrow_minHeight:70,toolbar:{items:["bold","italic","|","fontColor","fontFamily","fontSize","|","link","|","specialCharacters","imageUpload","|","sourceEditing","htmlEmbed"],shouldNotGroupWhenFull:!0},language:n.ckLocaleCode},this.account.encryption?"ssl"==this.account.encryption&&(this.defaultPort=993):this.account.encryption="none",this.account.smtpEncryption?this.smtpDefaultPort=465:this.account.smtpEncryption="none",p(),this.uploader=new i({url:[s.activeUser("folderURL")+"Mail",c,"importCertificate"].join("/"),autoUpload:!1,queueLimit:1,filters:[{name:m,fn:m}],onAfterAddingFile:function(e){u.certificateFilename=e.file.name},onSuccessItem:function(e,t,i,s){this.clearQueue(),a(function(){_.assign(u.account,{security:{hasCertificate:!0},$$certificate:t})}),p()},onErrorItem:function(e,t,i,s){r.alert(l("Error"),l("An error occurred while importing the certificate. Verify your password."))}}),this.hasIdentities=function(){return 0<_.filter(this.account.identities,this.isEditableIdentity).length},this.isEditableIdentity=function(e){return!e.isReadOnly},this.selectIdentity=function(e){this.selectedIdentity==e?this.selectedIdentity=null:this.selectedIdentity=e},this.hasDefaultIdentity=function(){return 0<=_.findIndex(this.account.identities,function(e){return!!e.isDefault})},this.setDefaultIdentity=function(e,i){return _.forEach(this.account.identities,function(e,t){t==i?e.isDefault=!e.isDefault:delete e.isDefault}),e.stopPropagation(),!1},this.canRemoveIdentity=function(e){return e==this.selectedIdentity&&this.hasIdentities()},this.removeIdentity=function(e){this.account.identities.splice(e,1),this.selectedIdentity=null},this.addIdentity=function(){var e=_.findIndex(this.account.identities,{isReadOnly:1}),t={};e<0&&(e=this.account.identities.length),this.customFromIsReadonly()&&(t.fullName=this.account.identities[0].fullName),this.account.identities.splice(Math.max(e,0),0,t),this.selectedIdentity=e},this.showCkEditor=function(e){return this.selectedIdentity==e&&"html"==this.defaults.SOGoMailComposeMessageType},this.filterEmailAddresses=function(t){return _.filter(e.defaultEmailAddresses,function(e){return 0<=e.toLowerCase().indexOf(t.toLowerCase())})},this.customFromIsReadonly=function(){return!(0<c||d)},this.importCertificate=function(){this.uploader.queue[0].formData=[{password:this.certificatePassword}],this.uploader.uploadItem(0)},this.onBeforeUploadCertificate=function(e){this.form=e,this.uploader.clearQueue()},this.removeCertificate=function(){this.account.$removeCertificate()},this.cancel=function(){t.cancel()},this.save=function(){JSON.stringify(this.account).length>this.maxSize?r.alert(l("Error"),l("Data too big. Please contact technical support.")):t.hide()}}e.$inject=["$timeout","$window","$mdDialog","FileUploader","Dialog","sgSettings","defaults","account","accountId","mailCustomFromEnabled","maxSize"],angular.module("SOGo.PreferencesUI").controller("AccountDialogController",e)}(),function(){"use strict";function e(e,t,i,s,a,r,n,o,c){var d=t.sieveCapabilities,f=t.forwardEnabled,u=t.notificationEnabled;t.vacationEnabled;this.filter=a,this.mailboxes=r,thLine truncated
|
||||
!function(){"use strict";function e(e,t){e.state("preferences",{abstract:!0,views:{preferences:{templateUrl:"preferences.html",controller:"PreferencesController",controllerAs:"app"}}}).state("preferences.general",{url:"/general",views:{module:{templateUrl:"generalPreferences.html"}}}).state("preferences.calendars",{url:"/calendars",views:{module:{templateUrl:"calendarsPreferences.html"}}}).state("preferences.addressbooks",{url:"/addressbooks",views:{module:{templateUrl:"addressbooksPreferences.html"}}}).state("preferences.mailer",{url:"/mailer",views:{module:{templateUrl:"mailerPreferences.html"}}}),t.rules.otherwise("/general")}function t(e,t,i,s){e.DebugEnabled||s.defaultErrorHandler(function(){}),i.onError({to:"preferences.**"},function(e){"preferences"==e.to().name||e.ignored()||(t.error("transition error to "+e.to().name+": "+e.error().detail),s.go({state:"preferences"}))})}angular.module("SOGo.PreferencesUI",["ui.router","sgCkeditor","angularFileUpload","SOGo.Common","SOGo.MailerUI","SOGo.ContactsUI","SOGo.Authentication","as.sortable"]).config(e).run(t),e.$inject=["$stateProvider","$urlServiceProvider"],t.$inject=["$window","$log","$transitions","$state"]}(),function(){"use strict";function e(a,e,t,i,r,s,n,o,c,d,f){var u=this,h=e.usesCASAuthentication||e.usesSAML2Authentication;function m(){u.account.security&&u.account.security.hasCertificate&&u.account.$certificate().then(function(e){u.certificate=e},function(){delete u.account.security.hasCertificate})}function p(e){e=0<e.type.indexOf("pkcs12")||/\.(p12|pfx)$/.test(e.name);return u.form.certificateFilename.$setValidity("fileformat",e),e}this.defaultPort=143,this.smtpDefaultPort=25,this.defaults=n,this.account=o,this.maxSize=f,this.accountId=c,this.hostnameRE=h&&0<c?/^(?!(127\.0\.0\.1|localhost(?:\.localdomain)?)$)/:/./,this.emailRE=String.emailRE,this.addressesSearchText="",this.ckConfig={autoGrow_minHeight:70,toolbar:{items:["bold","italic","|","fontColor","fontFamily","fontSize","|","link","|","specialCharacters","imageUpload","|","sourceEditing","htmlEmbed"],shouldNotGroupWhenFull:!0},language:n.ckLocaleCode},this.account.encryption?"ssl"==this.account.encryption&&(this.defaultPort=993):this.account.encryption="none",this.account.smtpEncryption?this.smtpDefaultPort=465:this.account.smtpEncryption="none",m(),this.uploader=new i({url:[s.activeUser("folderURL")+"Mail",c,"importCertificate"].join("/"),autoUpload:!1,queueLimit:1,filters:[{name:p,fn:p}],onAfterAddingFile:function(e){u.certificateFilename=e.file.name},onSuccessItem:function(e,t,i,s){this.clearQueue(),a(function(){_.assign(u.account,{security:{hasCertificate:!0},$$certificate:t})}),m()},onErrorItem:function(e,t,i,s){r.alert(l("Error"),l("An error occurred while importing the certificate. Verify your password."))}}),this.hasIdentities=function(){return 0<_.filter(this.account.identities,this.isEditableIdentity).length},this.isEditableIdentity=function(e){return!e.isReadOnly},this.selectIdentity=function(e){this.selectedIdentity==e?this.selectedIdentity=null:this.selectedIdentity=e},this.hasDefaultIdentity=function(){return 0<=_.findIndex(this.account.identities,function(e){return!!e.isDefault})},this.setDefaultIdentity=function(e,i){return _.forEach(this.account.identities,function(e,t){t==i?e.isDefault=!e.isDefault:delete e.isDefault}),e.stopPropagation(),!1},this.canRemoveIdentity=function(e){return e==this.selectedIdentity&&this.hasIdentities()},this.removeIdentity=function(e){this.account.identities.splice(e,1),this.selectedIdentity=null},this.addIdentity=function(){var e=_.findIndex(this.account.identities,{isReadOnly:1}),t={};e<0&&(e=this.account.identities.length),this.customFromIsReadonly()&&(t.fullName=this.account.identities[0].fullName),this.account.identities.splice(Math.max(e,0),0,t),this.selectedIdentity=e},this.showCkEditor=function(e){return this.selectedIdentity==e&&"html"==this.defaults.SOGoMailComposeMessageType},this.filterEmailAddresses=function(t){return _.filter(e.defaultEmailAddresses,function(e){return 0<=e.toLowerCase().indexOf(t.toLowerCase())})},this.customFromIsReadonly=function(){return!(0<c||d)},this.importCertificate=function(){this.uploader.queue[0].formData=[{password:this.certificatePassword}],this.uploader.uploadItem(0)},this.onBeforeUploadCertificate=function(e){this.form=e,this.uploader.clearQueue()},this.removeCertificate=function(){this.account.$removeCertificate()},this.cancel=function(){t.cancel()},this.save=function(){JSON.stringify(this.account).length>this.maxSize?r.alert(l("Error"),l("Data too big. Please contact technical support.")):t.hide()}}e.$inject=["$timeout","$window","$mdDialog","FileUploader","Dialog","sgSettings","defaults","account","accountId","mailCustomFromEnabled","maxSize"],angular.module("SOGo.PreferencesUI").controller("AccountDialogController",e)}(),function(){"use strict";function e(e,t,i,s,a,r,n,o,c){var d=t.sieveCapabilities,f=t.forwardEnabled,u=t.notificationEnabled;t.vacationEnabled;this.filter=a,this.mailboxes=r,thLine truncated
|
||||
//# sourceMappingURL=Preferences.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"Preferences.js","sources":["Preferences/Preferences.app.js","Preferences/AccountDialogController.js","Preferences/FiltersDialogController.js","Preferences/PreferencesController.js"],"names":["configure","$stateProvider","$urlServiceProvider","state","abstract","views","preferences","templateUrl","controller","controllerAs","url","module","rules","otherwise","runBlock","$window","$log","$transitions","$state","DebugEnabled","defaultErrorHandler","onError","to","transition","name","ignored","error","detail","go","angular","config","run","$inject","AccountDialogController","$timeout","$mdDialog","FileUploader","Dialog","Settings","defaults","account","accountId","mailCustomFromEnabled","maxSize","vm","this","usesSSO","usesCASAuthentication","usesSAML2Authentication","_loadCertificate","security","hasCertificate","$certificate","then","crt","certificate","filterByExtension","item","isP12File","type","indexOf","test","form","certificateFilename","$setValidity","defaultPort","smtpDefaultPort","hostnameRE","emailRE","String","addressesSearchText","ckConfig","autoGrow_minHeight","toolbar","items","shouldNotGroupWhenFull","language","ckLocaleCode","encryption","smtpEncryption","uploader","activeUser","join","autoUpload","queueLimit","filters","fn","onAfterAddingFile","file","onSuccessItem","response","status","headers","clearQueue","_","assign","$$certificate","onErrorItem","alert","l","hasIdentities","filter","identities","isEditableIdentity","length","identity","isReadOnly","selectIdentity","index","selectedIdentity","hasDefaultIdentity","findIndex","isDefault","setDefaultIdentity","$event","$index","forEach","i","stopPropagation","canRemoveIdentity","removeIdentity","splice","addIdentity","firstReadonlyIndex","customFromIsReadonly","fullName","Math","max","showCkEditor","SOGoMailComposeMessageType","filterEmailAddresses","$query","defaultEmailAddresses","address","toLowerCase","importCertificate","queue","formData","password","certificatePassword","uploadItem","onBeforeUploadCertificate","removeCertificate","$removeCertificate","cancel","save","JSON","stringify","hide","FiltersDialogController","$scope","mailboxes","labels","validateForwardAddress","Preferences","sieveCapabilities","forwardEnabled","notificationEnabled","vacationEnabled","fieldLabels","subject","from","cc","to_or_cc","size","header","body","methodLabels","discard","keep","stop","redirect","notify","reject","fileinto","addflag","methods","intersection","keys","numberOperatorLabels","under","over","textOperatorLabels","is","is_not","contains","contains_not","matches","matches_not","regex","regex_not","hasRulesAndActions","requirements","actions","match","push","every","a","invalid","method","action","argument","err","message","addMailFilterRule","event","field","operator","removeMailFilterRule","addMailFilterAction","removeMailFilterAction","PreferencesController","$q","$mdMedia","$mdSidenav","$mdToast","sgSettings","focus","User","Account","Authentication","AddressBook","Date","beginOfDay","_loadAllMailboxes","mail","id","$getMailboxes","allMailboxes","$flattenMailboxes","all","domain","domains","forwardConstraints","defaultAddresses","adr","split","Error","forwardConstraintsDomains","$onInit","passwords","newPassword","newPasswordConfirmation","oldPassword","timeZonesList","timeZonesSearchText","autocomplete","forward","notification","mailLabelKeyRE","RegExp","emailSeparatorKeys","Notification","notificationMessage","notificationTranslated","SOGoMailAutoMarkAsReadMode","mailAutoMarkAsReadDelay","SOGoMailAutoMarkAsReadDelay","SOGoAlternateAvatar","$alternateAvatar","sieveVariablesCapability","hasActiveExternalSieveScripts","updateVacationDates","$valid","close","onLanguageChange","confirm","ok","quick","location","reload","onDesktopNotificationsChange","SOGoDesktopNotifications","authorizeNotifications","resetContactsCategories","SOGoContactsCategories","defaultContactsCategories","slice","$setDirty","resetCalendarCategories","SOGoCalendarCategories","defaultCalendarCategories","SOGoCalendarCategoriesColorsValues","values","addCalendarCategory","resetCalendarCategoryValidity","removeCalendarCategory","addContactCategory","removeContactCategory","onMailAutoMarkAsReadDelay","addMailAccount","ev","AuxiliaryMailAccounts","isNew","email","receipts","receiptAction","receiptNonRecipientAction","receiptOutsideDomainAction","receiptAnyAction","show","targetEvent","locals","CDefaultsSize","isArray","settings","Mail","ExpandedFolders","$omit","editMailAccount","data","cloneDeep","catch","noop","removeMailAccount","resetMailLabelValidity","addMailLabel","guid","SOGoMailLabelsColorsKeys","SOGoMailLabelsColorsValues","removeMailLabel","addMailFilter","active","SOGoMailLabelsColors","SOGoSieveFilters","editMailFilter","copy","removeMailFilter","onFiltersOrderChanged","_onFiltersOrderChanged","difference","Vacation","autoReplyEmailAddresses","addDefaultEmailAddresses","v","isDefined","union","userFilter","search","excludedUsers","minimumSearLine truncated
|
||||
{"version":3,"file":"Preferences.js","sources":["Preferences/Preferences.app.js","Preferences/AccountDialogController.js","Preferences/FiltersDialogController.js","Preferences/PreferencesController.js"],"names":["configure","$stateProvider","$urlServiceProvider","state","abstract","views","preferences","templateUrl","controller","controllerAs","url","module","rules","otherwise","runBlock","$window","$log","$transitions","$state","DebugEnabled","defaultErrorHandler","onError","to","transition","name","ignored","error","detail","go","angular","config","run","$inject","AccountDialogController","$timeout","$mdDialog","FileUploader","Dialog","Settings","defaults","account","accountId","mailCustomFromEnabled","maxSize","vm","this","usesSSO","usesCASAuthentication","usesSAML2Authentication","_loadCertificate","security","hasCertificate","$certificate","then","crt","certificate","filterByExtension","item","isP12File","type","indexOf","test","form","certificateFilename","$setValidity","defaultPort","smtpDefaultPort","hostnameRE","emailRE","String","addressesSearchText","ckConfig","autoGrow_minHeight","toolbar","items","shouldNotGroupWhenFull","language","ckLocaleCode","encryption","smtpEncryption","uploader","activeUser","join","autoUpload","queueLimit","filters","fn","onAfterAddingFile","file","onSuccessItem","response","status","headers","clearQueue","_","assign","$$certificate","onErrorItem","alert","l","hasIdentities","filter","identities","isEditableIdentity","length","identity","isReadOnly","selectIdentity","index","selectedIdentity","hasDefaultIdentity","findIndex","isDefault","setDefaultIdentity","$event","$index","forEach","i","stopPropagation","canRemoveIdentity","removeIdentity","splice","addIdentity","firstReadonlyIndex","customFromIsReadonly","fullName","Math","max","showCkEditor","SOGoMailComposeMessageType","filterEmailAddresses","$query","defaultEmailAddresses","address","toLowerCase","importCertificate","queue","formData","password","certificatePassword","uploadItem","onBeforeUploadCertificate","removeCertificate","$removeCertificate","cancel","save","JSON","stringify","hide","FiltersDialogController","$scope","mailboxes","labels","validateForwardAddress","Preferences","sieveCapabilities","forwardEnabled","notificationEnabled","vacationEnabled","fieldLabels","subject","from","cc","to_or_cc","size","header","body","methodLabels","discard","keep","stop","redirect","notify","reject","fileinto","addflag","methods","intersection","keys","numberOperatorLabels","under","over","textOperatorLabels","is","is_not","contains","contains_not","matches","matches_not","regex","regex_not","hasRulesAndActions","requirements","actions","match","push","every","a","invalid","method","action","argument","err","message","addMailFilterRule","event","field","operator","removeMailFilterRule","addMailFilterAction","removeMailFilterAction","PreferencesController","$q","$mdMedia","$mdSidenav","$mdToast","sgSettings","focus","User","Account","Authentication","AddressBook","Date","beginOfDay","_loadAllMailboxes","mail","id","$getMailboxes","allMailboxes","$flattenMailboxes","all","domain","domains","forwardConstraints","defaultAddresses","adr","split","Error","forwardConstraintsDomains","$onInit","passwords","newPassword","newPasswordConfirmation","oldPassword","timeZonesList","timeZonesSearchText","autocomplete","forward","notification","mailLabelKeyRE","RegExp","emailSeparatorKeys","Notification","notificationMessage","notificationTranslated","SOGoMailAutoMarkAsReadMode","mailAutoMarkAsReadDelay","SOGoMailAutoMarkAsReadDelay","SOGoAlternateAvatar","$alternateAvatar","sieveVariablesCapability","hasActiveExternalSieveScripts","updateVacationDates","$valid","close","onLanguageChange","confirm","ok","quick","location","reload","onDesktopNotificationsChange","SOGoDesktopNotifications","authorizeNotifications","resetContactsCategories","SOGoContactsCategories","defaultContactsCategories","slice","$setDirty","resetCalendarCategories","SOGoCalendarCategories","defaultCalendarCategories","SOGoCalendarCategoriesColorsValues","values","addCalendarCategory","resetCalendarCategoryValidity","removeCalendarCategory","addContactCategory","removeContactCategory","onMailAutoMarkAsReadDelay","addMailAccount","ev","AuxiliaryMailAccounts","isNew","email","receipts","receiptAction","receiptNonRecipientAction","receiptOutsideDomainAction","receiptAnyAction","show","targetEvent","locals","CDefaultsSize","isArray","settings","Mail","ExpandedFolders","$omit","editMailAccount","data","cloneDeep","catch","noop","removeMailAccount","resetMailLabelValidity","addMailLabel","guid","SOGoMailLabelsColorsKeys","SOGoMailLabelsColorsValues","removeMailLabel","addMailFilter","active","SOGoMailLabelsColors","SOGoSieveFilters","editMailFilter","copy","removeMailFilter","onFiltersOrderChanged","_onFiltersOrderChanged","difference","Vacation","autoReplyEmailAddresses","addDefaultEmailAddresses","v","isDefined","union","userFilter","search","excludedUsers","minimumSearLine truncated
|
||||
@@ -427,20 +427,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// We check if we're allowed or not to notify based on the domain defaults
|
||||
if (this.preferences.defaults.Notification && this.preferences.defaults.Notification.enabled &&
|
||||
this.preferences.defaults.Notification.notificationAddress) {
|
||||
addresses = this.preferences.defaults.Notification.notificationAddress;
|
||||
try {
|
||||
for (i = 0; i < addresses.length; i++) {
|
||||
validateForwardAddress(addresses[i]);
|
||||
}
|
||||
} catch (err) {
|
||||
Dialog.alert(l('Error'), err);
|
||||
sendForm = false;
|
||||
}
|
||||
}
|
||||
|
||||
// IMAP labels must be unique
|
||||
if (this.preferences.defaults.SOGoMailLabelsColorsKeys.length !=
|
||||
this.preferences.defaults.SOGoMailLabelsColorsValues.length ||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
!function(){"use strict";function d(e){this.component=e,this.component.attendees&&_.forEach(this.component.attendees,function(e){e.image=d.$gravatar(e.email,32)}),this.workDaysOnly=!0,this.slotStartTimeLimit=new Date,this.slotStartTimeLimit.setMinutes(0),this.slotStartTimeLimit.setHours(d.dayStartHour),this.slotEndTimeLimit=new Date,this.slotEndTimeLimit.setMinutes(0),this.slotEndTimeLimit.setHours(d.dayEndHour),this.$days=[],this.$futureFreebusyData={},this.updateFreeBusyCoverage(),this.updateFreeBusy(),0==this.$days.length&&this.getDays()}d.$factory=["$q","$timeout","$log","sgSettings","Attendees_ROLES","Preferences","User","Card","Gravatar","Resource",function(e,t,n,i,a,o,r,s,c,l){return angular.extend(d,{$q:e,$timeout:t,$log:n,$settings:i,$User:r,$Preferences:o,$Card:s,$gravatar:c,$$resource:new l(i.activeUser("folderURL")+"Calendar",i.activeUser()),ROLES:a}),d.dayStartHour=parseInt(o.defaults.SOGoDayStartTime.split(":")[0]),d.dayEndHour=parseInt(o.defaults.SOGoDayEndTime.split(":")[0]),d}];try{angular.module("SOGo.SchedulerUI")}catch(e){angular.module("SOGo.SchedulerUI",["SOGo.Common"])}angular.module("SOGo.SchedulerUI").constant("Attendees_ROLES",{REQ_PARTICIPANT:"req-participant",OPT_PARTICIPANT:"opt-participant",NON_PARTICIPANT:"non-participant",CHAIR:"chair"}).factory("Attendees",d.$factory),d.timeToQuarters=function(e){return 4*e.getHours()+Math.ceil(e.getMinutes()/15)},d.prototype.getLength=function(){return this.component.attendees?this.component.attendees.length:0},d.prototype.initOrganizer=function(e){var t=this,e=e&&e.isSubscription?d.$User.$filter(e.owner).then(function(e){e=e[0];t.component.organizer={uid:e.uid,name:e.cn,email:e.c_email}}):(this.component.organizer||(this.component.organizer={uid:d.$settings.activeUser("login"),name:d.$settings.activeUser("identification"),email:d.$settings.activeUser("email")}),d.$q.when());e.then(function(){t.updateFreeBusyAttendee(t.component.organizer)})},d.prototype.add=function(e,t){var n,i,a=this,o=d.$q.when();return e&&((!this.component.attendees||t&&t.organizerCalendar)&&this.initOrganizer(t?t.organizerCalendar:null),e.$isList({expandable:!0})?o=(i=d.$Card.$find(e.container,e.c_name)).$id().then(function(e){_.forEach(i.refs,function(e){n={name:e.c_cn,email:e.$preferredEmail(t?t.partial:null),role:d.ROLES.REQ_PARTICIPANT,partstat:"needs-action",uid:e.c_uid,$avatarIcon:"person"},_.find(a.component.attendees,function(e){return e.email==n.email})||(n.image=d.$gravatar(n.email,32),a.component.attendees?a.component.attendees.push(n):a.component.attendees=[n],a.updateFreeBusyAttendee(n))})}):(n={uid:e.c_uid,domain:e.c_domain,isMSExchange:e.ismsexchange,isGroup:e.$isList(),isExpandableGroup:!1,isResource:e.isresource,name:e.c_cn,email:e.$$email,role:d.ROLES.REQ_PARTICIPANT,partstat:"needs-action",$avatarIcon:e.$avatarIcon},_.find(this.attendees,function(e){return e.email==n.email})||(e.$isList()&&d.$Preferences.defaults.SOGoLDAPGroupExpansionEnabled&&(o=e.$members().then(function(e){n.members=e,n.isExpandableGroup=!0})),n.image=d.$gravatar(n.email,32),this.component.attendees?_.findIndex(this.component.attendees,{email:n.email})<0&&this.component.attendees.push(n):this.component.attendees=[n],this.updateFreeBusyAttendee(n)))),o},d.prototype.nextRole=function(t){var e=_.values(d.ROLES),n=_.findIndex(e,function(e){return t.role===e});t.role=e[++n%4]},d.prototype.hasAttendee=function(e){var t=_.find(this.component.attendees,function(t){return _.find(e.emails,function(e){return e.value==t.email})});return angular.isDefined(t)},d.prototype.remove=function(t){var e=_.findIndex(this.component.attendees,function(e){return e.email==t.email});-1<e&&this.component.attendees.splice(e,1),delete this.$futureFreebusyData[t.uid]},d.prototype.updateFreeBusyCoverage=function(){var o,r,s,e,c={};this.component.start&&this.component.end&&(o=new Date(this.component.start.getTime()),r=new Date(this.component.end.getTime()),this.component.isAllDay?(o.setHours(d.dayStartHour),o.setMinutes(0),r.setHours(d.dayEndHour),r.setMinutes(0),s=e=0):(s=parseInt(o.getMinutes()/15+.5),e=parseInt(r.getMinutes()/15+.5)),o.setMinutes(15*s),r.setMinutes(15*e),_.forEach(o.beginOfDay().daysUpTo(r.beginOfDay()),function(e,t){var n,i=(e=e<o?new Date(o.getTime()):e).getDate(),a=e.getDayString();if(a===o.getDayString())for(n=e.getHours().toString(),c[a]={},c[a][n]=[];0<s;)c[a][n].push(0),s--;else e=e.beginOfDay(),c[a]={};for(;e.getTime()<r.getTime()&&e.getDate()==i;)n=e.getHours().toString(),angular.isUndefined(c[a][n])&&(c[a][n]=[]),c[a][n].push(1),e.addMinutes(15)}),this.freebusy=c)},d.prototype.coversFreeBusy=function(e,t,n){return this.freebusy&&angular.isDefined(this.freebusy[e])&&angular.isDefined(this.freebusy[e][t])&&1==this.freebusy[e][t][n]},d.prototype.getDays=function(e){var t,n,i,a=this;return e?(t=e,(n=new Date(e.getTime())).addMinutes(this.component.delta)):(t=this.component.start,n=this.component.end),(0===this.$days.length||_.findIndex(this.$days,["getDayString",t.getDayString()])<0||_Line truncated
|
||||
!function(){"use strict";function d(e){this.component=e,this.component.attendees&&_.forEach(this.component.attendees,function(e){e.image=d.$gravatar(e.email,32)}),this.workDaysOnly=!0,this.slotStartTimeLimit=new Date,this.slotStartTimeLimit.setMinutes(0),this.slotStartTimeLimit.setHours(d.dayStartHour),this.slotEndTimeLimit=new Date,this.slotEndTimeLimit.setMinutes(0),this.slotEndTimeLimit.setHours(d.dayEndHour),this.$days=[],this.$futureFreebusyData={},this.updateFreeBusyCoverage(),this.updateFreeBusy(),0==this.$days.length&&this.getDays()}d.$factory=["$q","$timeout","$log","sgSettings","Attendees_ROLES","Preferences","User","Card","Gravatar","Resource",function(e,t,n,i,a,o,r,s,c,l){return angular.extend(d,{$q:e,$timeout:t,$log:n,$settings:i,$User:r,$Preferences:o,$Card:s,$gravatar:c,$$resource:new l(i.activeUser("folderURL")+"Calendar",i.activeUser()),ROLES:a}),d.dayStartHour=parseInt(o.defaults.SOGoDayStartTime.split(":")[0]),d.dayEndHour=parseInt(o.defaults.SOGoDayEndTime.split(":")[0]),d}];try{angular.module("SOGo.SchedulerUI")}catch(e){angular.module("SOGo.SchedulerUI",["SOGo.Common"])}angular.module("SOGo.SchedulerUI").constant("Attendees_ROLES",{REQ_PARTICIPANT:"req-participant",OPT_PARTICIPANT:"opt-participant",NON_PARTICIPANT:"non-participant",CHAIR:"chair"}).factory("Attendees",d.$factory),d.timeToQuarters=function(e){return 4*e.getHours()+Math.ceil(e.getMinutes()/15)},d.prototype.getLength=function(){return this.component.attendees?this.component.attendees.length:0},d.prototype.initOrganizer=function(e){var t=this,e=e&&e.isSubscription?d.$User.$filter(e.owner).then(function(e){e=e[0];t.component.organizer={uid:e.uid,name:e.cn,email:e.c_email}}):(this.component.organizer||(this.component.organizer={uid:d.$settings.activeUser("login"),name:d.$settings.activeUser("identification"),email:d.$settings.activeUser("email")}),d.$q.when());e.then(function(){t.updateFreeBusyAttendee(t.component.organizer)})},d.prototype.add=function(e,t){var n,i,a=this,o=d.$q.when();return e&&((!this.component.attendees||t&&t.organizerCalendar)&&this.initOrganizer(t?t.organizerCalendar:null),e.$isList({expandable:!0})?o=(i=d.$Card.$find(e.container,e.c_name)).$id().then(function(e){_.forEach(i.refs,function(e){n={name:e.c_cn,email:e.$preferredEmail(t?t.partial:null),role:d.ROLES.REQ_PARTICIPANT,partstat:"needs-action",uid:e.c_uid,$avatarIcon:"person"},_.find(a.component.attendees,function(e){return e.email==n.email})||(n.image=d.$gravatar(n.email,32),a.component.attendees?a.component.attendees.push(n):a.component.attendees=[n],a.updateFreeBusyAttendee(n))})}):(n={uid:e.c_uid,domain:e.c_domain,isMSExchange:e.ismsexchange,isGroup:e.$isList(),isExpandableGroup:!1,isResource:e.isresource,name:e.c_cn,email:e.$$email,role:d.ROLES.REQ_PARTICIPANT,partstat:"needs-action",$avatarIcon:e.$avatarIcon},_.find(this.attendees,function(e){return e.email==n.email})||(e.$isList()&&d.$Preferences.defaults.SOGoLDAPGroupExpansionEnabled&&(o=e.$members().then(function(e){n.members=e,n.isExpandableGroup=!0})),n.image=d.$gravatar(n.email,32),this.component.attendees?_.findIndex(this.component.attendees,{email:n.email})<0&&this.component.attendees.push(n):this.component.attendees=[n],this.updateFreeBusyAttendee(n)))),o},d.prototype.nextRole=function(t){var e=_.values(d.ROLES),n=_.findIndex(e,function(e){return t.role===e});t.role=e[++n%4]},d.prototype.hasAttendee=function(e){var t=_.find(this.component.attendees,function(t){return _.find(e.emails,function(e){return e.value==t.email})});return angular.isDefined(t)},d.prototype.remove=function(t){var e=_.findIndex(this.component.attendees,function(e){return e.email==t.email});-1<e&&this.component.attendees.splice(e,1),delete this.$futureFreebusyData[t.uid]},d.prototype.updateFreeBusyCoverage=function(){var o,r,s,e,c={};this.component.start&&this.component.end&&(o=new Date(this.component.start.getTime()),r=new Date(this.component.end.getTime()),this.component.isAllDay?(o.setHours(d.dayStartHour),o.setMinutes(0),r.setHours(d.dayEndHour),r.setMinutes(0),s=e=0):(s=parseInt(o.getMinutes()/15+.5),e=parseInt(r.getMinutes()/15+.5)),o.setMinutes(15*s),r.setMinutes(15*e),_.forEach(o.beginOfDay().daysUpTo(r.beginOfDay()),function(e,t){var n,i=(e=e<o?new Date(o.getTime()):e).getDate(),a=e.getDayString();if(a===o.getDayString())for(n=e.getHours().toString(),c[a]={},c[a][n]=[];0<s;)c[a][n].push(0),s--;else e=e.beginOfDay(),c[a]={};for(;e.getTime()<r.getTime()&&e.getDate()==i;)n=e.getHours().toString(),angular.isUndefined(c[a][n])&&(c[a][n]=[]),c[a][n].push(1),e.addMinutes(15)}),this.freebusy=c)},d.prototype.coversFreeBusy=function(e,t,n){return this.freebusy&&angular.isDefined(this.freebusy[e])&&angular.isDefined(this.freebusy[e][t])&&1==this.freebusy[e][t][n]},d.prototype.getDays=function(e){var t,n,i,a=this;return e?(t=e,(n=new Date(e.getTime())).addMinutes(this.component.delta)):(t=this.component.start,n=this.component.end),(0===this.$days.length||_.findIndex(this.$days,["getDayString",t.getDayString()])<0||_Line truncated
|
||||
//# sourceMappingURL=Scheduler.services.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"Scheduler.services.js","sources":["Scheduler/Attendees.service.js","Scheduler/Calendar.service.js","Scheduler/Component.service.js","Scheduler/CalendarController.js","Scheduler/CalendarListController.js","Scheduler/CalendarsController.js","Scheduler/ComponentController.js","Scheduler/sgCalendarDay.directive.js","Scheduler/sgCalendarDayBlock.directive.js","Scheduler/sgCalendarDayTable.directive.js","Scheduler/sgCalendarGhost.directive.js","Scheduler/sgCalendarListEvent.directive.js","Scheduler/sgCalendarListItem.directive.js","Scheduler/sgCalendarMonthDay.directive.js","Scheduler/sgCalendarMonthEvent.directive.js","Scheduler/sgCalendarPrintStylesheet.directive.js","Scheduler/sgCalendarScrollView.directive.js","Scheduler/sgCategoryStylesheet.directive.js","Scheduler/sgDraggableCalendarBlock.directive.js","Scheduler/sgFreebusy.directive.js","Scheduler/sgFreebusyDay.directive.js","Scheduler/sgNowLine.directive.js"],"names":["Attendees","component","this","attendees","_","forEach","attendee","image","$gravatar","email","workDaysOnly","slotStartTimeLimit","Date","setMinutes","setHours","dayStartHour","slotEndTimeLimit","dayEndHour","$days","$futureFreebusyData","updateFreeBusyCoverage","updateFreeBusy","length","getDays","$factory","$q","$timeout","$log","Settings","ROLES","Preferences","User","Card","Gravatar","Resource","angular","extend","$settings","$User","$Preferences","$Card","$$resource","activeUser","parseInt","defaults","SOGoDayStartTime","split","SOGoDayEndTime","module","e","constant","REQ_PARTICIPANT","OPT_PARTICIPANT","NON_PARTICIPANT","CHAIR","factory","timeToQuarters","dateTime","getHours","Math","ceil","getMinutes","prototype","getLength","initOrganizer","calendar","_this","promise","isSubscription","$filter","owner","then","results","organizer","uid","name","cn","c_email","when","updateFreeBusyAttendee","add","card","options","list","organizerCalendar","$isList","expandable","$find","container","c_name","$id","listId","refs","ref","c_cn","$preferredEmail","partial","role","partstat","c_uid","$avatarIcon","find","o","push","domain","c_domain","isMSExchange","ismsexchange","isGroup","isExpandableGroup","isResource","isresource","$$email","SOGoLDAPGroupExpansionEnabled","$members","members","findIndex","nextRole","roles","values","index","hasAttendee","emails","value","isDefined","remove","currentAttendee","splice","roundedStart","roundedEnd","startQuarter","endQuarter","freebusy","start","end","getTime","isAllDay","beginOfDay","daysUpTo","date","hourKey","currentDay","getDate","dayKey","getDayString","toString","isUndefined","addMinutes","coversFreeBusy","day","hour","quarter","refDate","sd","ed","formatFcn","delta","addDays","$mdDateLocaleProvider","formatDate","$dateFormat","SOGoLongDateFormat","stringWithSeparator","promises","filter","all","resource","days","params","sday","map","eday","userResource","intersection","keys","fetch","data","i","forwardFindDate","currentStart","foundDate","maxOffset","endLimit","duration","offset","firstStep","floor","currentEntries","indexOf","startLimit","foundTime","testDuration","setTime","forwardAdjustCurrentStart","getDay","backwardFindDate","lastIndexOf","testOffset","debug","backwardAdjustCurrentStart","findSlot","direction","findDate","adjustCurrentStart","clone","setSeconds","step","catch","err","mergeFreebusy","startDay","j","attendeeEntries","flatMap","count","reject","l","Calendar","futureCalendarData","init","id","newCalendarData","create","$unwrap","Component","Acl","$Component","$$Acl","$view","EventDragDayLength","EventDragHorizontalOffset","ConflictHTTPErrorCode","$defaultCalendar","SOGoDefaultCalendar","$findAll","active","$add","isWebCalendar","$webcalendars","$subscriptions","$calendars","sibling","localeCompare","settings","FoldersOrder","saveFoldersOrder","$reloadAll","writable","contextId","calendars","union","isOwned","acls","objectCreator","calendarData","group","login","$get","$getIndex","$subscribe","path","$addWebCalendar","url","d","defer","urls","webCalendarURL","post","isEditable","isRemote","JSON","stringify","undefined","resolve","response","status","reloadWebCalendars","$error","statusText","$deleteComponents","components","pid","uids","saveFoldersActivation","ids","request","folders","color","$acl","isSuperUser","$shadowData","$omit","$futureCalendarData","getClassName","base","$rename","$save","$delete","$reset","key","save","setCredentials","username","password","export","realOwnerId","type","filename","webDavICSURL","ownerPaths","substring","join","open","downloadProvisioningProfile","$setActivation","$getComponent","componentId","recurrenceId","isError","isObject","copy","futureComponentData","newComponentData","newguid","isNew","$rootScope","Component_STATUS","STATUS","$Attendees","timeFormat","$query","search","$queryEvents","sort","asc","filterpopup","$queryTasks","$refreshTimeout","$ghost","EventsFilterState","TasksFilterState","EventsSortingState","TasksSortingState","show_completed","ShowCompletedLine truncated
|
||||
{"version":3,"file":"Scheduler.services.js","sources":["Scheduler/Attendees.service.js","Scheduler/Calendar.service.js","Scheduler/Component.service.js","Scheduler/CalendarController.js","Scheduler/CalendarListController.js","Scheduler/CalendarsController.js","Scheduler/ComponentController.js","Scheduler/sgCalendarDay.directive.js","Scheduler/sgCalendarDayBlock.directive.js","Scheduler/sgCalendarDayTable.directive.js","Scheduler/sgCalendarGhost.directive.js","Scheduler/sgCalendarListEvent.directive.js","Scheduler/sgCalendarListItem.directive.js","Scheduler/sgCalendarMonthDay.directive.js","Scheduler/sgCalendarMonthEvent.directive.js","Scheduler/sgCalendarPrintStylesheet.directive.js","Scheduler/sgCalendarScrollView.directive.js","Scheduler/sgCategoryStylesheet.directive.js","Scheduler/sgDraggableCalendarBlock.directive.js","Scheduler/sgFreebusy.directive.js","Scheduler/sgFreebusyDay.directive.js","Scheduler/sgNowLine.directive.js"],"names":["Attendees","component","this","attendees","_","forEach","attendee","image","$gravatar","email","workDaysOnly","slotStartTimeLimit","Date","setMinutes","setHours","dayStartHour","slotEndTimeLimit","dayEndHour","$days","$futureFreebusyData","updateFreeBusyCoverage","updateFreeBusy","length","getDays","$factory","$q","$timeout","$log","Settings","ROLES","Preferences","User","Card","Gravatar","Resource","angular","extend","$settings","$User","$Preferences","$Card","$$resource","activeUser","parseInt","defaults","SOGoDayStartTime","split","SOGoDayEndTime","module","e","constant","REQ_PARTICIPANT","OPT_PARTICIPANT","NON_PARTICIPANT","CHAIR","factory","timeToQuarters","dateTime","getHours","Math","ceil","getMinutes","prototype","getLength","initOrganizer","calendar","_this","promise","isSubscription","$filter","owner","then","results","organizer","uid","name","cn","c_email","when","updateFreeBusyAttendee","add","card","options","list","organizerCalendar","$isList","expandable","$find","container","c_name","$id","listId","refs","ref","c_cn","$preferredEmail","partial","role","partstat","c_uid","$avatarIcon","find","o","push","domain","c_domain","isMSExchange","ismsexchange","isGroup","isExpandableGroup","isResource","isresource","$$email","SOGoLDAPGroupExpansionEnabled","$members","members","findIndex","nextRole","roles","values","index","hasAttendee","emails","value","isDefined","remove","currentAttendee","splice","roundedStart","roundedEnd","startQuarter","endQuarter","freebusy","start","end","getTime","isAllDay","beginOfDay","daysUpTo","date","hourKey","currentDay","getDate","dayKey","getDayString","toString","isUndefined","addMinutes","coversFreeBusy","day","hour","quarter","refDate","sd","ed","formatFcn","delta","addDays","$mdDateLocaleProvider","formatDate","$dateFormat","SOGoLongDateFormat","stringWithSeparator","promises","filter","all","resource","days","params","sday","map","eday","userResource","intersection","keys","fetch","data","i","forwardFindDate","currentStart","foundDate","maxOffset","endLimit","duration","offset","firstStep","floor","currentEntries","indexOf","startLimit","foundTime","testDuration","setTime","forwardAdjustCurrentStart","getDay","backwardFindDate","lastIndexOf","testOffset","debug","backwardAdjustCurrentStart","findSlot","direction","findDate","adjustCurrentStart","clone","setSeconds","step","catch","err","mergeFreebusy","startDay","j","attendeeEntries","flatMap","count","reject","l","Calendar","futureCalendarData","init","id","newCalendarData","create","$unwrap","Component","Acl","$Component","$$Acl","$view","EventDragDayLength","EventDragHorizontalOffset","ConflictHTTPErrorCode","$defaultCalendar","SOGoDefaultCalendar","$findAll","active","$add","isWebCalendar","$webcalendars","$subscriptions","$calendars","sibling","localeCompare","settings","FoldersOrder","saveFoldersOrder","$reloadAll","writable","contextId","calendars","union","isOwned","acls","objectCreator","calendarData","group","login","$get","$getIndex","$subscribe","path","$addWebCalendar","url","d","defer","urls","webCalendarURL","post","isEditable","isRemote","JSON","stringify","undefined","resolve","response","status","reloadWebCalendars","$error","statusText","$deleteComponents","components","pid","uids","saveFoldersActivation","ids","request","folders","color","$acl","isSuperUser","$shadowData","$omit","$futureCalendarData","getClassName","base","$rename","$save","$delete","$reset","key","save","setCredentials","username","password","export","realOwnerId","type","filename","webDavICSURL","ownerPaths","substring","join","open","downloadProvisioningProfile","$setActivation","$getComponent","componentId","recurrenceId","isError","isObject","copy","futureComponentData","newComponentData","newguid","isNew","$rootScope","Component_STATUS","STATUS","$Attendees","timeFormat","$query","search","$queryEvents","sort","asc","filterpopup","$queryTasks","$refreshTimeout","$ghost","EventsFilterState","TasksFilterState","EventsSortingState","TasksSortingState","show_completed","ShowCompletedLine truncated
|
||||
@@ -840,8 +840,8 @@
|
||||
/**
|
||||
* @function hasJitsiUrl
|
||||
* @memberof Component.prototype
|
||||
* @desc Check if the there is a jisti url
|
||||
* @returns true if there is a jisti url
|
||||
* @desc Check if the there is a jitsi url
|
||||
* @returns true if there is a jitsi url
|
||||
*/
|
||||
Component.prototype.hasJitsiUrl = function() {
|
||||
if (angular.isUndefined(this.attachUrls)) {
|
||||
|
||||
@@ -316,9 +316,12 @@
|
||||
|
||||
this.addJitsiUrl = function () {
|
||||
var jitsiBaseUrl = "https://meet.jit.si";
|
||||
var jitsiRoomPrefix = "SOGo_meeting/";
|
||||
if(this.preferences.defaults && this.preferences.defaults.SOGoCalendarJitsiBaseUrl)
|
||||
jitsiBaseUrl = this.preferences.defaults.SOGoCalendarJitsiBaseUrl;
|
||||
var jitsiUrl = jitsiBaseUrl + "/SOGo_meeting/" + crypto.randomUUID();
|
||||
if(this.preferences.defaults && this.preferences.defaults.SOGoCalendarJitsiRoomPrefix)
|
||||
jitsiRoomPrefix = this.preferences.defaults.SOGoCalendarJitsiRoomPrefix;
|
||||
var jitsiUrl = jitsiBaseUrl + "/" + jitsiRoomPrefix + crypto.randomUUID();
|
||||
var i = this.component.addAttachUrl(jitsiUrl);
|
||||
focus('attachUrl_' + i);
|
||||
};
|
||||
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* AngularJS-Material-Mocks
|
||||
*
|
||||
* Developers interested in running their own custom unit tests WITH angular-material.js loaded...
|
||||
* must also include this *mocks* file. Similar to `angular-mocks.js`, `angular-material-mocks.js`
|
||||
* will override and disable specific AngularJS Material performance settings:
|
||||
*
|
||||
* - Disabled Theme CSS rule generations
|
||||
* - Forces $mdAria.expectWithText() to be synchronous
|
||||
* - Mocks $$rAF.throttle()
|
||||
* - Captures flush exceptions from $$rAF
|
||||
*/
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(window, angular, undefined) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// Allow our code to know when they are running inside of a test so they can expose extra services
|
||||
// that should NOT be exposed to the public but that should be tested.
|
||||
//
|
||||
// As an example, see input.js which exposes some animation-related methods.
|
||||
window._mdMocksIncluded = true;
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name ngMaterial-mock
|
||||
* @packageName angular-material-mocks
|
||||
*
|
||||
* @description
|
||||
* The `ngMaterial-mock` module provides support
|
||||
*/
|
||||
angular.module('ngMaterial-mock', ['ngMock', 'ngAnimateMock', 'material.core']).config([
|
||||
'$provide',
|
||||
function($provide) {
|
||||
$provide.factory('$material', [
|
||||
'$animate', '$timeout',
|
||||
function($animate, $timeout) {
|
||||
return {
|
||||
flushOutstandingAnimations: function() {
|
||||
// this code is placed in a try-catch statement
|
||||
// since 1.3 and 1.4 handle their animations differently
|
||||
// and there may be situations where follow-up animations
|
||||
// are run in one version and not the other
|
||||
try {
|
||||
$animate.flush();
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
},
|
||||
flushInterimElement: function() {
|
||||
this.flushOutstandingAnimations();
|
||||
$timeout.flush();
|
||||
this.flushOutstandingAnimations();
|
||||
$timeout.flush();
|
||||
this.flushOutstandingAnimations();
|
||||
$timeout.flush();
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
||||
/**
|
||||
* AngularJS Material dynamically generates Style tags
|
||||
* based on themes and palettes; for each ng-app.
|
||||
*
|
||||
* For testing, we want to disable generation and
|
||||
* <style> DOM injections. So we clear the huge THEME
|
||||
* styles while testing...
|
||||
*/
|
||||
$provide.constant('$MD_THEME_CSS', '/**/');
|
||||
|
||||
/**
|
||||
* Add throttle() and wrap .flush() to catch `no callbacks present`
|
||||
* errors
|
||||
*/
|
||||
$provide.decorator('$$rAF', function throttleInjector($delegate) {
|
||||
$delegate.throttle = function(cb) {
|
||||
return function() {
|
||||
cb.apply(this, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
const ngFlush = $delegate.flush;
|
||||
$delegate.flush = function() {
|
||||
try {
|
||||
ngFlush();
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
return $delegate;
|
||||
});
|
||||
|
||||
/**
|
||||
* Capture $timeout.flush() errors: "No deferred tasks to be flushed"
|
||||
* errors
|
||||
*/
|
||||
$provide.decorator('$timeout', function throttleInjector($delegate) {
|
||||
const ngFlush = $delegate.flush;
|
||||
$delegate.flush = function() {
|
||||
const args = Array.prototype.slice.call(arguments);
|
||||
try {
|
||||
ngFlush.apply($delegate, args);
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
return $delegate;
|
||||
});
|
||||
}
|
||||
]);
|
||||
|
||||
/**
|
||||
* Stylesheet Mocks used by `animateCss.spec.js`
|
||||
*/
|
||||
window.createMockStyleSheet = function createMockStyleSheet(doc, wind) {
|
||||
doc = doc ? doc[0] : window.document;
|
||||
wind = wind || window;
|
||||
|
||||
const node = doc.createElement('style');
|
||||
const head = doc.getElementsByTagName('head')[0];
|
||||
head.appendChild(node);
|
||||
|
||||
const ss = doc.styleSheets[doc.styleSheets.length - 1];
|
||||
|
||||
return {
|
||||
addRule: function(selector, styles) {
|
||||
styles = addVendorPrefix(styles);
|
||||
|
||||
try {
|
||||
ss.insertRule(selector + '{ ' + styles + '}', 0);
|
||||
} catch (e) {
|
||||
try {
|
||||
ss.addRule(selector, styles);
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e2) {}
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
head.removeChild(node);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Decompose styles, attached specific vendor prefixes
|
||||
* and recompose...
|
||||
* e.g.
|
||||
* 'transition:0.5s linear all; font-size:100px;'
|
||||
* becomes
|
||||
* '-webkit-transition:0.5s linear all; transition:0.5s linear all; font-size:100px;'
|
||||
*/
|
||||
function addVendorPrefix(styles) {
|
||||
const cache = {};
|
||||
|
||||
// Decompose into cache registry
|
||||
styles.match(/([-A-Za-z]*)\w:\w*([A-Za-z0-9.\-\s]*)/gi).forEach(function(style) {
|
||||
const pair = style.split(':');
|
||||
const key = pair[0];
|
||||
|
||||
switch (key) {
|
||||
case 'transition':
|
||||
case 'transform':
|
||||
case 'animation':
|
||||
case 'transition-duration':
|
||||
case 'animation-duration':
|
||||
cache[key] = cache['-webkit-' + key] = pair[1];
|
||||
break;
|
||||
default:
|
||||
cache[key] = pair[1];
|
||||
}
|
||||
});
|
||||
|
||||
// Recompose full style object (as string)
|
||||
styles = '';
|
||||
angular.forEach(cache, function(value, key) {
|
||||
styles = styles + key + ':' + value + '; ';
|
||||
});
|
||||
|
||||
return styles;
|
||||
}
|
||||
};
|
||||
})(window, window.angular);
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* AngularJS Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v1.2.5
|
||||
*/
|
||||
!function(L,be,ge){"use strict";function e(e,t){if(t.has("$swipe")){e.warn("You are using the ngTouch module. \nAngularJS Material already has mobile click, tap, and swipe support... \nngTouch is not supported with AngularJS Material!")}}function t(e,t){e.decorator("$$rAF",["$delegate",n]),e.decorator("$q",["$delegate",o]),t.theme("default").primaryPalette("indigo").accentPalette("pink").warnPalette("deep-orange").backgroundPalette("grey")}function n(i){return i.throttle=function(e){var t,n,o,r;return function(){t=arguments,r=this,o=e,n||(n=!0,i(function(){o.apply(r,Array.prototype.slice.call(t)),n=!1}))}},i}function o(e){return e.resolve||(e.resolve=e.when),e}function r(i){return{restrict:"A",link:{pre:function(e,t,n){var o=n.mdAutoFocus||n.mdAutofocus||n.mdSidenavFocus;r(i(o)(e)),o&&e.$watch(o,r);function r(e){be.isUndefined(e)&&(e=!0),t.toggleClass("md-autofocus",!!e)}}}}}function i(e,d){function s(){return!0}e&&!be.isArray(e)&&(e=Array.prototype.slice.call(e)),d=!!d;var l=e||[];return{items:function(){return[].concat(l)},count:function(){return l.length},inRange:c,contains:t,indexOf:m,itemAt:function(e){return c(e)?l[e]:null},findBy:function(t,n){return l.filter(function(e){return e[t]===n})},add:function(e,t){if(!e)return-1;be.isNumber(t)||(t=l.length);return l.splice(t,0,e),m(e)},remove:function(e){t(e)&&l.splice(m(e),1)},first:u,last:p,next:be.bind(null,n,!1),previous:be.bind(null,n,!0),hasPrevious:function(e){return!!e&&c(m(e)-1)},hasNext:function(e){return!!e&&c(m(e)+1)}};function c(e){return l.length&&-1<e&&e<l.length}function m(e){return l.indexOf(e)}function t(e){return e&&-1<m(e)}function u(){return l.length?l[0]:null}function p(){return l.length?l[l.length-1]:null}function n(e,t,n,o){n=n||s;for(var r=m(t);;){if(!c(r))return null;var i=r+(e?-1:1),a=null;if(c(i)?a=l[i]:d&&(i=m(a=e?p():u())),null===a||i===o)return null;if(n(a))return a;be.isUndefined(o)&&(o=i),r=i}}}function a(a,t,o){var i={},d={},r={},n={};return e.getResponsiveAttribute=function(e,t){for(var n=0;n<a.MEDIA_PRIORITY.length;n++){var o=a.MEDIA_PRIORITY[n];if(d[i[o]].matches){var r=l(e,t+"-"+o);if(e[r])return e[r]}}return e[l(e,t)]},e.getQuery=function(e){return d[e]},e.watchResponsiveAttributes=function(e,o,r){var i=[];return e.forEach(function(e){var t=l(o,e);for(var n in be.isDefined(o[t])&&i.push(o.$observe(t,be.bind(void 0,r,null))),a.MEDIA)t=l(o,e+"-"+n),be.isDefined(o[t])&&i.push(o.$observe(t,be.bind(void 0,r,n)))}),function(){i.forEach(function(e){e()})}},e;function e(e){var t=i[e];be.isUndefined(t)&&(t=i[e]=function(e){return a.MEDIA[e]||("("!==e.charAt(0)?"("+e+")":e)}(e));var n=r[t];return be.isUndefined(n)&&(n=function(e){var t=d[e];t=t||(d[e]=o.matchMedia(e));return t.addListener(s),r[t.media]=!!t.matches}(t)),n}function s(e){t.$evalAsync(function(){r[e.media]=!!e.matches})}function l(e,t){return n[t]||(n[t]=e.$normalize(t))}}function d(e,t){var o=["data","x"];return e?t?n(e):r(e):{buildList:r,buildSelector:n,hasAttribute:function(e,t){if(!(e=i(e)))return!1;for(var n=r(t),o=0;o<n.length;o++)if(e.hasAttribute(n[o]))return!0;return!1},removeAttribute:function(t,e){if(!(t=i(t)))return;r(e).forEach(function(e){t.removeAttribute(e)})}};function r(n){return(n=be.isArray(n)?n:[n]).forEach(function(t){o.forEach(function(e){n.push(e+"-"+t)})}),n}function n(e){return r(e=be.isArray(e)?e:[e]).map(function(e){return"["+e+"]"}).join(",")}function i(e){if((e=e[0]||e).nodeType)return e}}function A(e){return e.replace(/-[a-z]/g,function(e){return e.charAt(1).toUpperCase()})}var w,_,k,x,N,s,l,c,m,u,p,h,f,b,g,E,v,$,M,y,C,T;function S(o,r,s,i){var a=this.showWarnings;return{expect:d,expectAsync:l,expectWithText:function(e,t){var n=c(e)||"";-1<n.indexOf(i.startSymbol())?l(e,t,function(){return c(e)}):d(e,t,n)},expectWithoutText:function(e,t){var n=c(e);-1<n.indexOf(i.startSymbol())||n||d(e,t,n)},getText:c,hasAriaLabel:m,parentHasAriaLabel:function e(t,n){n=n||1;var o=be.element(t)[0]||t;if(!o.parentNode)return!1;if(r(o.parentNode))return!0;n--;if(n)return e(o.parentNode,n);return!1;function r(e){if(!m(e))return!1;if(e.hasAttribute("role"))switch(e.getAttribute("role").toLowerCase()){case"command":case"definition":case"directory":case"grid":case"list":case"listitem":case"log":case"marquee":case"menu":case"menubar":case"note":case"presentation":case"separator":case"scrollbar":case"status":case"tablist":return!1}switch(e.tagName.toLowerCase()){case"abbr":case"acronym":case"address":case"applet":case"audio":case"b":case"bdi":case"bdo":case"big":case"blockquote":case"br":case"canvas":case"caption":case"center":case"cite":case"code":case"col":case"data":case"dd":case"del":case"dfn":case"dir":case"div":case"dl":case"em":case"embed":case"fieldset":case"figcaption":case"font":case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":case"hgroup":case"html":case"i":case"ins":case"isindex":case"kbd":case"keygen":case"label":case"legend":case"li":case"map":case"mark":case"menu":case"object":case"ol":case"output":case"pre":case"presentation":case"q":case"Line truncated
|
||||
+7556
File diff suppressed because it is too large.
Load diff
+1058
File diff suppressed because it is too large.
Load diff
Vendored
+1125
File diff suppressed because it is too large.
Load diff
Loaded 100 of 106 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user