Monotone-Parent: 4aaa3d89a907d67df8c23bdce5f9fb5be71e663d
Monotone-Revision: 07a28abc844008a513555a2e67b3e7e410b3f355 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2007-04-16T17:36:56 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
4063ec97a6
commit
e6ee684ac4
|
@ -1,3 +1,9 @@
|
||||||
|
2007-04-16 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
|
||||||
|
* Main/SOGo.m ([SOGo +initialize]): on GNUstep, trigger some
|
||||||
|
debugging facilities when the SOGoDebugObjectAllocation user
|
||||||
|
default is set.
|
||||||
|
|
||||||
2007-04-11 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
2007-04-11 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
|
||||||
* SoObjects/SOGo/NSString+Utilities.m ([NSString -boolValue]): new
|
* SoObjects/SOGo/NSString+Utilities.m ([NSString -boolValue]): new
|
||||||
|
|
295
Main/SOGo.m
295
Main/SOGo.m
|
@ -21,92 +21,6 @@
|
||||||
|
|
||||||
#include <NGObjWeb/SoApplication.h>
|
#include <NGObjWeb/SoApplication.h>
|
||||||
|
|
||||||
// @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
|
|
||||||
|
|
||||||
@interface SOGo : SoApplication
|
@interface SOGo : SoApplication
|
||||||
{
|
{
|
||||||
NSMutableDictionary *localeLUT;
|
NSMutableDictionary *localeLUT;
|
||||||
|
@ -129,24 +43,34 @@
|
||||||
static unsigned int vMemSizeLimit = 0;
|
static unsigned int vMemSizeLimit = 0;
|
||||||
static BOOL doCrashOnSessionCreate = NO;
|
static BOOL doCrashOnSessionCreate = NO;
|
||||||
|
|
||||||
+ (void)initialize {
|
#ifdef GNUSTEP_BASE_LIBRARY
|
||||||
|
static BOOL debugObjectAllocation = NO;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+ (void) initialize
|
||||||
|
{
|
||||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||||
SoClassSecurityInfo *sInfo;
|
SoClassSecurityInfo *sInfo;
|
||||||
NSArray *basicRoles;
|
NSArray *basicRoles;
|
||||||
id tmp;
|
id tmp;
|
||||||
|
|
||||||
doCrashOnSessionCreate = [ud boolForKey:@"SOGoCrashOnSessionCreate"];
|
doCrashOnSessionCreate = [ud boolForKey:@"SOGoCrashOnSessionCreate"];
|
||||||
|
#ifdef GNUSTEP_BASE_LIBRARY
|
||||||
|
debugObjectAllocation = [ud boolForKey: @"SOGoDebugObjectAllocation"];
|
||||||
|
if (debugObjectAllocation)
|
||||||
|
{
|
||||||
|
NSLog (@"activating stats on object allocation");
|
||||||
|
GSDebugAllocationActive (YES);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* vMem size check - default is 200MB */
|
/* vMem size check - default is 200MB */
|
||||||
|
|
||||||
tmp = [ud objectForKey: @"SxVMemLimit"];
|
tmp = [ud objectForKey: @"SxVMemLimit"];
|
||||||
vMemSizeLimit = (tmp != nil)
|
vMemSizeLimit = ((tmp != nil) ? [tmp intValue] : 200);
|
||||||
? [tmp intValue]
|
if (vMemSizeLimit > 0)
|
||||||
: 200;
|
|
||||||
if (vMemSizeLimit > 0) {
|
|
||||||
NSLog(@"Note: vmem size check enabled: shutting down app when "
|
NSLog(@"Note: vmem size check enabled: shutting down app when "
|
||||||
@"vmem > %d MB", vMemSizeLimit);
|
@"vmem > %d MB", vMemSizeLimit);
|
||||||
}
|
|
||||||
#if LIB_FOUNDATION_LIBRARY
|
#if LIB_FOUNDATION_LIBRARY
|
||||||
if ([ud boolForKey:@"SOGoEnableDoubleReleaseCheck"])
|
if ([ud boolForKey:@"SOGoEnableDoubleReleaseCheck"])
|
||||||
[NSAutoreleasePool enableDoubleReleaseCheck: YES];
|
[NSAutoreleasePool enableDoubleReleaseCheck: YES];
|
||||||
|
@ -168,8 +92,10 @@ static BOOL doCrashOnSessionCreate = NO;
|
||||||
[sInfo declareRoles: basicRoles asDefaultForPermission: SoPerm_WebDAVAccess];
|
[sInfo declareRoles: basicRoles asDefaultForPermission: SoPerm_WebDAVAccess];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init {
|
- (id) init
|
||||||
if ((self = [super init])) {
|
{
|
||||||
|
if ((self = [super init]))
|
||||||
|
{
|
||||||
WOResourceManager *rm;
|
WOResourceManager *rm;
|
||||||
|
|
||||||
/* ensure core SoClass'es are setup */
|
/* ensure core SoClass'es are setup */
|
||||||
|
@ -178,7 +104,7 @@ static BOOL doCrashOnSessionCreate = NO;
|
||||||
[$(@"SOGoFolder") soClass];
|
[$(@"SOGoFolder") soClass];
|
||||||
|
|
||||||
/* setup locale cache */
|
/* setup locale cache */
|
||||||
self->localeLUT = [[NSMutableDictionary alloc] initWithCapacity:2];
|
localeLUT = [[NSMutableDictionary alloc] initWithCapacity:2];
|
||||||
|
|
||||||
/* load products */
|
/* load products */
|
||||||
[[SOGoProductLoader productLoader] loadProducts];
|
[[SOGoProductLoader productLoader] loadProducts];
|
||||||
|
@ -187,23 +113,28 @@ static BOOL doCrashOnSessionCreate = NO;
|
||||||
rm = [[WEResourceManager alloc] init];
|
rm = [[WEResourceManager alloc] init];
|
||||||
[self setResourceManager:rm];
|
[self setResourceManager:rm];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void) dealloc
|
||||||
[self->localeLUT release];
|
{
|
||||||
|
[localeLUT release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* authenticator */
|
/* authenticator */
|
||||||
|
|
||||||
- (id)authenticatorInContext:(id)_ctx {
|
- (id) authenticatorInContext: (id) _ctx
|
||||||
|
{
|
||||||
return [$(@"SOGoAuthenticator") sharedSOGoAuthenticator];
|
return [$(@"SOGoAuthenticator") sharedSOGoAuthenticator];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* name lookup */
|
/* name lookup */
|
||||||
|
|
||||||
- (BOOL)isUserName:(NSString *)_key inContext:(id)_ctx {
|
- (BOOL) isUserName: (NSString *) _key
|
||||||
|
inContext: (id) _ctx
|
||||||
|
{
|
||||||
if ([_key length] < 1)
|
if ([_key length] < 1)
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
|
@ -218,21 +149,29 @@ static BOOL doCrashOnSessionCreate = NO;
|
||||||
initWithName:_key inContainer:self] autorelease];
|
initWithName:_key inContainer:self] autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_setupLocaleInContext:(WOContext *)_ctx {
|
- (void) _setupLocaleInContext: (WOContext *) _ctx
|
||||||
|
{
|
||||||
NSArray *langs;
|
NSArray *langs;
|
||||||
NSDictionary *locale;
|
NSDictionary *locale;
|
||||||
|
|
||||||
if ([[_ctx valueForKey:@"locale"] isNotNull])
|
if ([[_ctx valueForKey:@"locale"] isNotNull])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
langs = [[(WOContext *)_ctx request] browserLanguages];
|
langs = [[_ctx request] browserLanguages];
|
||||||
locale = [self currentLocaleConsideringLanguages:langs];
|
locale = [self currentLocaleConsideringLanguages:langs];
|
||||||
[_ctx takeValue:locale forKey:@"locale"];
|
[_ctx takeValue:locale forKey:@"locale"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag {
|
- (id) lookupName: (NSString *) _key
|
||||||
|
inContext: (id) _ctx
|
||||||
|
acquire: (BOOL) _flag
|
||||||
|
{
|
||||||
id obj;
|
id obj;
|
||||||
|
|
||||||
|
#ifdef GNUSTEP_BASE_LIBRARY
|
||||||
|
if (debugObjectAllocation)
|
||||||
|
NSLog(@"objects allocated\n%s", GSDebugAllocationList (YES));
|
||||||
|
#endif
|
||||||
/* put locale info into the context in case it's not there */
|
/* put locale info into the context in case it's not there */
|
||||||
[self _setupLocaleInContext:_ctx];
|
[self _setupLocaleInContext:_ctx];
|
||||||
|
|
||||||
|
@ -259,7 +198,8 @@ static BOOL doCrashOnSessionCreate = NO;
|
||||||
|
|
||||||
/* WebDAV */
|
/* WebDAV */
|
||||||
|
|
||||||
- (NSString *)davDisplayName {
|
- (NSString *) davDisplayName
|
||||||
|
{
|
||||||
/* this is used in the UI, eg in the navigation */
|
/* this is used in the UI, eg in the navigation */
|
||||||
return @"SOGo";
|
return @"SOGo";
|
||||||
}
|
}
|
||||||
|
@ -275,42 +215,37 @@ static BOOL doCrashOnSessionCreate = NO;
|
||||||
|
|
||||||
/* runtime maintenance */
|
/* runtime maintenance */
|
||||||
|
|
||||||
// - (void) _dumpClassAllocation
|
- (void) checkIfDaemonHasToBeShutdown
|
||||||
// {
|
{
|
||||||
// classtree *ct;
|
unsigned int vmem;
|
||||||
|
|
||||||
// ct = [classtree newWithTopClass: [NSObject class]];
|
|
||||||
// [ct dumpTree];
|
|
||||||
// }
|
|
||||||
|
|
||||||
- (void)checkIfDaemonHasToBeShutdown {
|
|
||||||
unsigned int limit, vmem;
|
|
||||||
|
|
||||||
if ((limit = vMemSizeLimit) == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
if (vMemSizeLimit > 0)
|
||||||
|
{
|
||||||
vmem = [[NSProcessInfo processInfo] virtualMemorySize]/1048576;
|
vmem = [[NSProcessInfo processInfo] virtualMemorySize]/1048576;
|
||||||
|
|
||||||
if (vmem > limit) {
|
if (vmem > vMemSizeLimit)
|
||||||
|
{
|
||||||
[self logWithFormat:
|
[self logWithFormat:
|
||||||
@"terminating app, vMem size limit (%d MB) has been reached"
|
@"terminating app, vMem size limit (%d MB) has been reached"
|
||||||
@" (currently %d MB)",
|
@" (currently %d MB)",
|
||||||
limit, vmem];
|
vMemSizeLimit, vmem];
|
||||||
|
// if (debugObjectAllocation)
|
||||||
// [self _dumpClassAllocation];
|
// [self _dumpClassAllocation];
|
||||||
[self terminate];
|
[self terminate];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (WOResponse *)dispatchRequest:(WORequest *)_request {
|
- (WOResponse *) dispatchRequest: (WORequest *) _request
|
||||||
|
{
|
||||||
static NSArray *runLoopModes = nil;
|
static NSArray *runLoopModes = nil;
|
||||||
WOResponse *resp;
|
WOResponse *resp;
|
||||||
|
|
||||||
resp = [super dispatchRequest: _request];
|
resp = [super dispatchRequest: _request];
|
||||||
|
|
||||||
if ([self isTerminating])
|
if (![self isTerminating])
|
||||||
return resp;
|
{
|
||||||
|
if (!runLoopModes)
|
||||||
if (runLoopModes == nil)
|
|
||||||
runLoopModes = [[NSArray alloc] initWithObjects: NSDefaultRunLoopMode, nil];
|
runLoopModes = [[NSArray alloc] initWithObjects: NSDefaultRunLoopMode, nil];
|
||||||
|
|
||||||
// TODO: a bit complicated? (-perform:afterDelay: doesn't work?)
|
// TODO: a bit complicated? (-perform:afterDelay: doesn't work?)
|
||||||
|
@ -318,12 +253,15 @@ static BOOL doCrashOnSessionCreate = NO;
|
||||||
@selector (checkIfDaemonHasToBeShutdown)
|
@selector (checkIfDaemonHasToBeShutdown)
|
||||||
target: self argument: nil
|
target: self argument: nil
|
||||||
order:1 modes:runLoopModes];
|
order:1 modes:runLoopModes];
|
||||||
|
}
|
||||||
|
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* session management */
|
/* session management */
|
||||||
|
|
||||||
- (id)createSessionForRequest:(WORequest *)_request {
|
- (id) createSessionForRequest: (WORequest *) _request
|
||||||
|
{
|
||||||
[self warnWithFormat: @"session creation requested!"];
|
[self warnWithFormat: @"session creation requested!"];
|
||||||
if (doCrashOnSessionCreate)
|
if (doCrashOnSessionCreate)
|
||||||
abort();
|
abort();
|
||||||
|
@ -332,87 +270,102 @@ static BOOL doCrashOnSessionCreate = NO;
|
||||||
|
|
||||||
/* localization */
|
/* localization */
|
||||||
|
|
||||||
- (NSDictionary *)currentLocaleConsideringLanguages:(NSArray *)_langs {
|
- (NSDictionary *) currentLocaleConsideringLanguages: (NSArray *) langs
|
||||||
unsigned i, count;
|
{
|
||||||
|
NSEnumerator *enumerator;
|
||||||
/* assume _langs is ordered by priority */
|
|
||||||
count = [_langs count];
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
NSString *lname;
|
NSString *lname;
|
||||||
NSDictionary *locale;
|
NSDictionary *locale;
|
||||||
|
|
||||||
lname = [_langs objectAtIndex:i];
|
enumerator = [langs objectEnumerator];
|
||||||
|
lname = nil;
|
||||||
|
locale = nil;
|
||||||
|
lname = [enumerator nextObject];
|
||||||
|
while (lname && !locale)
|
||||||
|
{
|
||||||
locale = [self localeForLanguageNamed: lname];
|
locale = [self localeForLanguageNamed: lname];
|
||||||
if (locale != nil)
|
lname = [enumerator nextObject];
|
||||||
return locale;
|
|
||||||
}
|
|
||||||
/* no appropriate language, fallback to default */
|
|
||||||
return [self localeForLanguageNamed:@"English"];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)pathToLocaleForLanguageNamed:(NSString *)_name {
|
if (!locale)
|
||||||
|
locale = [self localeForLanguageNamed: @"English"];
|
||||||
|
|
||||||
|
/* no appropriate language, fallback to default */
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) pathToLocaleForLanguageNamed: (NSString *) _name
|
||||||
|
{
|
||||||
static Class MainProduct = Nil;
|
static Class MainProduct = Nil;
|
||||||
NSString *lpath;
|
NSString *lpath;
|
||||||
|
|
||||||
lpath = [[self resourceManager] pathForResourceNamed: @"Locale"
|
lpath = [[self resourceManager] pathForResourceNamed: @"Locale"
|
||||||
inFramework: nil
|
inFramework: nil
|
||||||
languages: [NSArray arrayWithObject:_name]];
|
languages: [NSArray arrayWithObject:_name]];
|
||||||
if ([lpath isNotNull])
|
if (![lpath length])
|
||||||
return lpath;
|
{
|
||||||
|
if (!MainProduct)
|
||||||
if (MainProduct == Nil) {
|
{
|
||||||
if ((MainProduct = $(@"MainUIProduct")) == Nil)
|
MainProduct = $(@"MainUIProduct");
|
||||||
|
if (!MainProduct)
|
||||||
[self errorWithFormat: @"did not find MainUIProduct class!"];
|
[self errorWithFormat: @"did not find MainUIProduct class!"];
|
||||||
}
|
}
|
||||||
|
|
||||||
lpath = [(id) MainProduct pathToLocaleForLanguageNamed: _name];
|
lpath = [(id) MainProduct pathToLocaleForLanguageNamed: _name];
|
||||||
if ([lpath isNotNull])
|
if (![lpath length])
|
||||||
return lpath;
|
lpath = nil;
|
||||||
|
|
||||||
return nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary *)localeForLanguageNamed:(NSString *)_name {
|
return lpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDictionary *) localeForLanguageNamed: (NSString *) _name
|
||||||
|
{
|
||||||
NSString *lpath;
|
NSString *lpath;
|
||||||
id data;
|
id data;
|
||||||
NSDictionary *locale;
|
NSDictionary *locale;
|
||||||
|
|
||||||
if (![_name isNotNull]) {
|
locale = nil;
|
||||||
[self errorWithFormat:@"%s: name parameter must not be nil!",
|
if ([_name length] > 0)
|
||||||
__PRETTY_FUNCTION__];
|
{
|
||||||
return nil;
|
locale = [localeLUT objectForKey: _name];
|
||||||
}
|
if (!locale)
|
||||||
|
{
|
||||||
if ((locale = [self->localeLUT objectForKey:_name]) != nil)
|
lpath = [self pathToLocaleForLanguageNamed:_name];
|
||||||
return locale;
|
if (lpath)
|
||||||
|
{
|
||||||
if ((lpath = [self pathToLocaleForLanguageNamed:_name]) == nil) {
|
data = [NSData dataWithContentsOfFile: lpath];
|
||||||
[self errorWithFormat:@"did not find Locale for language: %@", _name];
|
if (data)
|
||||||
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
|
data = [[[NSString alloc] initWithData: data
|
||||||
encoding: NSUTF8StringEncoding] autorelease];
|
encoding: NSUTF8StringEncoding] autorelease];
|
||||||
locale = [data propertyList];
|
locale = [data propertyList];
|
||||||
if (locale == nil) {
|
if (locale)
|
||||||
|
[localeLUT setObject: locale forKey: _name];
|
||||||
|
else
|
||||||
[self logWithFormat:@"%s couldn't load locale with name:%@",
|
[self logWithFormat:@"%s couldn't load locale with name:%@",
|
||||||
__PRETTY_FUNCTION__,
|
__PRETTY_FUNCTION__,
|
||||||
_name];
|
_name];
|
||||||
return nil;
|
|
||||||
}
|
}
|
||||||
[self->localeLUT setObject:locale forKey:_name];
|
else
|
||||||
|
[self logWithFormat:@"%s didn't find locale with name: %@",
|
||||||
|
__PRETTY_FUNCTION__,
|
||||||
|
_name];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[self errorWithFormat:@"did not find Locale for language: %@", _name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[self errorWithFormat:@"%s: name parameter must not be nil!",
|
||||||
|
__PRETTY_FUNCTION__];
|
||||||
|
|
||||||
return locale;
|
return locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* name (used by the WEResourceManager) */
|
/* name (used by the WEResourceManager) */
|
||||||
|
|
||||||
- (NSString *)name {
|
- (NSString *) name
|
||||||
|
{
|
||||||
return @"SOGo-0.9";
|
return @"SOGo-0.9";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue