2006-06-15 21:34:10 +02:00
|
|
|
/*
|
2016-03-10 22:34:06 +01:00
|
|
|
Copyright (C) 2005-2016 Inverse inc.
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2010-09-09 19:03:27 +02:00
|
|
|
This file is part of SOGo
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2010-09-09 19:03:27 +02:00
|
|
|
SOGo is free software; you can redistribute it and/or modify it under
|
2006-06-15 21:34:10 +02:00
|
|
|
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.
|
|
|
|
|
2010-09-09 19:03:27 +02:00
|
|
|
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
|
2006-06-15 21:34:10 +02:00
|
|
|
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 OGo; see the file COPYING. If not, write to the
|
|
|
|
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
2007-06-29 23:56:21 +02:00
|
|
|
|
|
|
|
#import <GDLAccess/EOAdaptorChannel.h>
|
|
|
|
#import <GDLContentStore/GCSChannelManager.h>
|
2010-08-19 19:40:28 +02:00
|
|
|
#import <GDLContentStore/GCSFolderManager.h>
|
2016-03-10 22:34:06 +01:00
|
|
|
#import <GDLContentStore/GCSFolderType.h>
|
2010-08-19 19:40:28 +02:00
|
|
|
#import <GDLContentStore/GCSAlarmsFolder.h>
|
2012-10-22 16:09:13 +02:00
|
|
|
#import <GDLContentStore/GCSSessionsFolder.h>
|
2007-06-29 23:56:21 +02:00
|
|
|
|
2016-12-15 20:22:07 +01:00
|
|
|
#import <NGObjWeb/NSException+HTTP.h>
|
2007-06-29 23:56:21 +02:00
|
|
|
#import <NGObjWeb/SoClassSecurityInfo.h>
|
|
|
|
#import <NGObjWeb/WOContext.h>
|
2009-12-09 00:18:12 +01:00
|
|
|
#import <NGObjWeb/WORequest+So.h>
|
2010-05-21 14:28:48 +02:00
|
|
|
#import <NGObjWeb/WOResponse.h>
|
2007-06-29 23:56:21 +02:00
|
|
|
|
|
|
|
#import <NGExtensions/NGBundleManager.h>
|
2011-03-30 15:42:57 +02:00
|
|
|
#import <NGExtensions/NGLogger.h>
|
|
|
|
#import <NGExtensions/NGLoggerManager.h>
|
2007-06-29 23:56:21 +02:00
|
|
|
#import <NGExtensions/NSNull+misc.h>
|
|
|
|
#import <NGExtensions/NSObject+Logs.h>
|
|
|
|
#import <NGExtensions/NSProcessInfo+misc.h>
|
2007-11-04 23:31:50 +01:00
|
|
|
#import <NGExtensions/NSString+Encoding.h>
|
2008-05-03 01:14:26 +02:00
|
|
|
#import <NGExtensions/NSString+misc.h>
|
2007-06-29 23:56:21 +02:00
|
|
|
|
|
|
|
#import <WEExtensions/WEResourceManager.h>
|
|
|
|
|
2010-02-18 23:08:48 +01:00
|
|
|
#import <SOGo/SOGoBuild.h>
|
2009-11-29 05:19:32 +01:00
|
|
|
#import <SOGo/SOGoCache.h>
|
|
|
|
#import <SOGo/SOGoDAVAuthenticator.h>
|
|
|
|
#import <SOGo/SOGoPermissions.h>
|
2010-06-02 18:35:59 +02:00
|
|
|
#import <SOGo/SOGoPublicBaseFolder.h>
|
2010-02-18 22:55:40 +01:00
|
|
|
#import <SOGo/SOGoProductLoader.h>
|
2009-11-29 05:19:32 +01:00
|
|
|
#import <SOGo/SOGoProxyAuthenticator.h>
|
|
|
|
#import <SOGo/SOGoUser.h>
|
|
|
|
#import <SOGo/SOGoSystemDefaults.h>
|
|
|
|
#import <SOGo/SOGoWebAuthenticator.h>
|
|
|
|
#import <SOGo/WORequest+SOGo.h>
|
2011-02-03 17:12:22 +01:00
|
|
|
#import <SOGo/WOResourceManager+SOGo.h>
|
2010-01-15 00:19:19 +01:00
|
|
|
#import <SOGo/NSObject+DAV.h>
|
2007-06-29 23:56:21 +02:00
|
|
|
|
2007-12-03 15:13:10 +01:00
|
|
|
#import "NSException+Stacktrace.h"
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2009-01-09 18:26:25 +01:00
|
|
|
#import "SOGo.h"
|
2009-11-19 00:13:44 +01:00
|
|
|
|
2010-01-15 00:19:19 +01:00
|
|
|
#warning might be useful to have a SOGoObject-derived proxy class for \
|
|
|
|
handling requests and avoid duplicating methods
|
2006-06-15 21:34:10 +02:00
|
|
|
@implementation SOGo
|
|
|
|
|
2009-11-29 05:19:32 +01:00
|
|
|
static unsigned int vMemSizeLimit;
|
|
|
|
static BOOL doCrashOnSessionCreate;
|
|
|
|
static BOOL hasCheckedTables;
|
|
|
|
static BOOL debugRequests;
|
|
|
|
static BOOL useRelativeURLs;
|
2009-09-11 16:38:43 +02:00
|
|
|
static BOOL trustProxyAuthentication;
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
#ifdef GNUSTEP_BASE_LIBRARY
|
2009-11-29 05:19:32 +01:00
|
|
|
static BOOL debugLeaks;
|
2007-04-16 19:36:56 +02:00
|
|
|
#endif
|
|
|
|
|
2011-03-30 15:42:57 +02:00
|
|
|
+ (void) logWithFormat: (NSString *) format, ...
|
|
|
|
{
|
|
|
|
static NGLogger *sogoLogger = nil;
|
|
|
|
NGLoggerManager *lmgr;
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
if (!sogoLogger)
|
|
|
|
{
|
|
|
|
lmgr = [NGLoggerManager defaultLoggerManager];
|
|
|
|
sogoLogger = [lmgr loggerForClass: [self class]];
|
|
|
|
}
|
|
|
|
va_start (ap, format);
|
|
|
|
[sogoLogger logWithFormat: format arguments:ap];
|
|
|
|
va_end (ap);
|
|
|
|
}
|
|
|
|
|
2011-03-30 21:58:42 +02:00
|
|
|
+ (void) applicationWillStart
|
2007-04-16 19:36:56 +02:00
|
|
|
{
|
2009-11-29 05:19:32 +01:00
|
|
|
SOGoSystemDefaults *defaults;
|
2006-12-14 22:20:13 +01:00
|
|
|
SoClassSecurityInfo *sInfo;
|
|
|
|
NSArray *basicRoles;
|
2007-08-08 16:55:27 +02:00
|
|
|
|
2011-03-30 17:01:55 +02:00
|
|
|
[self logWithFormat: @"version %@ (build %@) -- starting",
|
|
|
|
SOGoVersion, SOGoBuildDate];
|
2011-03-30 15:42:57 +02:00
|
|
|
|
2009-11-29 05:19:32 +01:00
|
|
|
defaults = [SOGoSystemDefaults sharedSystemDefaults];
|
|
|
|
doCrashOnSessionCreate = [defaults crashOnSessionCreate];
|
|
|
|
debugRequests = [defaults debugRequests];
|
2009-11-19 00:13:44 +01:00
|
|
|
#ifdef GNUSTEP_BASE_LIBRARY
|
2009-11-29 05:19:32 +01:00
|
|
|
debugLeaks = [defaults debugLeaks];
|
2011-03-30 15:42:57 +02:00
|
|
|
if (debugLeaks)
|
|
|
|
[self logWithFormat: @"activating leak debugging"];
|
2009-11-19 00:13:44 +01:00
|
|
|
#endif
|
|
|
|
|
2010-02-19 14:47:00 +01:00
|
|
|
/* vMem size check - default is 384MB */
|
2009-11-29 05:19:32 +01:00
|
|
|
vMemSizeLimit = [defaults vmemLimit];
|
2011-03-30 15:42:57 +02:00
|
|
|
if (vMemSizeLimit > 0)
|
|
|
|
[self logWithFormat: @"vmem size check enabled: shutting down app when "
|
2017-01-09 22:03:32 +01:00
|
|
|
@"vmem > %d MB. Currently at %d MB", vMemSizeLimit, [[NSProcessInfo processInfo] virtualMemorySize]/1048576];
|
2011-03-30 15:42:57 +02:00
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
/* SoClass security declarations */
|
2006-12-14 22:20:13 +01:00
|
|
|
sInfo = [self soClassSecurityInfo];
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
/* to allow public access to all contained objects (subkeys) */
|
2006-12-14 22:20:13 +01:00
|
|
|
[sInfo setDefaultAccess: @"allow"];
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
/* require Authenticated role for View and WebDAV */
|
2010-01-15 00:19:19 +01:00
|
|
|
basicRoles = [NSArray arrayWithObject: SoRole_Authenticated];
|
2006-12-14 22:20:13 +01:00
|
|
|
[sInfo declareRoles: basicRoles asDefaultForPermission: SoPerm_View];
|
|
|
|
[sInfo declareRoles: basicRoles asDefaultForPermission: SoPerm_WebDAVAccess];
|
2009-09-11 16:38:43 +02:00
|
|
|
|
2009-11-29 05:19:32 +01:00
|
|
|
trustProxyAuthentication = [defaults trustProxyAuthentication];
|
|
|
|
useRelativeURLs = [defaults useRelativeURLs];
|
2011-03-30 15:42:57 +02:00
|
|
|
|
|
|
|
/* ensure core SoClass'es are setup */
|
|
|
|
[$(@"SOGoObject") soClass];
|
|
|
|
[$(@"SOGoContentObject") soClass];
|
|
|
|
[$(@"SOGoFolder") soClass];
|
|
|
|
|
|
|
|
/* load products */
|
2016-06-13 15:16:08 +02:00
|
|
|
[[SOGoProductLoader productLoader] loadAllProducts: YES];
|
2017-01-09 22:09:09 +01:00
|
|
|
if (vMemSizeLimit > 0)
|
|
|
|
[self logWithFormat: @"All products loaded - current memory usage at %d MB", [[NSProcessInfo processInfo] virtualMemorySize]/1048576];
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
- (id) init
|
|
|
|
{
|
|
|
|
if ((self = [super init]))
|
|
|
|
{
|
|
|
|
WOResourceManager *rm;
|
|
|
|
|
|
|
|
/* setup resource manager */
|
|
|
|
rm = [[WEResourceManager alloc] init];
|
|
|
|
[self setResourceManager:rm];
|
2009-10-10 20:30:30 +02:00
|
|
|
[rm release];
|
2007-04-16 19:36:56 +02:00
|
|
|
}
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2010-10-13 15:34:06 +02:00
|
|
|
#warning the following methods should be replaced with helpers in GCSSpecialQueries
|
2007-12-07 21:34:29 +01:00
|
|
|
- (NSString *) _sqlScriptForTable: (NSString *) tableName
|
|
|
|
withType: (NSString *) tableType
|
|
|
|
andFileSuffix: (NSString *) fileSuffix
|
|
|
|
{
|
|
|
|
NSString *tableFile, *descFile;
|
2007-06-29 23:56:21 +02:00
|
|
|
NGBundleManager *bm;
|
|
|
|
NSBundle *bundle;
|
|
|
|
unsigned int length;
|
|
|
|
|
|
|
|
bm = [NGBundleManager defaultBundleManager];
|
2007-08-13 23:27:20 +02:00
|
|
|
|
2007-12-07 21:34:29 +01:00
|
|
|
bundle = [bm bundleWithName: @"MainUI" type: @"SOGo"];
|
|
|
|
length = [tableType length] - 3;
|
|
|
|
tableFile = [tableType substringToIndex: length];
|
2018-09-21 19:06:15 +02:00
|
|
|
descFile = [bundle pathForResource: [NSString stringWithFormat: @"%@-%@",
|
|
|
|
tableFile, fileSuffix]
|
|
|
|
ofType: @"sql"];
|
2007-12-07 21:34:29 +01:00
|
|
|
if (!descFile)
|
|
|
|
descFile = [bundle pathForResource: tableFile ofType: @"sql"];
|
|
|
|
|
|
|
|
return [[NSString stringWithContentsOfFile: descFile]
|
|
|
|
stringByReplacingString: @"@{tableName}"
|
|
|
|
withString: tableName];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _checkTableWithCM: (GCSChannelManager *) cm
|
|
|
|
tableURL: (NSString *) url
|
|
|
|
andType: (NSString *) tableType
|
|
|
|
{
|
|
|
|
NSString *tableName, *fileSuffix, *tableScript;
|
|
|
|
EOAdaptorChannel *tc;
|
|
|
|
NSURL *channelURL;
|
2018-08-24 14:48:41 +02:00
|
|
|
NSException *ex;
|
2007-12-07 21:34:29 +01:00
|
|
|
|
2007-08-13 23:27:20 +02:00
|
|
|
channelURL = [NSURL URLWithString: url];
|
|
|
|
fileSuffix = [channelURL scheme];
|
|
|
|
tc = [cm acquireOpenChannelForURL: channelURL];
|
2007-06-29 23:56:21 +02:00
|
|
|
|
2012-06-28 16:46:37 +02:00
|
|
|
/* FIXME: make use of [EOChannelAdaptor describeTableNames] instead */
|
2007-06-29 23:56:21 +02:00
|
|
|
tableName = [url lastPathComponent];
|
|
|
|
if ([tc evaluateExpressionX:
|
2007-12-07 21:34:29 +01:00
|
|
|
[NSString stringWithFormat: @"SELECT count(*) FROM %@",
|
|
|
|
tableName]])
|
2007-06-29 23:56:21 +02:00
|
|
|
{
|
2018-08-27 14:41:24 +02:00
|
|
|
// We re-acquire the channel in case it was abruptly closed between statements
|
|
|
|
if (![tc isOpen])
|
|
|
|
tc = [cm acquireOpenChannelForURL: channelURL];
|
2007-12-07 21:34:29 +01:00
|
|
|
tableScript = [self _sqlScriptForTable: tableName
|
|
|
|
withType: tableType
|
|
|
|
andFileSuffix: fileSuffix];
|
2018-08-24 14:48:41 +02:00
|
|
|
if (!(ex = [tc evaluateExpressionX: tableScript]))
|
2007-06-29 23:56:21 +02:00
|
|
|
[self logWithFormat: @"table '%@' successfully created!", tableName];
|
2018-08-24 14:48:41 +02:00
|
|
|
else
|
|
|
|
[self logWithFormat: @"table '%@' creation failed! Reason: %@", tableName, ex];
|
2007-06-29 23:56:21 +02:00
|
|
|
}
|
2007-07-03 16:17:31 +02:00
|
|
|
else
|
|
|
|
[tc cancelFetch];
|
2007-06-29 23:56:21 +02:00
|
|
|
|
|
|
|
[cm releaseChannel: tc];
|
|
|
|
}
|
|
|
|
|
2016-03-10 22:34:06 +01:00
|
|
|
- (void) _checkQuickTableWithTypeName: typeName
|
|
|
|
withCm: (GCSChannelManager *) cm
|
|
|
|
tableURL: (NSString *) url
|
|
|
|
{
|
2018-09-21 19:06:15 +02:00
|
|
|
NSString *tableName, *sql, *driver;
|
2016-03-10 22:34:06 +01:00
|
|
|
EOAdaptorChannel *channel;
|
2018-08-24 14:48:41 +02:00
|
|
|
GCSFolderType *type;
|
|
|
|
NSException *ex;
|
2016-03-10 22:34:06 +01:00
|
|
|
|
|
|
|
channel = [cm acquireOpenChannelForURL: [NSURL URLWithString: url]];
|
|
|
|
|
|
|
|
tableName = [NSString stringWithFormat: @"sogo_quick_%@", typeName];
|
2018-09-21 19:06:15 +02:00
|
|
|
driver = [url substringToIndex: [url rangeOfString: @":"].location];
|
2016-03-10 22:34:06 +01:00
|
|
|
sql = [NSString stringWithFormat: @"SELECT count(*) FROM %@",
|
|
|
|
tableName];
|
|
|
|
if ([channel evaluateExpressionX: sql])
|
|
|
|
{
|
2018-09-21 19:06:15 +02:00
|
|
|
type = [GCSFolderType folderTypeWithName: typeName driver: driver];
|
2016-03-10 22:34:06 +01:00
|
|
|
if (type)
|
|
|
|
{
|
|
|
|
sql = [type sqlQuickCreateWithTableName: tableName];
|
2018-08-24 14:48:41 +02:00
|
|
|
if (!(ex = [channel evaluateExpressionX: sql]))
|
|
|
|
[self logWithFormat: @"sogo quick table '%@' successfully created!",
|
2016-03-10 22:34:06 +01:00
|
|
|
tableName];
|
2018-08-24 14:48:41 +02:00
|
|
|
else
|
|
|
|
[self logWithFormat: @"sogo quick table '%@' creation failed! Reason: %@", tableName, ex];
|
2016-03-10 22:34:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[channel cancelFetch];
|
|
|
|
|
|
|
|
[cm releaseChannel:channel];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// If OCSStoreURL is defined, we also check for OCSAclURL, OCSCacheFolderURL
|
|
|
|
// and we create the combined quick tables.
|
|
|
|
//
|
2007-06-29 23:56:21 +02:00
|
|
|
- (BOOL) _checkMandatoryTables
|
|
|
|
{
|
|
|
|
GCSChannelManager *cm;
|
2010-08-19 19:40:28 +02:00
|
|
|
GCSFolderManager *fm;
|
2016-03-10 22:34:06 +01:00
|
|
|
NSArray *urlStrings;
|
|
|
|
NSArray *quickTypeStrings;
|
|
|
|
NSString *tmp, *value;
|
2009-11-29 05:19:32 +01:00
|
|
|
SOGoSystemDefaults *defaults;
|
2016-03-10 22:34:06 +01:00
|
|
|
NSEnumerator *e;
|
|
|
|
BOOL ok, combined;
|
2007-06-29 23:56:21 +02:00
|
|
|
|
2009-11-29 05:19:32 +01:00
|
|
|
defaults = [SOGoSystemDefaults sharedSystemDefaults];
|
2007-06-29 23:56:21 +02:00
|
|
|
ok = YES;
|
2016-03-10 22:34:06 +01:00
|
|
|
|
|
|
|
if ([GCSFolderManager singleStoreMode])
|
|
|
|
{
|
|
|
|
urlStrings = [NSArray arrayWithObjects: @"SOGoProfileURL", @"OCSFolderInfoURL", @"OCSStoreURL", @"OCSAclURL", @"OCSCacheFolderURL", nil];
|
|
|
|
quickTypeStrings = [NSArray arrayWithObjects: @"contact", @"appointment", nil];
|
|
|
|
combined = YES;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
urlStrings = [NSArray arrayWithObjects: @"SOGoProfileURL", @"OCSFolderInfoURL", nil];
|
|
|
|
combined = NO;
|
|
|
|
}
|
|
|
|
|
2007-06-29 23:56:21 +02:00
|
|
|
cm = [GCSChannelManager defaultChannelManager];
|
|
|
|
|
2016-03-10 22:34:06 +01:00
|
|
|
e = [urlStrings objectEnumerator];
|
|
|
|
while (ok && (tmp = [e nextObject]))
|
2007-06-29 23:56:21 +02:00
|
|
|
{
|
2016-03-10 22:34:06 +01:00
|
|
|
value = [defaults stringForKey: tmp];
|
2007-06-29 23:56:21 +02:00
|
|
|
if (value)
|
2016-03-10 22:34:06 +01:00
|
|
|
[self _checkTableWithCM: cm tableURL: value andType: tmp];
|
2007-06-29 23:56:21 +02:00
|
|
|
else
|
|
|
|
{
|
2016-03-10 22:34:06 +01:00
|
|
|
[self errorWithFormat: @"No value specified for '%@'", tmp];
|
2007-06-29 23:56:21 +02:00
|
|
|
ok = NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-10 22:34:06 +01:00
|
|
|
if (combined)
|
|
|
|
{
|
|
|
|
e = [quickTypeStrings objectEnumerator];
|
|
|
|
while ((tmp = [e nextObject]))
|
|
|
|
{
|
|
|
|
[self _checkQuickTableWithTypeName: tmp
|
|
|
|
withCm: cm
|
|
|
|
tableURL: [defaults stringForKey: @"OCSFolderInfoURL"]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-28 18:42:50 +01:00
|
|
|
if (ok)
|
2010-08-19 19:40:28 +02:00
|
|
|
{
|
|
|
|
fm = [GCSFolderManager defaultFolderManager];
|
2010-12-28 18:42:50 +01:00
|
|
|
|
|
|
|
// Create the sessions table
|
|
|
|
[[fm sessionsFolder] createFolderIfNotExists];
|
|
|
|
|
|
|
|
// Create the email alarms table, if required
|
|
|
|
if ([defaults enableEMailAlarms])
|
|
|
|
{
|
|
|
|
[[fm alarmsFolder] createFolderIfNotExists];
|
|
|
|
}
|
2010-08-19 19:40:28 +02:00
|
|
|
}
|
|
|
|
|
2007-06-29 23:56:21 +02:00
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) run
|
|
|
|
{
|
|
|
|
if (!hasCheckedTables)
|
|
|
|
{
|
|
|
|
hasCheckedTables = YES;
|
|
|
|
[self _checkMandatoryTables];
|
|
|
|
}
|
|
|
|
[super run];
|
|
|
|
}
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
/* authenticator */
|
|
|
|
|
2007-09-05 00:02:29 +02:00
|
|
|
- (id) authenticatorInContext: (WOContext *) context
|
2007-04-16 19:36:56 +02:00
|
|
|
{
|
2007-09-04 17:41:14 +02:00
|
|
|
id authenticator;
|
|
|
|
|
2013-06-18 17:50:28 +02:00
|
|
|
if (trustProxyAuthentication && [[context request] headerForKey: @"x-webobjects-remote-user"])
|
2009-09-11 16:38:43 +02:00
|
|
|
authenticator = [SOGoProxyAuthenticator sharedSOGoProxyAuthenticator];
|
2007-11-08 20:56:18 +01:00
|
|
|
else
|
2009-09-11 16:38:43 +02:00
|
|
|
{
|
|
|
|
if ([[context request] handledByDefaultHandler])
|
|
|
|
authenticator = [SOGoWebAuthenticator sharedSOGoWebAuthenticator];
|
|
|
|
else
|
|
|
|
authenticator = [SOGoDAVAuthenticator sharedSOGoDAVAuthenticator];
|
|
|
|
}
|
2007-09-04 17:41:14 +02:00
|
|
|
|
|
|
|
return authenticator;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* name lookup */
|
|
|
|
|
2007-07-04 22:07:52 +02:00
|
|
|
- (id) lookupUser: (NSString *) _key
|
|
|
|
inContext: (id)_ctx
|
|
|
|
{
|
|
|
|
SOGoUser *user;
|
|
|
|
id userFolder;
|
|
|
|
|
|
|
|
user = [SOGoUser userWithLogin: _key roles: nil];
|
|
|
|
if (user)
|
2009-11-29 05:19:32 +01:00
|
|
|
userFolder = [$(@"SOGoUserFolder") objectWithName: _key
|
|
|
|
inContainer: self];
|
2007-07-04 22:07:52 +02:00
|
|
|
else
|
|
|
|
userFolder = nil;
|
|
|
|
|
|
|
|
return userFolder;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
- (void) _setupLocaleInContext: (WOContext *) _ctx
|
|
|
|
{
|
2006-06-15 21:34:10 +02:00
|
|
|
NSArray *langs;
|
|
|
|
NSDictionary *locale;
|
|
|
|
|
|
|
|
if ([[_ctx valueForKey:@"locale"] isNotNull])
|
|
|
|
return;
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
langs = [[_ctx request] browserLanguages];
|
2006-06-15 21:34:10 +02:00
|
|
|
locale = [self currentLocaleConsideringLanguages:langs];
|
|
|
|
[_ctx takeValue:locale forKey:@"locale"];
|
|
|
|
}
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
- (id) lookupName: (NSString *) _key
|
|
|
|
inContext: (id) _ctx
|
|
|
|
acquire: (BOOL) _flag
|
|
|
|
{
|
2006-06-15 21:34:10 +02:00
|
|
|
id obj;
|
2010-01-15 00:19:19 +01:00
|
|
|
WORequest *request;
|
|
|
|
BOOL isDAVRequest;
|
2010-06-02 18:35:59 +02:00
|
|
|
SOGoSystemDefaults *sd;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
|
|
|
/* put locale info into the context in case it's not there */
|
|
|
|
[self _setupLocaleInContext:_ctx];
|
2009-12-09 00:18:12 +01:00
|
|
|
|
2010-06-02 18:35:59 +02:00
|
|
|
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
2010-01-15 00:19:19 +01:00
|
|
|
request = [_ctx request];
|
2010-06-02 18:35:59 +02:00
|
|
|
isDAVRequest = [[request requestHandlerKey] isEqualToString:@"dav"];
|
|
|
|
if (isDAVRequest || [sd isWebAccessEnabled])
|
2008-10-03 17:59:05 +02:00
|
|
|
{
|
2010-01-15 00:19:19 +01:00
|
|
|
if (isDAVRequest)
|
|
|
|
{
|
2010-06-02 18:35:59 +02:00
|
|
|
if ([_key isEqualToString: @"public"] && [sd enablePublicAccess])
|
|
|
|
obj = [SOGoPublicBaseFolder objectWithName: @"public" inContainer: self];
|
|
|
|
else if ([[request method] isEqualToString: @"REPORT"])
|
2010-01-15 00:19:19 +01:00
|
|
|
obj = [self davReportInvocationForKey: _key];
|
|
|
|
else
|
|
|
|
obj = nil;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* first check attributes directly bound to the application */
|
|
|
|
obj = [super lookupName:_key inContext:_ctx acquire:_flag];
|
|
|
|
}
|
2010-06-02 18:35:59 +02:00
|
|
|
|
2009-12-09 00:18:12 +01:00
|
|
|
if (!obj)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
The problem is, that at this point we still get request for
|
|
|
|
resources, eg 'favicon.ico'.
|
|
|
|
|
|
|
|
Addition: we also get queries for various other methods, like
|
|
|
|
"GET" if no method was provided in the query path.
|
|
|
|
*/
|
2010-01-15 00:19:19 +01:00
|
|
|
if ([_key length] > 0 && ![_key isEqualToString:@"favicon.ico"])
|
2016-12-15 20:22:07 +01:00
|
|
|
{
|
|
|
|
obj = [self lookupUser: _key inContext: _ctx];
|
2016-12-16 15:07:55 +01:00
|
|
|
if (!obj && ![_key isEqualToString: @"public"])
|
2016-12-15 20:22:07 +01:00
|
|
|
obj = [self lookupUser: @"anonymous" inContext: _ctx];
|
|
|
|
}
|
|
|
|
}
|
2008-10-03 17:59:05 +02:00
|
|
|
}
|
2009-12-09 00:18:12 +01:00
|
|
|
else
|
|
|
|
obj = nil;
|
2007-07-04 22:07:52 +02:00
|
|
|
|
2008-10-03 17:59:05 +02:00
|
|
|
return obj;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2010-06-02 18:35:59 +02:00
|
|
|
- (BOOL) isInPublicZone
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
/* WebDAV */
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
- (NSString *) davDisplayName
|
|
|
|
{
|
2006-06-15 21:34:10 +02:00
|
|
|
/* this is used in the UI, eg in the navigation */
|
|
|
|
return @"SOGo";
|
|
|
|
}
|
|
|
|
|
|
|
|
/* exception handling */
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
- (WOResponse *) handleException: (NSException *) _exc
|
|
|
|
inContext: (WOContext *) _ctx
|
2006-06-15 21:34:10 +02:00
|
|
|
{
|
2017-03-09 19:57:27 +01:00
|
|
|
WOResponse *resp;
|
|
|
|
|
|
|
|
NSLog(@"EXCEPTION: %s\n", [[_exc description] cString]);
|
|
|
|
resp = [WOResponse responseWithRequest: [_ctx request]];
|
|
|
|
[resp setStatus: 501];
|
|
|
|
return resp;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* runtime maintenance */
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
- (void) checkIfDaemonHasToBeShutdown
|
|
|
|
{
|
|
|
|
unsigned int vmem;
|
|
|
|
|
|
|
|
if (vMemSizeLimit > 0)
|
|
|
|
{
|
|
|
|
vmem = [[NSProcessInfo processInfo] virtualMemorySize]/1048576;
|
|
|
|
|
|
|
|
if (vmem > vMemSizeLimit)
|
|
|
|
{
|
|
|
|
[self logWithFormat:
|
|
|
|
@"terminating app, vMem size limit (%d MB) has been reached"
|
|
|
|
@" (currently %d MB)",
|
|
|
|
vMemSizeLimit, vmem];
|
|
|
|
[self terminate];
|
|
|
|
}
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
- (WOResponse *) dispatchRequest: (WORequest *) _request
|
|
|
|
{
|
2006-06-15 21:34:10 +02:00
|
|
|
static NSArray *runLoopModes = nil;
|
2009-10-10 20:30:30 +02:00
|
|
|
static BOOL debugOn = NO;
|
2016-03-21 13:19:40 +01:00
|
|
|
|
|
|
|
SOGoSystemDefaults *sd;
|
2006-06-15 21:34:10 +02:00
|
|
|
WOResponse *resp;
|
2010-05-18 19:57:58 +02:00
|
|
|
NSDate *startDate;
|
2016-03-18 16:03:45 +01:00
|
|
|
NSString *path;
|
|
|
|
|
2010-05-18 19:57:58 +02:00
|
|
|
NSTimeInterval timeDelta;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-06-13 22:01:10 +02:00
|
|
|
if (debugRequests)
|
|
|
|
{
|
|
|
|
[self logWithFormat: @"starting method '%@' on uri '%@'",
|
|
|
|
[_request method], [_request uri]];
|
|
|
|
startDate = [NSDate date];
|
|
|
|
}
|
2008-06-19 20:26:33 +02:00
|
|
|
|
2016-03-21 13:19:40 +01:00
|
|
|
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
2008-01-16 19:57:58 +01:00
|
|
|
cache = [SOGoCache sharedCache];
|
2009-11-19 00:13:44 +01:00
|
|
|
#ifdef GNUSTEP_BASE_LIBRARY
|
2009-02-06 21:12:42 +01:00
|
|
|
if (debugLeaks)
|
|
|
|
{
|
2009-10-10 20:30:30 +02:00
|
|
|
if (debugOn)
|
2015-01-22 19:31:31 +01:00
|
|
|
[self logWithFormat: @"allocated classes:\n%s", GSDebugAllocationList (YES)];
|
2009-10-10 20:30:30 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
debugOn = YES;
|
|
|
|
GSDebugAllocationActive (YES);
|
|
|
|
}
|
2009-02-06 21:12:42 +01:00
|
|
|
}
|
2009-11-19 00:13:44 +01:00
|
|
|
#endif
|
2009-02-06 21:12:42 +01:00
|
|
|
|
2016-03-18 16:03:45 +01:00
|
|
|
// We check for rate-limiting settings - ignore anything actually
|
|
|
|
// sent to /SOGo/ (so unauthenticated requests).
|
|
|
|
path = [_request requestHandlerPath];
|
2016-03-21 13:19:40 +01:00
|
|
|
if ([path length] && [sd maximumRequestCount] > 0)
|
2016-03-18 16:03:45 +01:00
|
|
|
{
|
|
|
|
NSDictionary *requestCount;
|
|
|
|
NSString *username;
|
|
|
|
NSRange r;
|
|
|
|
|
|
|
|
r = [path rangeOfString: @"/"];
|
2016-03-18 17:50:09 +01:00
|
|
|
|
|
|
|
// We handle /sogo1/Calendar/.../ and "sogo1" as paths
|
|
|
|
if (r.length)
|
|
|
|
username = [path substringWithRange: NSMakeRange(0, r.location)];
|
|
|
|
else
|
|
|
|
username = path;
|
|
|
|
|
2016-03-18 16:03:45 +01:00
|
|
|
requestCount = [cache requestCountForLogin: username];
|
|
|
|
|
|
|
|
if (requestCount)
|
|
|
|
{
|
|
|
|
unsigned int current_time, start_time, delta, block_time, request_count;
|
|
|
|
|
|
|
|
current_time = [[NSCalendarDate date] timeIntervalSince1970];
|
|
|
|
start_time = [[requestCount objectForKey: @"InitialDate"] unsignedIntValue];
|
|
|
|
delta = current_time - start_time;
|
|
|
|
|
|
|
|
block_time = [sd requestBlockInterval];
|
|
|
|
request_count = [[requestCount objectForKey: @"RequestCount"] intValue];
|
|
|
|
|
|
|
|
if ( request_count >= [sd maximumRequestCount] &&
|
|
|
|
delta < [sd maximumRequestInterval] &&
|
|
|
|
delta <= block_time )
|
|
|
|
{
|
|
|
|
resp = [WOResponse responseWithRequest: _request];
|
|
|
|
[resp setStatus: 429];
|
|
|
|
return resp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (delta > block_time)
|
|
|
|
{
|
|
|
|
[cache setRequestCount: 1
|
|
|
|
forLogin: username
|
|
|
|
interval: current_time];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[cache setRequestCount: (request_count+1)
|
|
|
|
forLogin: username
|
|
|
|
interval: start_time];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[cache setRequestCount: 1
|
|
|
|
forLogin: username
|
|
|
|
interval: 0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
resp = [super dispatchRequest: _request];
|
2009-11-16 16:02:14 +01:00
|
|
|
[cache killCache];
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-06-13 22:01:10 +02:00
|
|
|
if (debugRequests)
|
|
|
|
{
|
2010-05-18 19:57:58 +02:00
|
|
|
timeDelta = [[NSDate date] timeIntervalSinceDate: startDate];
|
2010-05-18 20:00:11 +02:00
|
|
|
[self logWithFormat: @"request took %f seconds to execute",
|
|
|
|
timeDelta];
|
2010-05-18 19:57:58 +02:00
|
|
|
[resp setHeader: [NSString stringWithFormat: @"%f", timeDelta]
|
2010-06-02 18:35:59 +02:00
|
|
|
forKey: @"SOGo-Request-Duration"];
|
2008-06-13 22:01:10 +02:00
|
|
|
}
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
if (![self isTerminating])
|
|
|
|
{
|
|
|
|
if (!runLoopModes)
|
|
|
|
runLoopModes = [[NSArray alloc] initWithObjects: NSDefaultRunLoopMode, nil];
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
// TODO: a bit complicated? (-perform:afterDelay: doesn't work?)
|
|
|
|
[[NSRunLoop currentRunLoop] performSelector:
|
|
|
|
@selector (checkIfDaemonHasToBeShutdown)
|
|
|
|
target: self argument: nil
|
|
|
|
order:1 modes:runLoopModes];
|
|
|
|
}
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
return resp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* session management */
|
|
|
|
|
2009-09-13 17:17:05 +02:00
|
|
|
- (NSString *) sessionIDFromRequest: (WORequest *) _rq
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
- (id) createSessionForRequest: (WORequest *) _request
|
|
|
|
{
|
|
|
|
[self warnWithFormat: @"session creation requested!"];
|
2006-06-15 21:34:10 +02:00
|
|
|
if (doCrashOnSessionCreate)
|
|
|
|
abort();
|
|
|
|
return [super createSessionForRequest:_request];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* localization */
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
- (NSDictionary *) currentLocaleConsideringLanguages: (NSArray *) langs
|
|
|
|
{
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
NSString *lname;
|
|
|
|
NSDictionary *locale;
|
|
|
|
|
|
|
|
enumerator = [langs objectEnumerator];
|
|
|
|
lname = nil;
|
|
|
|
locale = nil;
|
|
|
|
lname = [enumerator nextObject];
|
|
|
|
while (lname && !locale)
|
|
|
|
{
|
2011-02-03 17:12:22 +01:00
|
|
|
locale = [[self resourceManager] localeForLanguageNamed: lname];
|
2007-04-16 19:36:56 +02:00
|
|
|
lname = [enumerator nextObject];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!locale)
|
2012-01-31 21:17:19 +01:00
|
|
|
// no appropriate language, fallback to default
|
2011-02-03 17:12:22 +01:00
|
|
|
locale = [[self resourceManager] localeForLanguageNamed: @"English"];
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
return locale;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2008-05-03 01:14:26 +02:00
|
|
|
- (NSURL *) _urlPreferringParticle: (NSString *) expected
|
|
|
|
overThisOne: (NSString *) possible
|
|
|
|
{
|
|
|
|
NSURL *serverURL, *url;
|
|
|
|
NSMutableArray *path;
|
|
|
|
NSString *baseURL, *urlMethod;
|
|
|
|
WOContext *context;
|
|
|
|
|
|
|
|
context = [self context];
|
|
|
|
serverURL = [context serverURL];
|
|
|
|
baseURL = [[self baseURLInContext: context] stringByUnescapingURL];
|
|
|
|
path = [NSMutableArray arrayWithArray: [baseURL componentsSeparatedByString:
|
|
|
|
@"/"]];
|
|
|
|
if ([baseURL hasPrefix: @"http"])
|
|
|
|
{
|
|
|
|
[path removeObjectAtIndex: 1];
|
|
|
|
[path removeObjectAtIndex: 0];
|
|
|
|
[path replaceObjectAtIndex: 0 withObject: @""];
|
|
|
|
}
|
|
|
|
urlMethod = [path objectAtIndex: 2];
|
|
|
|
if (![urlMethod isEqualToString: expected])
|
|
|
|
{
|
|
|
|
if ([urlMethod isEqualToString: possible])
|
|
|
|
[path replaceObjectAtIndex: 2 withObject: expected];
|
|
|
|
else
|
|
|
|
[path insertObject: expected atIndex: 2];
|
|
|
|
}
|
|
|
|
|
|
|
|
url = [[NSURL alloc] initWithScheme: [serverURL scheme]
|
|
|
|
host: [serverURL host]
|
|
|
|
path: [path componentsJoinedByString: @"/"]];
|
|
|
|
[url autorelease];
|
|
|
|
|
|
|
|
return url;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSURL *) davURL
|
|
|
|
{
|
|
|
|
return [self _urlPreferringParticle: @"dav" overThisOne: @"so"];
|
|
|
|
}
|
|
|
|
|
2009-10-21 23:17:11 +02:00
|
|
|
- (NSString *) davURLAsString
|
|
|
|
{
|
|
|
|
NSURL *davURL;
|
2009-12-08 22:15:56 +01:00
|
|
|
NSString *davURLAsString;
|
2010-01-15 00:19:19 +01:00
|
|
|
WORequest *request;
|
2009-10-21 23:17:11 +02:00
|
|
|
|
2009-12-08 22:15:56 +01:00
|
|
|
/* we know that GNUstep returns a "/" suffix for the absoluteString but not
|
|
|
|
for the path method. Therefore we add one. */
|
|
|
|
if (useRelativeURLs)
|
2010-01-15 00:19:19 +01:00
|
|
|
{
|
|
|
|
request = [[self context] request];
|
|
|
|
davURLAsString = [NSString stringWithFormat: @"/%@/dav/",
|
|
|
|
[request applicationName]];
|
|
|
|
}
|
2009-12-08 22:15:56 +01:00
|
|
|
else
|
2010-01-15 00:19:19 +01:00
|
|
|
{
|
|
|
|
davURL = [self davURL];
|
|
|
|
davURLAsString = [davURL absoluteString];
|
|
|
|
}
|
2009-12-08 22:15:56 +01:00
|
|
|
|
|
|
|
return davURLAsString;
|
2009-10-21 23:17:11 +02:00
|
|
|
}
|
|
|
|
|
2008-05-03 01:14:26 +02:00
|
|
|
- (NSURL *) soURL
|
|
|
|
{
|
|
|
|
return [self _urlPreferringParticle: @"so" overThisOne: @"dav"];
|
|
|
|
}
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
/* name (used by the WEResourceManager) */
|
|
|
|
|
2007-04-16 19:36:56 +02:00
|
|
|
- (NSString *) name
|
|
|
|
{
|
2009-03-18 23:13:04 +01:00
|
|
|
return @"SOGo";
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@end /* SOGo */
|