]> err.no Git - scalable-opengroupware.org/blob - Main/SOGo.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1031 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / Main / SOGo.m
1 /*
2   Copyright (C) 2004-2005 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21
22 #include <NGObjWeb/SoApplication.h>
23
24 // @interface classtree : NSObject
25 // {
26 //   Class topClass;
27 //   int indentLevel;
28 // }
29
30 // - (id) initWithTopClass: (Class) newTopClass;
31 // - (void) dumpSiblings: (Class) node;
32
33 // @end
34
35 // @implementation classtree
36
37 // + (id) newWithTopClass: (Class) newTopClass
38 // {
39 //   id newTree;
40
41 //   newTree = [[self alloc] initWithTopClass: newTopClass];
42 //   [newTree autorelease];
43
44 //   return newTree;
45 // }
46
47 // - (id) initWithTopClass: (Class) newTopClass
48 // {
49 //   if ((self = [self init]))
50 //     topClass = newTopClass;
51
52 //   return self;
53 // }
54
55 // #define indentGap 2
56
57 // - (NSString *) indentSpaces
58 // {
59 //   char *spaceString;
60
61 //   spaceString = malloc(sizeof (char *) * indentGap * indentLevel + 1);
62 //   *(spaceString + indentGap * indentLevel) = 0;
63 //   memset (spaceString, ' ', indentGap * indentLevel);
64
65 //   return [[NSString alloc] initWithCStringNoCopy: spaceString
66 //                            length: indentGap * indentLevel
67 //                            freeWhenDone: YES];
68 // }
69
70 // - (void) dumpNode: (Class) node
71 // {
72 //   Class currentSubclass;
73 //   unsigned int count;
74
75 //   count = 0;
76 //   currentSubclass = node->subclass_list;
77 //   if (currentSubclass)
78 //     {
79 //       NSLog(@"%@%@:",
80 //             [[self indentSpaces] autorelease], NSStringFromClass(node));
81 //       indentLevel++;
82 //       [self dumpSiblings: currentSubclass];
83 //       indentLevel--;
84 //     }
85 //   else
86 //     NSLog(@"%@%@", [self indentSpaces], NSStringFromClass(node));
87 // }
88
89 // - (void) dumpSiblings: (Class) node
90 // {
91 //   Class currentNode;
92
93 //   currentNode = node;
94 //   while (currentNode && currentNode->instance_size)
95 //     {
96 //       [self dumpNode: currentNode];
97 //       currentNode = currentNode->sibling_class;
98 //     }
99 // }
100
101 // - (void) dumpTree
102 // {
103 //   indentLevel = 0;
104
105 //   [self dumpSiblings: topClass];
106 // }
107
108 // @end
109
110 @interface SOGo : SoApplication
111 {
112     NSMutableDictionary *localeLUT;
113 }
114
115 - (NSDictionary *) currentLocaleConsideringLanguages:(NSArray *)_langs;
116 - (NSDictionary *) localeForLanguageNamed:(NSString *)_name;
117
118 @end
119
120 #include "SOGoProductLoader.h"
121 #include <WEExtensions/WEResourceManager.h>
122 #include <SOGo/SOGoAuthenticator.h>
123 #include <SOGo/SOGoUserFolder.h>
124 #include <SOGo/SOGoPermissions.h>
125 #include "common.h"
126
127 @implementation SOGo
128
129 static unsigned int vMemSizeLimit = 0;
130 static BOOL doCrashOnSessionCreate = NO;
131
132 + (void)initialize {
133   NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
134   SoClassSecurityInfo *sInfo;
135   NSArray *basicRoles;
136   id tmp;
137   
138   doCrashOnSessionCreate = [ud boolForKey:@"SOGoCrashOnSessionCreate"];
139
140   /* vMem size check - default is 200MB */
141     
142   tmp = [ud objectForKey:@"SxVMemLimit"];
143   vMemSizeLimit = (tmp != nil)
144     ? [tmp intValue]
145     : 200;
146   if (vMemSizeLimit > 0) {
147     NSLog(@"Note: vmem size check enabled: shutting down app when "
148           @"vmem > %d MB", vMemSizeLimit);
149   }
150 #if LIB_FOUNDATION_LIBRARY
151   if ([ud boolForKey:@"SOGoEnableDoubleReleaseCheck"])
152     [NSAutoreleasePool enableDoubleReleaseCheck:YES];
153 #endif
154
155   /* SoClass security declarations */
156   sInfo = [self soClassSecurityInfo];
157   /* require View permission to access the root (bound to authenticated ...) */
158   [sInfo declareObjectProtected: SoPerm_View];
159
160   /* to allow public access to all contained objects (subkeys) */
161   [sInfo setDefaultAccess: @"allow"];
162
163   basicRoles = [NSArray arrayWithObjects: SoRole_Authenticated,
164                         SOGoRole_FreeBusy, nil];
165
166   /* require Authenticated role for View and WebDAV */
167   [sInfo declareRoles: basicRoles asDefaultForPermission: SoPerm_View];
168   [sInfo declareRoles: basicRoles asDefaultForPermission: SoPerm_WebDAVAccess];
169 }
170
171 - (id)init {
172   if ((self = [super init])) {
173     WOResourceManager *rm;
174     
175     /* ensure core SoClass'es are setup */
176     [$(@"SOGoObject")        soClass];
177     [$(@"SOGoContentObject") soClass];
178     [$(@"SOGoFolder")        soClass];
179     
180     /* setup locale cache */
181     self->localeLUT = [[NSMutableDictionary alloc] initWithCapacity:2];
182     
183     /* load products */
184     [[SOGoProductLoader productLoader] loadProducts];
185     
186     /* setup resource manager */
187     rm = [[WEResourceManager alloc] init];
188     [self setResourceManager:rm];
189   }
190   return self;
191 }
192
193 - (void)dealloc {
194   [self->localeLUT release];
195   [super dealloc];
196 }
197
198 /* authenticator */
199
200 - (id)authenticatorInContext:(id)_ctx {
201   return [$(@"SOGoAuthenticator") sharedSOGoAuthenticator];
202 }
203
204 /* name lookup */
205
206 - (BOOL)isUserName:(NSString *)_key inContext:(id)_ctx {
207   if ([_key length] < 1)
208     return NO;
209   
210   if (isdigit([_key characterAtIndex:0]))
211     return NO;
212
213   return YES;
214 }
215
216 - (id)lookupUser:(NSString *)_key inContext:(id)_ctx {
217   return [[[$(@"SOGoUserFolder") alloc] 
218             initWithName:_key inContainer:self] autorelease];
219 }
220
221 - (void)_setupLocaleInContext:(WOContext *)_ctx {
222   NSArray      *langs;
223   NSDictionary *locale;
224   
225   if ([[_ctx valueForKey:@"locale"] isNotNull])
226     return;
227
228   langs = [[(WOContext *)_ctx request] browserLanguages];
229   locale = [self currentLocaleConsideringLanguages:langs];
230   [_ctx takeValue:locale forKey:@"locale"];
231 }
232
233 - (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag {
234   id obj;
235
236   /* put locale info into the context in case it's not there */
237   [self _setupLocaleInContext:_ctx];
238   
239   /* first check attributes directly bound to the application */
240   if ((obj = [super lookupName:_key inContext:_ctx acquire:_flag]))
241     return obj;
242   
243   /* 
244      The problem is, that at this point we still get request for resources,
245      eg 'favicon.ico'.
246      
247      Addition: we also get queries for various other methods, like "GET" if
248                no method was provided in the query path.
249   */
250   
251   if ([_key isEqualToString:@"favicon.ico"])
252     return nil;
253
254   if ([self isUserName:_key inContext:_ctx])
255     return [self lookupUser:_key inContext:_ctx];
256   
257   return nil;
258 }
259
260 /* WebDAV */
261
262 - (NSString *)davDisplayName {
263   /* this is used in the UI, eg in the navigation */
264   return @"SOGo";
265 }
266
267 /* exception handling */
268
269 - (WOResponse *)handleException:(NSException *)_exc
270   inContext:(WOContext *)_ctx
271 {
272   printf("EXCEPTION: %s\n", [[_exc description] cString]);
273   abort();
274 }
275
276 /* runtime maintenance */
277
278 // - (void) _dumpClassAllocation
279 // {
280 //   classtree *ct;
281
282 //   ct = [classtree newWithTopClass: [NSObject class]];
283 //   [ct dumpTree];
284 // }
285
286 - (void)checkIfDaemonHasToBeShutdown {
287   unsigned int limit, vmem;
288   
289   if ((limit = vMemSizeLimit) == 0)
290     return;
291
292   vmem = [[NSProcessInfo processInfo] virtualMemorySize]/1048576;
293
294   if (vmem > limit) {
295     [self logWithFormat:
296           @"terminating app, vMem size limit (%d MB) has been reached"
297           @" (currently %d MB)",
298           limit, vmem];
299 //     [self _dumpClassAllocation];
300     [self terminate];
301   }
302 }
303
304 - (WOResponse *)dispatchRequest:(WORequest *)_request {
305   static NSArray *runLoopModes = nil;
306   WOResponse *resp;
307
308   resp = [super dispatchRequest:_request];
309
310   if ([self isTerminating])
311     return resp;
312
313   if (runLoopModes == nil)
314     runLoopModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, nil];
315   
316   // TODO: a bit complicated? (-perform:afterDelay: doesn't work?)
317   [[NSRunLoop currentRunLoop] performSelector:
318                                 @selector(checkIfDaemonHasToBeShutdown)
319                               target:self argument:nil
320                               order:1 modes:runLoopModes];
321   return resp;
322 }
323
324 /* session management */
325
326 - (id)createSessionForRequest:(WORequest *)_request {
327   [self warnWithFormat:@"session creation requested!"];
328   if (doCrashOnSessionCreate)
329     abort();
330   return [super createSessionForRequest:_request];
331 }
332
333 /* localization */
334
335 - (NSDictionary *)currentLocaleConsideringLanguages:(NSArray *)_langs {
336   unsigned i, count;
337
338   /* assume _langs is ordered by priority */
339   count = [_langs count];
340   for (i = 0; i < count; i++) {
341     NSString     *lname;
342     NSDictionary *locale;
343     
344     lname  = [_langs objectAtIndex:i];
345     locale = [self localeForLanguageNamed:lname];
346     if (locale != nil)
347       return locale;
348   }
349   /* no appropriate language, fallback to default */
350   return [self localeForLanguageNamed:@"English"];
351 }
352
353 - (NSString *)pathToLocaleForLanguageNamed:(NSString *)_name {
354   static Class MainProduct = Nil;
355   NSString *lpath;
356
357   lpath = [[self resourceManager] pathForResourceNamed:@"Locale"
358                                   inFramework:nil
359                                   languages:[NSArray arrayWithObject:_name]];
360   if ([lpath isNotNull])
361     return lpath;
362   
363   if (MainProduct == Nil) {
364     if ((MainProduct = $(@"MainUIProduct")) == Nil)
365       [self errorWithFormat:@"did not find MainUIProduct class!"];
366   }
367   
368   lpath = [(id)MainProduct pathToLocaleForLanguageNamed:_name];
369   if ([lpath isNotNull])
370     return lpath;
371   
372   return nil;
373 }
374
375 - (NSDictionary *)localeForLanguageNamed:(NSString *)_name {
376   NSString     *lpath;
377   id           data;
378   NSDictionary *locale;
379   
380   if (![_name isNotNull]) {
381     [self errorWithFormat:@"%s: name parameter must not be nil!",
382           __PRETTY_FUNCTION__];
383     return nil;
384   }
385   
386   if ((locale = [self->localeLUT objectForKey:_name]) != nil)
387     return locale;
388   
389   if ((lpath = [self pathToLocaleForLanguageNamed:_name]) == nil) {
390     [self errorWithFormat:@"did not find Locale for language: %@", _name];
391     return nil;
392   }
393   
394   if ((data = [NSData dataWithContentsOfFile:lpath]) == nil) {
395     [self logWithFormat:@"%s didn't find locale with name:%@",
396           __PRETTY_FUNCTION__,
397           _name];
398     return nil;
399   }
400   data = [[[NSString alloc] initWithData:data
401                             encoding:NSUTF8StringEncoding] autorelease];
402   locale = [data propertyList];
403   if (locale == nil) {
404     [self logWithFormat:@"%s couldn't load locale with name:%@",
405           __PRETTY_FUNCTION__,
406           _name];
407     return nil;
408   }
409   [self->localeLUT setObject:locale forKey:_name];
410   return locale;
411 }
412
413 /* name (used by the WEResourceManager) */
414
415 - (NSString *)name {
416   return @"SOGo-0.9";
417 }
418
419 @end /* SOGo */