Monotone-Parent: f6d0d3d72013771c7544d3498ed9510e4a4a9ff2

Monotone-Revision: 597389f8260d0d6fdfa812be82b4f10f924e5c8b

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2008-06-30T14:12:10
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Wolfgang Sourdeau
2008-06-30 14:12:10 +00:00
parent e389f53590
commit 7c2be6f0d3
2 changed files with 265 additions and 229 deletions
+5
View File
@@ -1,5 +1,10 @@
2008-06-30 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* GCSFolderManager.m ([GCSFolderManager
-createFolderOfType:_typewithName:_nameatPath:_path]): wrap the
creation queries in a transaction, to ensure the creation of
tables is atomic.
* GCSFolder.m ([GCSFolder -recordOfEntryWithName:name])
([GCSFolder -writeContent:_contenttoName:_namebaseVersion:_baseVersion])
([GCSFolder -fetchFields:fieldsfetchSpecification:spec]): don't
+260 -229
View File
@@ -29,16 +29,17 @@
#import "EOAdaptorChannel+GCS.h"
#import "common.h"
#import <GDLAccess/EOAdaptorChannel.h>
#import <GDLAccess/EOAdaptorContext.h>
#import <NGExtensions/NGResourceLocator.h>
#import <unistd.h>
/*
Required database schema:
<arbitary table>
c_path
c_path1, path2, path3... [quickPathCount times]
c_foldername
<arbitary table>
c_path
c_path1, path2, path3... [quickPathCount times]
c_foldername
TODO:
- add a local cache?
@@ -68,12 +69,12 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
int seed;
seed = ([[NSDate date] timeIntervalSince1970]
seed = ((unsigned int) [[NSDate date] timeIntervalSince1970]
+ [[NSProcessInfo processInfo] processIdentifier]);
srand (seed);
debugOn = [ud boolForKey:@"GCSFolderManagerDebugEnabled"];
debugSQLGen = [ud boolForKey:@"GCSFolderManagerSQLDebugEnabled"];
debugOn = [ud boolForKey: @"GCSFolderManagerDebugEnabled"];
debugSQLGen = [ud boolForKey: @"GCSFolderManagerSQLDebugEnabled"];
emptyArray = [[NSArray alloc] init];
if (!asciiAlphaNumericCS)
{
@@ -112,7 +113,8 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
return fm;
}
- (NSDictionary *)loadDefaultFolderTypes {
- (NSDictionary *) loadDefaultFolderTypes
{
NSMutableDictionary *typeMap;
NSArray *types;
unsigned i, count;
@@ -136,7 +138,7 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
typeObject = [[GCSFolderType alloc] initWithFolderTypeName:type];
[self logWithFormat:@" %@: %s",
type, [typeObject isNotNull] ? "OK" : "FAIL"];
type, [typeObject isNotNull] ? "OK" : "FAIL"];
[typeMap setObject:typeObject forKey:type];
[typeObject release];
}
@@ -147,13 +149,13 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
- (id)initWithFolderInfoLocation:(NSURL *)_url {
if (_url == nil) {
[self logWithFormat:@"ERROR(%s): missing folder info url!",
__PRETTY_FUNCTION__];
__PRETTY_FUNCTION__];
[self release];
return nil;
}
if ((self = [super init])) {
self->channelManager = [[GCSChannelManager defaultChannelManager] retain];
self->folderInfoLocation = [_url retain];
channelManager = [[GCSChannelManager defaultChannelManager] retain];
folderInfoLocation = [_url retain];
if ([[self folderInfoTableName] length] == 0) {
[self logWithFormat:@"ERROR(%s): missing tablename in URL: %@",
@@ -163,22 +165,23 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
}
/* register default folder types */
self->nameToType = [[self loadDefaultFolderTypes] copy];
nameToType = [[self loadDefaultFolderTypes] copy];
}
return self;
}
- (void)dealloc {
[self->nameToType release];
[self->folderInfoLocation release];
[self->channelManager release];
- (void) dealloc
{
[nameToType release];
[folderInfoLocation release];
[channelManager release];
[super dealloc];
}
/* accessors */
- (NSURL *)folderInfoLocation {
return self->folderInfoLocation;
return folderInfoLocation;
}
- (NSString *)folderInfoTableName {
@@ -188,14 +191,14 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
/* connection */
- (GCSChannelManager *)channelManager {
return self->channelManager;
return channelManager;
}
- (EOAdaptorChannel *)acquireOpenChannel {
EOAdaptorChannel *ch;
ch = [[self channelManager] acquireOpenChannelForURL:
[self folderInfoLocation]];
[self folderInfoLocation]];
return ch;
}
- (void)releaseChannel:(EOAdaptorChannel *)_channel {
@@ -226,7 +229,7 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
if ((ex = [channel evaluateExpressionX:_sql]) != nil) {
[self logWithFormat:@"ERROR(%s): cannot execute\n SQL '%@':\n %@",
__PRETTY_FUNCTION__, _sql, ex];
__PRETTY_FUNCTION__, _sql, ex];
[self releaseChannel:channel];
return nil;
}
@@ -256,14 +259,14 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
folderTypeName = [_record objectForKey:@"c_folder_type"];
if (![folderTypeName isNotNull]) {
[self logWithFormat:@"ERROR(%s): missing type in folder: %@",
__PRETTY_FUNCTION__, _record];
__PRETTY_FUNCTION__, _record];
return nil;
}
if ((folderType = [self folderTypeWithName:folderTypeName]) == nil) {
[self logWithFormat:
@"ERROR(%s): could not resolve type '%@' of folder: %@",
__PRETTY_FUNCTION__,
folderTypeName, [_record valueForKey:@"c_path"]];
__PRETTY_FUNCTION__,
folderTypeName, [_record valueForKey:@"c_path"]];
return nil;
}
@@ -277,7 +280,7 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
: nil;
if (location == nil) {
[self logWithFormat:@"ERROR(%s): missing folder location in record: %@",
__PRETTY_FUNCTION__, _record];
__PRETTY_FUNCTION__, _record];
return nil;
}
@@ -288,7 +291,7 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
if (quickLocation == nil) {
[self logWithFormat:@"WARNING(%s): missing quick location in record: %@",
__PRETTY_FUNCTION__, _record];
__PRETTY_FUNCTION__, _record];
}
locationString = [_record objectForKey:@"c_acl_location"];
@@ -308,7 +311,7 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
/* path SQL */
- (NSString *)generateSQLWhereForInternalNames:(NSArray *)_names
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
{
/* generates a WHERE qualifier for matching the "quick" entries */
NSMutableString *sql;
@@ -316,7 +319,7 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
if ((count = [_names count]) == 0) {
[self debugWithFormat:@"WARNING(%s): passed in empty name array!",
__PRETTY_FUNCTION__];
__PRETTY_FUNCTION__];
return @"1 = 2";
}
@@ -374,7 +377,7 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
}
- (NSString *)generateSQLPathFetchForInternalNames:(NSArray *)_names
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
{
/* fetches the 'path' subset for a given quick-names */
NSMutableString *sql;
@@ -404,109 +407,142 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
return YES;
}
- (NSString *)internalNameFromPath:(NSString *)_path {
- (NSString *) internalNameFromPath: (NSString *) _path
{
NSString *name;
// TODO: ensure proper path and SQL escaping!
if (![self _isStandardizedPath:_path]) {
[self debugWithFormat:@"%s: not a standardized path: '%@'",
if ([self _isStandardizedPath:_path])
{
if ([_path hasSuffix:@"/"] && [_path length] > 1)
name = [_path substringToIndex: ([_path length] - 1)];
else
name = _path;
}
else
{
[self debugWithFormat:@"%s: not a standardized path: '%@'",
__PRETTY_FUNCTION__, _path];
return nil;
}
name = nil;
}
if ([_path hasSuffix:@"/"] && [_path length] > 1)
_path = [_path substringToIndex:([_path length] - 1)];
return _path;
return name;
}
- (NSArray *)internalNamesFromPath:(NSString *)_path {
- (NSArray *) internalNamesFromPath: (NSString *) _path
{
NSString *fname;
NSArray *fnames;
if ((fname = [self internalNameFromPath:_path]) == nil)
return nil;
if ([fname hasPrefix:@"/"])
fname = [fname substringFromIndex:1];
fnames = [fname componentsSeparatedByString:@"/"];
if ([fnames count] == 0)
return nil;
fname = [self internalNameFromPath: _path];
if (fname)
{
if ([fname hasPrefix:@"/"])
fname = [fname substringFromIndex: 1];
fnames = [fname componentsSeparatedByString:@"/"];
if ([fnames count] == 0)
fnames = nil;
}
else
fnames = nil;
return fnames;
}
- (NSString *)pathFromInternalName:(NSString *)_name {
- (NSString *) pathFromInternalName: (NSString *) _name
{
/* for incomplete pathes, like '/Users/helge/' */
return _name;
}
- (NSString *)pathPartFromInternalName:(NSString *)_name {
- (NSString *) pathPartFromInternalName: (NSString *) _name
{
/* for incomplete pathes, like 'Users/' */
return _name;
}
- (NSDictionary *)filterRecords:(NSArray *)_records forPath:(NSString *)_path {
unsigned i, count;
- (NSDictionary *) filterRecords: (NSArray *) _records
forPath: (NSString *) _path
{
NSString *name;
if (_records == nil) return nil;
if ((name = [self internalNameFromPath:_path]) == nil) return nil;
for (i = 0, count = [_records count]; i < count; i++) {
NSDictionary *record;
NSString *recName;
record = [_records objectAtIndex:i];
recName = [record objectForKey:GCSPathRecordName];
NSDictionary *record, *matchRecord;
NSString *recName;
unsigned int i, count;
matchRecord = nil;
if (_records)
{
name = [self internalNameFromPath: _path];
if (name)
{
count = [_records count];
i = 0;
while (!matchRecord && i < count)
{
record = [_records objectAtIndex: i];
recName = [record objectForKey: GCSPathRecordName];
#if 0
[self logWithFormat:@"check '%@' vs '%@' (%@)...",
name, recName, [_records objectAtIndex:i]];
[self logWithFormat:@"check '%@' vs '%@' (%@)...",
name, recName, [_records objectAtIndex:i]];
#endif
if ([name isEqualToString:recName])
return [_records objectAtIndex:i];
}
return nil;
if ([name isEqualToString: recName])
matchRecord = record;
else
i++;
}
}
}
return matchRecord;
}
- (BOOL)folderExistsAtPath:(NSString *)_path {
NSString *fname;
- (BOOL) folderExistsAtPath: (NSString *) _path
{
NSString *fname, *sname, *sql;
NSArray *fnames, *records;
NSString *sql;
unsigned count;
unsigned int count;
NSDictionary *record;
BOOL result;
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
fnames = [self internalNamesFromPath: _path];
if (fnames)
{
sql = [self generateSQLPathFetchForInternalNames: fnames
exactMatch: YES
orDirectSubfolderMatch: NO];
if ([sql length])
{
records = [self performSQL: sql];
if (records)
{
count = [records count];
if (count)
{
fname = [self internalNameFromPath: _path];
if (count == 1)
{
record = [records objectAtIndex: 0];
sname = [record objectForKey: GCSPathRecordName];
result = [fname isEqualToString: sname];
}
else
[self logWithFormat: @"records: %@", records];
}
}
else
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
__PRETTY_FUNCTION__, sql];
}
else
[self debugWithFormat:@"got no SQL for names: %@", fnames];
}
else
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
return NO;
}
sql = [self generateSQLPathFetchForInternalNames:fnames
exactMatch:YES orDirectSubfolderMatch:NO];
if ([sql length] == 0) {
[self debugWithFormat:@"got no SQL for names: %@", fnames];
return NO;
}
if ((records = [self performSQL:sql]) == nil) {
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
__PRETTY_FUNCTION__, sql];
return NO;
}
if ((count = [records count]) == 0)
return NO;
fname = [self internalNameFromPath:_path];
if (count == 1) {
NSDictionary *record;
NSString *sname;
record = [records objectAtIndex:0];
sname = [record objectForKey:GCSPathRecordName];
return [fname isEqualToString:sname];
}
[self logWithFormat:@"records: %@", records];
return NO;
return result;
}
- (NSArray *)listSubFoldersAtPath:(NSString *)_path recursive:(BOOL)_recursive{
@@ -530,7 +566,7 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
if ((records = [self performSQL:sql]) == nil) {
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
__PRETTY_FUNCTION__, sql];
__PRETTY_FUNCTION__, sql];
return nil;
}
@@ -567,7 +603,8 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
return result;
}
- (GCSFolder *)folderAtPath:(NSString *)_path {
- (GCSFolder *) folderAtPath: (NSString *) _path
{
NSMutableString *sql;
NSArray *fnames, *records;
NSString *ws;
@@ -600,7 +637,7 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
if ((records = [self performSQL:sql]) == nil) {
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
__PRETTY_FUNCTION__, sql];
__PRETTY_FUNCTION__, sql];
return nil;
}
@@ -615,7 +652,7 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
}
[self logWithFormat:@"ERROR(%s): more than one row for path: '%@'",
__PRETTY_FUNCTION__, _path];
__PRETTY_FUNCTION__, _path];
return nil;
}
@@ -654,128 +691,117 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
newUID, randInc & 0xfff, (unsigned int) rand()];
}
- (NSException *)createFolderOfType:(NSString *)_type
withName:(NSString*)_name atPath:(NSString *)_path
- (NSException *) _reallyCreateFolderWithName: (NSString *) folderName
andFolderType: (NSString *) folderType
andType: (GCSFolderType *) ftype
andChannel: (EOAdaptorChannel
<GCSEOAdaptorChannel> *) channel
atPath: (NSString *) path
{
// TBD: badly broken, needs to be wrapped in a transaction.
// TBD: would be best to perform all operations as a single SQL statement.
GCSFolderType *ftype;
NSString *tableName, *quickTableName, *aclTableName;
NSString *baseURL, *pathElement;
EOAdaptorChannel <GCSEOAdaptorChannel> *channel;
NSEnumerator *pathElements;
NSMutableArray *paths;
NSException *error;
NSString *sql;
NSException *error;
NSString *baseURL, *tableName, *quickTableName, *aclTableName, *sql;
EOAdaptorContext *aContext;
NSMutableArray *paths;
paths = [[NSMutableArray alloc] initWithCapacity: 5];
pathElements = [[_path componentsSeparatedByString: @"/"] objectEnumerator];
while ((pathElement = [pathElements nextObject]) != nil) {
NSString *p = [[NSString alloc] initWithFormat: @"'%@'", pathElement];
[paths addObject: p];
[p release]; p = nil;
}
paths
= [NSMutableArray arrayWithArray: [path componentsSeparatedByString: @"/"]];
while ([paths count] < 5)
[paths addObject: @"NULL"];
tableName = [self baseTableNameWithUID: [paths objectAtIndex: 2]];
aContext = [channel adaptorContext];
[aContext beginTransaction];
error = [channel createGCSFolderTableWithName: tableName];
if (!error)
{
quickTableName = [tableName stringByAppendingString: @"_quick"];
sql = [ftype sqlQuickCreateWithTableName: quickTableName];
error = [channel evaluateExpressionX: sql];
if (!error)
{
aclTableName = [tableName stringByAppendingString: @"_acl"];
error = [channel createGCSFolderACLTableWithName: aclTableName];
if (!error)
{
// TBD: fix SQL injection issues
baseURL
= [[folderInfoLocation absoluteString] stringByDeletingLastPathComponent];
sql = [NSString stringWithFormat: @"INSERT INTO %@"
@" (c_path, c_path1, c_path2, c_path3, c_path4,"
@" c_foldername, c_location, c_quick_location,"
@" c_acl_location, c_folder_type)"
@" VALUES ('%@', '%@', '%@', '%@', '%@', '%@', '%@/%@',"
@" '%@/%@', '%@/%@', '%@')",
[self folderInfoTableName], path,
[paths objectAtIndex: 1], [paths objectAtIndex: 2],
[paths objectAtIndex: 3], [paths objectAtIndex: 4],
[folderName stringByReplacingString: @"'" withString: @"''"],
baseURL, tableName,
baseURL, quickTableName,
baseURL, aclTableName,
folderType];
error = [channel evaluateExpressionX: sql];
}
}
}
if (error)
[aContext rollbackTransaction];
else
[aContext commitTransaction];
return error;
}
- (NSException *) createFolderOfType: (NSString *) _type
withName: (NSString*) _name
atPath: (NSString *) _path
{
// TBD: would be best to perform all operations as a single SQL statement.
GCSFolderType *ftype;
EOAdaptorChannel <GCSEOAdaptorChannel> *channel;
NSException *error;
// TBD: fix SQL injection issue!
sql = [NSString stringWithFormat: @"SELECT * FROM %@ WHERE c_path = '%@'",
[self folderInfoTableName], _path];
if ([[self performSQL: sql] isNotEmpty]) {
return [NSException exceptionWithName:@"GCSExitingFolder"
reason:@"a folder already exists at that path"
userInfo:nil];
}
if ((ftype = [self folderTypeWithName:_type]) == nil) {
return [NSException exceptionWithName:@"GCSMissingFolderType"
reason:@"missing folder type"userInfo:nil];
}
if ((channel = [self acquireOpenChannel]) == nil) {
return [NSException exceptionWithName:@"GCSNoChannel"
reason:@"could not open channel"
userInfo:nil];
}
if ([self folderExistsAtPath: _path])
error = [NSException exceptionWithName: @"GCSExitingFolder"
reason: @"a folder already exists at that path"
userInfo: nil];
else
{
ftype = [self folderTypeWithName:_type];
if (ftype)
{
channel = [self acquireOpenChannel];
if (channel)
{
error = [self _reallyCreateFolderWithName: _name
andFolderType: _type
andType: ftype andChannel: channel
atPath: _path];
if (error && [self folderExistsAtPath: _path])
error = nil;
tableName = [self baseTableNameWithUID: [paths objectAtIndex: 2]];
quickTableName = [tableName stringByAppendingString: @"_quick"];
aclTableName = [tableName stringByAppendingString: @"_acl"];
sql = [@"DROP TABLE " stringByAppendingString:quickTableName];
if ((error = [channel evaluateExpressionX:sql]) != nil)
; // 'DROP TABLE' is allowed to fail (DROP IF EXISTS is not in PG<8.2)
sql = [@"DROP TABLE " stringByAppendingString:tableName];
if ((error = [channel evaluateExpressionX:sql]) != nil)
; // 'DROP TABLE' is allowed to fail (DROP IF EXISTS is not in PG<8.2)
sql = [@"DROP TABLE " stringByAppendingString:aclTableName];
if ((error = [channel evaluateExpressionX:sql]) != nil)
; // 'DROP TABLE' is allowed to fail (DROP IF EXISTS is not in PG<8.2)
if ((error = [channel createGCSFolderTableWithName: tableName]) != nil)
return error;
sql = [ftype sqlQuickCreateWithTableName: quickTableName];
if (debugSQLGen) [self logWithFormat:@"quick-Create: %@", sql];
if ((error = [channel evaluateExpressionX:sql]) != nil) {
/* 'rollback' TBD: wrap in proper tx */
sql = [@"DROP TABLE " stringByAppendingString:tableName];
if ((error = [channel evaluateExpressionX:sql]) != nil) {
[self warnWithFormat:@"failed to drop freshly created table: %@",
tableName];
[self releaseChannel: channel];
}
else
error = [NSException exceptionWithName: @"GCSNoChannel"
reason: @"could not open channel"
userInfo: nil];
}
else
error = [NSException exceptionWithName: @"GCSMissingFolderType"
reason: @"missing folder type"
userInfo: nil];
}
return error;
}
if (debugSQLGen) [self logWithFormat:@"acl-Create: %@", sql];
if ((error = [channel createGCSFolderACLTableWithName: aclTableName])
!= nil) {
/* 'rollback' TBD: wrap in proper tx */
sql = [@"DROP TABLE " stringByAppendingString:quickTableName];
if ((error = [channel evaluateExpressionX:sql]) != nil) {
[self warnWithFormat:@"failed to drop freshly created table: %@",
tableName];
}
sql = [@"DROP TABLE " stringByAppendingString:tableName];
if ((error = [channel evaluateExpressionX:sql]) != nil) {
[self warnWithFormat:@"failed to drop freshly created table: %@",
tableName];
}
return error;
}
// TBD: fix SQL injection issues
baseURL
= [[folderInfoLocation absoluteString] stringByDeletingLastPathComponent];
sql = [NSString stringWithFormat: @"INSERT INTO %@"
@" (c_path, c_path1, c_path2, c_path3, c_path4,"
@" c_foldername, c_location, c_quick_location,"
@" c_acl_location, c_folder_type)"
@" VALUES ('%@', %@, %@, %@, %@, '%@', '%@/%@',"
@" '%@/%@', '%@/%@', '%@')",
[self folderInfoTableName], _path,
[paths objectAtIndex: 1], [paths objectAtIndex: 2],
[paths objectAtIndex: 3], [paths objectAtIndex: 4],
[_name stringByReplacingString: @"'" withString: @"''"],
baseURL, tableName,
baseURL, quickTableName,
baseURL, aclTableName,
_type];
if ((error = [channel evaluateExpressionX:sql]) != nil)
return error;
[paths release]; paths = nil;
[self releaseChannel: channel];
return nil;
return error;
}
- (NSException *)deleteFolderAtPath:(NSString *)_path {
- (NSException *) deleteFolderAtPath: (NSString *) _path
{
GCSFolder *folder;
NSArray *fnames;
NSString *sql, *ws;
@@ -816,7 +842,8 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
/* folder types */
- (GCSFolderType *)folderTypeWithName:(NSString *)_name {
- (GCSFolderType *) folderTypeWithName: (NSString *) _name
{
NSString *specificName;
GCSFolderType *type;
@@ -825,37 +852,41 @@ static NSCharacterSet *asciiAlphaNumericCS = nil;
specificName = [NSString stringWithFormat: @"%@-%@",
_name, [folderInfoLocation scheme]];
type = [self->nameToType objectForKey: [specificName lowercaseString]];
type = [nameToType objectForKey: [specificName lowercaseString]];
if (!type)
type = [self->nameToType objectForKey:[_name lowercaseString]];
type = [nameToType objectForKey:[_name lowercaseString]];
return type;
}
/* cache management */
- (void)reset {
- (void) reset
{
/* does nothing in the moment, but we need a way to signal refreshes */
}
/* debugging */
- (BOOL)isDebuggingEnabled {
- (BOOL) isDebuggingEnabled
{
return debugOn;
}
/* description */
- (NSString *)description {
- (NSString *) description
{
NSMutableString *ms;
ms = [NSMutableString stringWithCapacity:256];
[ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
[ms appendFormat:@" url=%@", [self->folderInfoLocation absoluteString]];
[ms appendFormat:@" url=%@", [folderInfoLocation absoluteString]];
[ms appendFormat:@" channel-manager=0x%p", [self channelManager]];
[ms appendString:@">"];
return ms;
}