2006-06-15 21:34:10 +02:00
|
|
|
/*
|
|
|
|
Copyright (C) 2004-2005 SKYRIX Software AG
|
|
|
|
|
|
|
|
This file is part of OpenGroupware.org.
|
|
|
|
|
|
|
|
OGo 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.
|
|
|
|
|
|
|
|
OGo 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 OGo; see the file COPYING. If not, write to the
|
|
|
|
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <NGObjWeb/SoApplication.h>
|
|
|
|
|
2007-03-07 23:31:34 +01:00
|
|
|
// @interface classtree : NSObject
|
|
|
|
// {
|
|
|
|
// Class topClass;
|
|
|
|
// int indentLevel;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// - (id) initWithTopClass: (Class) newTopClass;
|
|
|
|
// - (void) dumpSiblings: (Class) node;
|
|
|
|
|
|
|
|
// @end
|
|
|
|
|
|
|
|
// @implementation classtree
|
|
|
|
|
|
|
|
// + (id) newWithTopClass: (Class) newTopClass
|
|
|
|
// {
|
|
|
|
// id newTree;
|
|
|
|
|
|
|
|
// newTree = [[self alloc] initWithTopClass: newTopClass];
|
|
|
|
// [newTree autorelease];
|
|
|
|
|
|
|
|
// return newTree;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// - (id) initWithTopClass: (Class) newTopClass
|
|
|
|
// {
|
|
|
|
// if ((self = [self init]))
|
|
|
|
// topClass = newTopClass;
|
|
|
|
|
|
|
|
// return self;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// #define indentGap 2
|
|
|
|
|
|
|
|
// - (NSString *) indentSpaces
|
|
|
|
// {
|
|
|
|
// char *spaceString;
|
|
|
|
|
|
|
|
// spaceString = malloc(sizeof (char *) * indentGap * indentLevel + 1);
|
|
|
|
// *(spaceString + indentGap * indentLevel) = 0;
|
|
|
|
// memset (spaceString, ' ', indentGap * indentLevel);
|
|
|
|
|
|
|
|
// return [[NSString alloc] initWithCStringNoCopy: spaceString
|
|
|
|
// length: indentGap * indentLevel
|
|
|
|
// freeWhenDone: YES];
|
|
|
|
// }
|
|
|
|
|
|
|
|
// - (void) dumpNode: (Class) node
|
|
|
|
// {
|
|
|
|
// Class currentSubclass;
|
|
|
|
// unsigned int count;
|
|
|
|
|
|
|
|
// count = 0;
|
|
|
|
// currentSubclass = node->subclass_list;
|
|
|
|
// if (currentSubclass)
|
|
|
|
// {
|
|
|
|
// NSLog(@"%@%@:",
|
|
|
|
// [[self indentSpaces] autorelease], NSStringFromClass(node));
|
|
|
|
// indentLevel++;
|
|
|
|
// [self dumpSiblings: currentSubclass];
|
|
|
|
// indentLevel--;
|
|
|
|
// }
|
|
|
|
// else
|
|
|
|
// NSLog(@"%@%@", [self indentSpaces], NSStringFromClass(node));
|
|
|
|
// }
|
|
|
|
|
|
|
|
// - (void) dumpSiblings: (Class) node
|
|
|
|
// {
|
|
|
|
// Class currentNode;
|
|
|
|
|
|
|
|
// currentNode = node;
|
|
|
|
// while (currentNode && currentNode->instance_size)
|
|
|
|
// {
|
|
|
|
// [self dumpNode: currentNode];
|
|
|
|
// currentNode = currentNode->sibling_class;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// - (void) dumpTree
|
|
|
|
// {
|
|
|
|
// indentLevel = 0;
|
|
|
|
|
|
|
|
// [self dumpSiblings: topClass];
|
|
|
|
// }
|
|
|
|
|
|
|
|
// @end
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
@interface SOGo : SoApplication
|
|
|
|
{
|
|
|
|
NSMutableDictionary *localeLUT;
|
|
|
|
}
|
|
|
|
|
2006-12-14 22:20:13 +01:00
|
|
|
- (NSDictionary *) currentLocaleConsideringLanguages:(NSArray *)_langs;
|
|
|
|
- (NSDictionary *) localeForLanguageNamed:(NSString *)_name;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
#include "SOGoProductLoader.h"
|
|
|
|
#include <WEExtensions/WEResourceManager.h>
|
2006-12-14 22:20:13 +01:00
|
|
|
#include <SOGo/SOGoAuthenticator.h>
|
2006-06-15 21:34:10 +02:00
|
|
|
#include <SOGo/SOGoUserFolder.h>
|
2006-12-14 22:20:13 +01:00
|
|
|
#include <SOGo/SOGoPermissions.h>
|
2006-06-15 21:34:10 +02:00
|
|
|
#include "common.h"
|
|
|
|
|
|
|
|
@implementation SOGo
|
|
|
|
|
|
|
|
static unsigned int vMemSizeLimit = 0;
|
|
|
|
static BOOL doCrashOnSessionCreate = NO;
|
|
|
|
|
|
|
|
+ (void)initialize {
|
|
|
|
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
2006-12-14 22:20:13 +01:00
|
|
|
SoClassSecurityInfo *sInfo;
|
|
|
|
NSArray *basicRoles;
|
2006-06-15 21:34:10 +02:00
|
|
|
id tmp;
|
|
|
|
|
|
|
|
doCrashOnSessionCreate = [ud boolForKey:@"SOGoCrashOnSessionCreate"];
|
|
|
|
|
|
|
|
/* vMem size check - default is 200MB */
|
|
|
|
|
|
|
|
tmp = [ud objectForKey:@"SxVMemLimit"];
|
|
|
|
vMemSizeLimit = (tmp != nil)
|
|
|
|
? [tmp intValue]
|
|
|
|
: 200;
|
|
|
|
if (vMemSizeLimit > 0) {
|
|
|
|
NSLog(@"Note: vmem size check enabled: shutting down app when "
|
|
|
|
@"vmem > %d MB", vMemSizeLimit);
|
|
|
|
}
|
|
|
|
#if LIB_FOUNDATION_LIBRARY
|
|
|
|
if ([ud boolForKey:@"SOGoEnableDoubleReleaseCheck"])
|
|
|
|
[NSAutoreleasePool enableDoubleReleaseCheck:YES];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* SoClass security declarations */
|
2006-12-14 22:20:13 +01:00
|
|
|
sInfo = [self soClassSecurityInfo];
|
2006-06-15 21:34:10 +02:00
|
|
|
/* require View permission to access the root (bound to authenticated ...) */
|
2006-12-14 22:20:13 +01:00
|
|
|
[sInfo declareObjectProtected: SoPerm_View];
|
|
|
|
|
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"];
|
|
|
|
|
|
|
|
basicRoles = [NSArray arrayWithObjects: SoRole_Authenticated,
|
|
|
|
SOGoRole_FreeBusy, nil];
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
/* require Authenticated role for View and WebDAV */
|
2006-12-14 22:20:13 +01:00
|
|
|
[sInfo declareRoles: basicRoles asDefaultForPermission: SoPerm_View];
|
|
|
|
[sInfo declareRoles: basicRoles asDefaultForPermission: SoPerm_WebDAVAccess];
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id)init {
|
|
|
|
if ((self = [super init])) {
|
|
|
|
WOResourceManager *rm;
|
|
|
|
|
|
|
|
/* ensure core SoClass'es are setup */
|
2006-12-14 22:22:57 +01:00
|
|
|
[$(@"SOGoObject") soClass];
|
|
|
|
[$(@"SOGoContentObject") soClass];
|
|
|
|
[$(@"SOGoFolder") soClass];
|
2006-06-15 21:34:10 +02:00
|
|
|
|
|
|
|
/* setup locale cache */
|
|
|
|
self->localeLUT = [[NSMutableDictionary alloc] initWithCapacity:2];
|
|
|
|
|
|
|
|
/* load products */
|
|
|
|
[[SOGoProductLoader productLoader] loadProducts];
|
|
|
|
|
|
|
|
/* setup resource manager */
|
|
|
|
rm = [[WEResourceManager alloc] init];
|
|
|
|
[self setResourceManager:rm];
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)dealloc {
|
|
|
|
[self->localeLUT release];
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* authenticator */
|
|
|
|
|
|
|
|
- (id)authenticatorInContext:(id)_ctx {
|
2006-12-14 22:20:13 +01:00
|
|
|
return [$(@"SOGoAuthenticator") sharedSOGoAuthenticator];
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* name lookup */
|
|
|
|
|
|
|
|
- (BOOL)isUserName:(NSString *)_key inContext:(id)_ctx {
|
|
|
|
if ([_key length] < 1)
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
if (isdigit([_key characterAtIndex:0]))
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)lookupUser:(NSString *)_key inContext:(id)_ctx {
|
2006-12-14 22:22:57 +01:00
|
|
|
return [[[$(@"SOGoUserFolder") alloc]
|
2006-06-15 21:34:10 +02:00
|
|
|
initWithName:_key inContainer:self] autorelease];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)_setupLocaleInContext:(WOContext *)_ctx {
|
|
|
|
NSArray *langs;
|
|
|
|
NSDictionary *locale;
|
|
|
|
|
|
|
|
if ([[_ctx valueForKey:@"locale"] isNotNull])
|
|
|
|
return;
|
|
|
|
|
|
|
|
langs = [[(WOContext *)_ctx request] browserLanguages];
|
|
|
|
locale = [self currentLocaleConsideringLanguages:langs];
|
|
|
|
[_ctx takeValue:locale forKey:@"locale"];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag {
|
|
|
|
id obj;
|
|
|
|
|
|
|
|
/* put locale info into the context in case it's not there */
|
|
|
|
[self _setupLocaleInContext:_ctx];
|
|
|
|
|
|
|
|
/* first check attributes directly bound to the application */
|
|
|
|
if ((obj = [super lookupName:_key inContext:_ctx acquire:_flag]))
|
|
|
|
return 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ([_key isEqualToString:@"favicon.ico"])
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
if ([self isUserName:_key inContext:_ctx])
|
|
|
|
return [self lookupUser:_key inContext:_ctx];
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* WebDAV */
|
|
|
|
|
|
|
|
- (NSString *)davDisplayName {
|
|
|
|
/* this is used in the UI, eg in the navigation */
|
|
|
|
return @"SOGo";
|
|
|
|
}
|
|
|
|
|
|
|
|
/* exception handling */
|
|
|
|
|
|
|
|
- (WOResponse *)handleException:(NSException *)_exc
|
|
|
|
inContext:(WOContext *)_ctx
|
|
|
|
{
|
|
|
|
printf("EXCEPTION: %s\n", [[_exc description] cString]);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* runtime maintenance */
|
|
|
|
|
2007-03-07 23:31:34 +01:00
|
|
|
// - (void) _dumpClassAllocation
|
|
|
|
// {
|
|
|
|
// classtree *ct;
|
|
|
|
|
|
|
|
// ct = [classtree newWithTopClass: [NSObject class]];
|
|
|
|
// [ct dumpTree];
|
|
|
|
// }
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
- (void)checkIfDaemonHasToBeShutdown {
|
|
|
|
unsigned int limit, vmem;
|
|
|
|
|
|
|
|
if ((limit = vMemSizeLimit) == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
vmem = [[NSProcessInfo processInfo] virtualMemorySize]/1048576;
|
|
|
|
|
|
|
|
if (vmem > limit) {
|
|
|
|
[self logWithFormat:
|
|
|
|
@"terminating app, vMem size limit (%d MB) has been reached"
|
|
|
|
@" (currently %d MB)",
|
|
|
|
limit, vmem];
|
2007-03-07 23:31:34 +01:00
|
|
|
// [self _dumpClassAllocation];
|
2006-06-15 21:34:10 +02:00
|
|
|
[self terminate];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (WOResponse *)dispatchRequest:(WORequest *)_request {
|
|
|
|
static NSArray *runLoopModes = nil;
|
|
|
|
WOResponse *resp;
|
|
|
|
|
|
|
|
resp = [super dispatchRequest:_request];
|
|
|
|
|
|
|
|
if ([self isTerminating])
|
|
|
|
return resp;
|
|
|
|
|
|
|
|
if (runLoopModes == nil)
|
|
|
|
runLoopModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, nil];
|
|
|
|
|
|
|
|
// TODO: a bit complicated? (-perform:afterDelay: doesn't work?)
|
|
|
|
[[NSRunLoop currentRunLoop] performSelector:
|
|
|
|
@selector(checkIfDaemonHasToBeShutdown)
|
|
|
|
target:self argument:nil
|
|
|
|
order:1 modes:runLoopModes];
|
|
|
|
return resp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* session management */
|
|
|
|
|
|
|
|
- (id)createSessionForRequest:(WORequest *)_request {
|
|
|
|
[self warnWithFormat:@"session creation requested!"];
|
|
|
|
if (doCrashOnSessionCreate)
|
|
|
|
abort();
|
|
|
|
return [super createSessionForRequest:_request];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* localization */
|
|
|
|
|
|
|
|
- (NSDictionary *)currentLocaleConsideringLanguages:(NSArray *)_langs {
|
|
|
|
unsigned i, count;
|
|
|
|
|
|
|
|
/* assume _langs is ordered by priority */
|
|
|
|
count = [_langs count];
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
NSString *lname;
|
|
|
|
NSDictionary *locale;
|
|
|
|
|
|
|
|
lname = [_langs objectAtIndex:i];
|
|
|
|
locale = [self localeForLanguageNamed:lname];
|
|
|
|
if (locale != nil)
|
|
|
|
return locale;
|
|
|
|
}
|
|
|
|
/* no appropriate language, fallback to default */
|
|
|
|
return [self localeForLanguageNamed:@"English"];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)pathToLocaleForLanguageNamed:(NSString *)_name {
|
|
|
|
static Class MainProduct = Nil;
|
|
|
|
NSString *lpath;
|
|
|
|
|
|
|
|
lpath = [[self resourceManager] pathForResourceNamed:@"Locale"
|
|
|
|
inFramework:nil
|
|
|
|
languages:[NSArray arrayWithObject:_name]];
|
|
|
|
if ([lpath isNotNull])
|
|
|
|
return lpath;
|
|
|
|
|
|
|
|
if (MainProduct == Nil) {
|
2006-12-14 22:22:57 +01:00
|
|
|
if ((MainProduct = $(@"MainUIProduct")) == Nil)
|
2006-06-15 21:34:10 +02:00
|
|
|
[self errorWithFormat:@"did not find MainUIProduct class!"];
|
|
|
|
}
|
|
|
|
|
|
|
|
lpath = [(id)MainProduct pathToLocaleForLanguageNamed:_name];
|
|
|
|
if ([lpath isNotNull])
|
|
|
|
return lpath;
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDictionary *)localeForLanguageNamed:(NSString *)_name {
|
|
|
|
NSString *lpath;
|
|
|
|
id data;
|
|
|
|
NSDictionary *locale;
|
|
|
|
|
|
|
|
if (![_name isNotNull]) {
|
|
|
|
[self errorWithFormat:@"%s: name parameter must not be nil!",
|
|
|
|
__PRETTY_FUNCTION__];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((locale = [self->localeLUT objectForKey:_name]) != nil)
|
|
|
|
return locale;
|
|
|
|
|
|
|
|
if ((lpath = [self pathToLocaleForLanguageNamed:_name]) == nil) {
|
|
|
|
[self errorWithFormat:@"did not find Locale for language: %@", _name];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((data = [NSData dataWithContentsOfFile:lpath]) == nil) {
|
|
|
|
[self logWithFormat:@"%s didn't find locale with name:%@",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
_name];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
data = [[[NSString alloc] initWithData:data
|
|
|
|
encoding:NSUTF8StringEncoding] autorelease];
|
|
|
|
locale = [data propertyList];
|
|
|
|
if (locale == nil) {
|
|
|
|
[self logWithFormat:@"%s couldn't load locale with name:%@",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
_name];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
[self->localeLUT setObject:locale forKey:_name];
|
|
|
|
return locale;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* name (used by the WEResourceManager) */
|
|
|
|
|
|
|
|
- (NSString *)name {
|
|
|
|
return @"SOGo-0.9";
|
|
|
|
}
|
|
|
|
|
|
|
|
@end /* SOGo */
|