2 Copyright (C) 2004-2005 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #import <Foundation/NSDebug.h>
23 #import <Foundation/NSData.h>
24 #import <Foundation/NSProcessInfo.h>
25 #import <Foundation/NSRunLoop.h>
26 #import <Foundation/NSURL.h>
27 #import <Foundation/NSUserDefaults.h>
29 #import <GDLAccess/EOAdaptorChannel.h>
30 #import <GDLContentStore/GCSChannelManager.h>
32 #import <NGObjWeb/SoApplication.h>
33 #import <NGObjWeb/SoClassSecurityInfo.h>
34 #import <NGObjWeb/WOContext.h>
35 #import <NGObjWeb/WORequest.h>
37 #import <NGExtensions/NGBundleManager.h>
38 #import <NGExtensions/NSNull+misc.h>
39 #import <NGExtensions/NSObject+Logs.h>
40 #import <NGExtensions/NSProcessInfo+misc.h>
41 #import <NGExtensions/NSString+Encoding.h>
43 #import <WEExtensions/WEResourceManager.h>
45 #import <SoObjects/SOGo/SOGoDAVAuthenticator.h>
46 #import <SoObjects/SOGo/SOGoPermissions.h>
47 #import <SoObjects/SOGo/SOGoUserFolder.h>
48 #import <SoObjects/SOGo/SOGoUser.h>
49 #import <SoObjects/SOGo/SOGoWebAuthenticator.h>
52 #import "SOGoProductLoader.h"
54 @interface SOGo : SoApplication
56 NSMutableDictionary *localeLUT;
59 - (NSDictionary *) currentLocaleConsideringLanguages:(NSArray *)_langs;
60 - (NSDictionary *) localeForLanguageNamed:(NSString *)_name;
66 static unsigned int vMemSizeLimit = 0;
67 static BOOL doCrashOnSessionCreate = NO;
68 static BOOL hasCheckedTables = NO;
70 #ifdef GNUSTEP_BASE_LIBRARY
71 static BOOL debugObjectAllocation = NO;
76 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
77 SoClassSecurityInfo *sInfo;
81 NSLog (@"starting SOGo (build %@)", SOGoBuildDate);
83 doCrashOnSessionCreate = [ud boolForKey:@"SOGoCrashOnSessionCreate"];
84 #ifdef GNUSTEP_BASE_LIBRARY
85 debugObjectAllocation = [ud boolForKey: @"SOGoDebugObjectAllocation"];
86 if (debugObjectAllocation)
88 NSLog (@"activating stats on object allocation");
89 GSDebugAllocationActive (YES);
93 /* vMem size check - default is 200MB */
95 tmp = [ud objectForKey: @"SxVMemLimit"];
96 vMemSizeLimit = ((tmp != nil) ? [tmp intValue] : 200);
97 if (vMemSizeLimit > 0)
98 NSLog(@"Note: vmem size check enabled: shutting down app when "
99 @"vmem > %d MB", vMemSizeLimit);
100 #if LIB_FOUNDATION_LIBRARY
101 if ([ud boolForKey:@"SOGoEnableDoubleReleaseCheck"])
102 [NSAutoreleasePool enableDoubleReleaseCheck: YES];
105 /* SoClass security declarations */
106 sInfo = [self soClassSecurityInfo];
107 /* require View permission to access the root (bound to authenticated ...) */
108 // [sInfo declareObjectProtected: SoPerm_View];
110 /* to allow public access to all contained objects (subkeys) */
111 [sInfo setDefaultAccess: @"allow"];
113 basicRoles = [NSArray arrayWithObjects: SoRole_Authenticated,
114 SOGoRole_FreeBusy, nil];
116 /* require Authenticated role for View and WebDAV */
117 [sInfo declareRoles: basicRoles asDefaultForPermission: SoPerm_View];
118 [sInfo declareRoles: basicRoles asDefaultForPermission: SoPerm_WebDAVAccess];
123 if ((self = [super init]))
125 WOResourceManager *rm;
127 /* ensure core SoClass'es are setup */
128 [$(@"SOGoObject") soClass];
129 [$(@"SOGoContentObject") soClass];
130 [$(@"SOGoFolder") soClass];
132 /* setup locale cache */
133 localeLUT = [[NSMutableDictionary alloc] initWithCapacity:2];
136 [[SOGoProductLoader productLoader] loadProducts];
138 /* setup resource manager */
139 rm = [[WEResourceManager alloc] init];
140 [self setResourceManager:rm];
152 - (void) _checkTableWithCM: (GCSChannelManager *) cm
153 tableURL: (NSString *) url
154 andType: (NSString *) tableType
156 NSString *tableName, *descFile, *tableFile, *fileSuffix;
157 EOAdaptorChannel *tc;
163 bm = [NGBundleManager defaultBundleManager];
165 channelURL = [NSURL URLWithString: url];
166 fileSuffix = [channelURL scheme];
167 tc = [cm acquireOpenChannelForURL: channelURL];
169 tableName = [url lastPathComponent];
170 if ([tc evaluateExpressionX:
171 [NSString stringWithFormat: @"SELECT count(*) FROM %@", tableName]])
173 bundle = [bm bundleWithName: @"MainUI" type: @"SOGo"];
174 length = [tableType length] - 3;
175 tableFile = [tableType substringToIndex: length];
177 = [bundle pathForResource: [NSString stringWithFormat: @"%@-%@",
178 tableFile, fileSuffix]
181 descFile = [bundle pathForResource: tableFile ofType: @"sql"];
182 if (![tc evaluateExpressionX:
183 [NSString stringWithContentsOfFile: descFile]])
184 [self logWithFormat: @"table '%@' successfully created!", tableName];
189 [cm releaseChannel: tc];
192 - (BOOL) _checkMandatoryTables
194 GCSChannelManager *cm;
195 NSString *urlStrings[] = {@"AgenorProfileURL", @"OCSFolderInfoURL", nil};
196 NSString **urlString;
201 ud = [NSUserDefaults standardUserDefaults];
203 cm = [GCSChannelManager defaultChannelManager];
205 urlString = urlStrings;
206 while (ok && *urlString)
208 value = [ud stringForKey: *urlString];
211 [self _checkTableWithCM: cm tableURL: value andType: *urlString];
216 NSLog (@"No value specified for '%@'", *urlString);
226 if (!hasCheckedTables)
228 hasCheckedTables = YES;
229 [self _checkMandatoryTables];
236 - (id) authenticatorInContext: (WOContext *) context
241 key = [[context request] requestHandlerKey];
242 if ([key isEqualToString: @"dav"])
243 authenticator = [SOGoDAVAuthenticator sharedSOGoDAVAuthenticator];
245 authenticator = [SOGoWebAuthenticator sharedSOGoWebAuthenticator];
247 return authenticator;
252 - (BOOL) isUserName: (NSString *) _key
255 if ([_key length] < 1)
261 - (id) lookupUser: (NSString *) _key
267 user = [SOGoUser userWithLogin: _key roles: nil];
269 userFolder = [$(@"SOGoUserFolder") objectWithName: _key
277 - (void) _setupLocaleInContext: (WOContext *) _ctx
280 NSDictionary *locale;
282 if ([[_ctx valueForKey:@"locale"] isNotNull])
285 langs = [[_ctx request] browserLanguages];
286 locale = [self currentLocaleConsideringLanguages:langs];
287 [_ctx takeValue:locale forKey:@"locale"];
290 - (id) lookupName: (NSString *) _key
292 acquire: (BOOL) _flag
296 #ifdef GNUSTEP_BASE_LIBRARY
297 if (debugObjectAllocation)
298 NSLog(@"objects allocated\n%s", GSDebugAllocationList (YES));
300 /* put locale info into the context in case it's not there */
301 [self _setupLocaleInContext:_ctx];
303 /* first check attributes directly bound to the application */
304 if ((obj = [super lookupName:_key inContext:_ctx acquire:_flag]))
308 The problem is, that at this point we still get request for resources,
311 Addition: we also get queries for various other methods, like "GET" if
312 no method was provided in the query path.
315 if ([_key isEqualToString:@"favicon.ico"])
318 if ([self isUserName:_key inContext:_ctx])
319 return [self lookupUser:_key inContext:_ctx];
326 - (NSString *) davDisplayName
328 /* this is used in the UI, eg in the navigation */
332 /* exception handling */
334 - (WOResponse *) handleException: (NSException *) _exc
335 inContext: (WOContext *) _ctx
337 printf("EXCEPTION: %s\n", [[_exc description] cString]);
341 /* runtime maintenance */
343 - (void) checkIfDaemonHasToBeShutdown
347 if (vMemSizeLimit > 0)
349 vmem = [[NSProcessInfo processInfo] virtualMemorySize]/1048576;
351 if (vmem > vMemSizeLimit)
354 @"terminating app, vMem size limit (%d MB) has been reached"
355 @" (currently %d MB)",
356 vMemSizeLimit, vmem];
357 // if (debugObjectAllocation)
358 // [self _dumpClassAllocation];
364 - (WOResponse *) dispatchRequest: (WORequest *) _request
366 static NSArray *runLoopModes = nil;
369 resp = [super dispatchRequest: _request];
371 if (![self isTerminating])
374 runLoopModes = [[NSArray alloc] initWithObjects: NSDefaultRunLoopMode, nil];
376 // TODO: a bit complicated? (-perform:afterDelay: doesn't work?)
377 [[NSRunLoop currentRunLoop] performSelector:
378 @selector (checkIfDaemonHasToBeShutdown)
379 target: self argument: nil
380 order:1 modes:runLoopModes];
386 /* session management */
388 - (id) createSessionForRequest: (WORequest *) _request
390 [self warnWithFormat: @"session creation requested!"];
391 if (doCrashOnSessionCreate)
393 return [super createSessionForRequest:_request];
398 - (NSDictionary *) currentLocaleConsideringLanguages: (NSArray *) langs
400 NSEnumerator *enumerator;
402 NSDictionary *locale;
404 enumerator = [langs objectEnumerator];
407 lname = [enumerator nextObject];
408 while (lname && !locale)
410 locale = [self localeForLanguageNamed: lname];
411 lname = [enumerator nextObject];
415 locale = [self localeForLanguageNamed: @"English"];
417 /* no appropriate language, fallback to default */
421 - (NSString *) pathToLocaleForLanguageNamed: (NSString *) _name
423 static Class MainProduct = Nil;
426 lpath = [[self resourceManager] pathForResourceNamed: @"Locale"
428 languages: [NSArray arrayWithObject:_name]];
433 MainProduct = $(@"MainUIProduct");
435 [self errorWithFormat: @"did not find MainUIProduct class!"];
438 lpath = [(id) MainProduct pathToLocaleForLanguageNamed: _name];
446 - (NSDictionary *) localeForLanguageNamed: (NSString *) _name
450 NSDictionary *locale;
453 if ([_name length] > 0)
455 locale = [localeLUT objectForKey: _name];
458 lpath = [self pathToLocaleForLanguageNamed:_name];
461 data = [NSData dataWithContentsOfFile: lpath];
464 data = [[[NSString alloc] initWithData: data
465 encoding: NSUTF8StringEncoding] autorelease];
466 locale = [data propertyList];
468 [localeLUT setObject: locale forKey: _name];
470 [self logWithFormat:@"%s couldn't load locale with name:%@",
475 [self logWithFormat:@"%s didn't find locale with name: %@",
480 [self errorWithFormat:@"did not find Locale for language: %@", _name];
484 [self errorWithFormat:@"%s: name parameter must not be nil!",
485 __PRETTY_FUNCTION__];
490 /* name (used by the WEResourceManager) */