From: wolfgang Date: Thu, 29 Mar 2007 19:53:25 +0000 (+0000) Subject: git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1034 d1b88da0-ebda-0310... X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=035a30162fc300798dba0244be4e540e39a9bd57;p=scalable-opengroupware.org git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1034 d1b88da0-ebda-0310-925b-ed51d893ca5b --- diff --git a/ChangeLog b/ChangeLog index c1dad0c5..4091f7b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,103 @@ +2007-03-29 Wolfgang Sourdeau + + * UI/Contacts/UIxContactsListViewContainer.m + ([UIxContactsListViewContainer -additionalFolders]): take the list + of subscribed folders from the new property list used for the user + settings. The value of its key is SubscribedFolders for the + dictionary entry named "Contacts". + + * UI/Contacts/UIxContactsListView.m ([UIxContactsListView + -canAccessContentAction]): new method to override the one from + UIxFoldersActions by taking into account the fact that, this time, + the clientObject is an ldap folder. Removed many method that used + to be related to the handling of the user selector. + + * UI/Scheduler/UIxCalDayView.m: commented out many unused methods + to make sure they can be removed. + + * UI/Scheduler/UIxCalView.m ([UIxCalView -_setupCalendarFolders]): + populate the calendar entries based on the user settings plist. + + * UI/Contacts/UIxContactFoldersView.m ([UIxContactFoldersView + -selectForMailerAction]): restored method. + + * UI/Scheduler/UIxCalendarSelector.m: new template module derived + from a simplified version of the old UIxContactEditor (removed). + + * UI/Contacts/UIxContactsUserFolders.m: new template module for + selecting users or user folders through an LDAP search of which + the results are displayed as a tree. + + * UI/WebServerResources/UIxMailEditor.js: moved previous generic + method "onContactAdd" here since the Mailer is now the only module + to use it when composing emails. + + * UI/WebServerResources/generic.js: added code for handling the + new scheme used for describing SOGo folders, common code to handle + folder addition or removal. + + * UI/Common/UIxFolderActions.m ([UIxFolderActions + -activateFolderAction]): new method that change the "active" + settings in the folder-related fields in the user settings. + ([UIxFolderActions -deactivateFolderAction]): see above. + + * UI/Contacts/UIxContactFoldersView.m ([UIxContactFoldersView + -checkRightsAction]): removed method. + + * UI/Contacts/UIxContactFoldersView.m ([UIxContactFoldersView + -updateAdditionalAddressBooksAction]): removed method. + + * UI/Scheduler/UIxCalMainView.m ([UIxCalMainView + -updateCalendarsAction]): removed method. + +2007-03-28 Wolfgang Sourdeau + + * UI/Scheduler/UIxCalMainView.m ([UIxCalMainView + -checkRightsAction]): removed method. + + * UI/Common/UIxFolderActions.m ([UIxFolderActions + -canAccessContentAction]): new method designed to replace + [UIxCalMainView checkRightsAction] in a more universal way. + +2007-03-27 Wolfgang Sourdeau + + * SoObjects/Contacts/SOGoContactFolders.m ([SOGoContactFolders + -roleOfUser:uidinContext:context]): take all the subkeys into + account, not only the "personal" folder. + + * UI/Scheduler/UIxComponentEditor.m ([UIxComponentEditor + -takeValuesFromRequest:_rqinContext:_ctx]): append a "uid" field + to the new components. + + * SoObjects/SOGo/SOGoUser.m ([SOGoUser -userSettings]): new method + (see below). + + * SoObjects/SOGo/AgenorUserManager.m ([AgenorUserManager + -getUserDefaultsForUID:uid]): rewrote method to use the "defaults" + field of the sogo_user_profile table, where the user-customizable + changes will be saved. + ([AgenorUserManager -getUserSettingsForUID:uid]): new method + similar to the one above, using the "settings" field where the + automatic settings will be saved. + + * SoObjects/SOGo/AgenorUserDefaults.m: rewrote a big part of the + module to bind the userdefaults to a property list contained in a + specified field of the sogo_user_profile table. + ([AgenorUserDefaults + -initWithTableURL:tableURLuid:userIDfieldName:defaultsFieldName]): + added a "fieldName" parameter. + + * UI/Common/UIxFolderActions.m: new module implementing web + actions common to all GCS-based folders. + +2007-03-26 Wolfgang Sourdeau + + * UI/Scheduler/UIxCalDayTable.m ([UIxCalDayTable -labelForDay]): + put a carriage return after the day name. + + * UI/MainUI/SOGoUserHomePage.m ([SOGoUserHomePage + -readFreeBusyAction]): restored method. + 2007-03-22 Wolfgang Sourdeau * UI/MainUI/SOGoUserHomePage.m ([SOGoUserHomePage diff --git a/SoObjects/Contacts/SOGoContactFolders.m b/SoObjects/Contacts/SOGoContactFolders.m index 4e57d72d..fb81bb53 100644 --- a/SoObjects/Contacts/SOGoContactFolders.m +++ b/SoObjects/Contacts/SOGoContactFolders.m @@ -239,17 +239,14 @@ if ([traversalPath count] > 2) { objectName = [traversalPath objectAtIndex: 2]; - if ([objectName isEqualToString: @"personal"]) - { - roles = [[context activeUser] - rolesForObject: [self lookupName: objectName - inContext: context - acquire: NO] - inContext: context]; - if ([roles containsObject: SOGoRole_Assistant] - || [roles containsObject: SOGoRole_Delegate]) - role = SOGoRole_Assistant; - } + roles = [[context activeUser] + rolesForObject: [self lookupName: objectName + inContext: context + acquire: NO] + inContext: context]; + if ([roles containsObject: SOGoRole_Assistant] + || [roles containsObject: SOGoRole_Delegate]) + role = SOGoRole_Assistant; } return role; diff --git a/SoObjects/Contacts/product.plist b/SoObjects/Contacts/product.plist index 4ff7a937..6766efe0 100644 --- a/SoObjects/Contacts/product.plist +++ b/SoObjects/Contacts/product.plist @@ -12,7 +12,7 @@ superclass = "SOGoObject"; defaultRoles = { "Add Documents, Images, and Files" = ( "Owner", "Delegate" ); - "View" = ( "Owner", "Delegate", "Assistant" ); + "View" = ( "Owner", "Delegate", "Assistant" ); "WebDAV Access" = ( "Owner", "Delegate", "Assistant" ); "Access Contents Information" = ( "Owner", "Assistant", "Delegate" ); "ReadAcls" = ( "Owner", "Delegate", "Assistant" ); diff --git a/SoObjects/Mailer/SOGoMailFolder.m b/SoObjects/Mailer/SOGoMailFolder.m index cf537404..00db1a0e 100644 --- a/SoObjects/Mailer/SOGoMailFolder.m +++ b/SoObjects/Mailer/SOGoMailFolder.m @@ -295,7 +295,7 @@ static BOOL useAltNamespace = NO; return [self lookupImap4Message:_key inContext:_ctx]; } - obj = [self lookupImap4Folder:_key inContext:_ctx]; + obj = [self lookupImap4Folder:_key inContext:_ctx]; if (obj != nil) return obj; @@ -320,7 +320,7 @@ static BOOL useAltNamespace = NO; } - (NSException *)delete { - /* Note: overrides SOGoObject -delete */ + /* Note: overrides SOGoObject -delete */o return [[self imap4Connection] deleteMailboxAtURL:[self imap4URL]]; } diff --git a/SoObjects/SOGo/AgenorUserDefaults.h b/SoObjects/SOGo/AgenorUserDefaults.h index f984fc91..7bdbca78 100644 --- a/SoObjects/SOGo/AgenorUserDefaults.h +++ b/SoObjects/SOGo/AgenorUserDefaults.h @@ -34,51 +34,54 @@ @class NSString, NSURL, NSUserDefaults, NSArray, NSDictionary, NSData; @class NSCalendarDate, NSMutableDictionary; -@interface AgenorUserDefaults : NSObject +@interface AgenorUserDefaults : NSObject { NSUserDefaults *parent; NSURL *url; NSString *uid; + NSString *fieldName; - NSArray *fieldNames; - NSDictionary *attributes; + NSArray *fieldNames; NSMutableDictionary *values; - NSCalendarDate *lastFetch; + NSCalendarDate *lastFetch; - struct { - int modified:1; - int isNew:1; - int reserved:30; + struct + { + int modified: 1; + int isNew: 1; + int reserved: 30; } defFlags; } -- (id)initWithTableURL:(NSURL *)_url uid:(NSString *)_uid; +- (id) initWithTableURL: (NSURL *) url + uid: (NSString *) uid + fieldName: (NSString *) fieldName; /* value access */ -- (void)setObject:(id)_value forKey:(NSString *)_key; -- (id)objectForKey:(NSString *)_key; -- (void)removeObjectForKey:(NSString *)_key; +- (void) setObject: (id) value + forKey: (NSString *) key; +- (id) objectForKey: (NSString *) key; +- (void) removeObjectForKey: (NSString *) key; /* typed accessors */ -- (NSArray *)arrayForKey:(NSString *)_key; -- (NSDictionary *)dictionaryForKey:(NSString *)_key; -- (NSData *)dataForKey:(NSString *)_key; -- (NSArray *)stringArrayForKey:(NSString *)_key; -- (NSString *)stringForKey:(NSString *)_key; -- (BOOL)boolForKey:(NSString *)_key; -- (float)floatForKey:(NSString *)_key; -- (int)integerForKey:(NSString *)_key; +- (NSArray *) arrayForKey: (NSString *)key; +- (NSDictionary *) dictionaryForKey: (NSString *)key; +- (NSData *) dataForKey: (NSString *)key; +- (NSString *) stringForKey: (NSString *)key; +- (BOOL) boolForKey: (NSString *) key; +- (float) floatForKey: (NSString *) key; +- (int) integerForKey: (NSString *) key; -- (void)setBool:(BOOL)value forKey:(NSString *)_key; -- (void)setFloat:(float)value forKey:(NSString *)_key; -- (void)setInteger:(int)value forKey:(NSString *)_key; +- (void) setBool: (BOOL) value forKey: (NSString *) key; +- (void) setFloat: (float) value forKey: (NSString *) key; +- (void) setInteger: (int) value forKey: (NSString *) key; /* saving changes */ -- (BOOL)synchronize; +- (BOOL) synchronize; @end -#endif /* __AgenorUserDefaults_H_ */ +#endif /* __AgenorUserDefaults_H__ */ diff --git a/SoObjects/SOGo/AgenorUserDefaults.m b/SoObjects/SOGo/AgenorUserDefaults.m index 9b97cc65..1069645b 100644 --- a/SoObjects/SOGo/AgenorUserDefaults.m +++ b/SoObjects/SOGo/AgenorUserDefaults.m @@ -19,454 +19,435 @@ 02111-1307, USA. */ -#include "AgenorUserDefaults.h" -#include -#include -#include -#include -#include -#include "common.h" +#import +#import +#import +#import +#import +#import + +#import "common.h" +#import "AgenorUserDefaults.h" @implementation AgenorUserDefaults static NSString *uidColumnName = @"uid"; -- (id)initWithTableURL:(NSURL *)_url uid:(NSString *)_uid { - if ((self = [super init])) { - if (_url == nil || [_uid length] < 1) { - [self errorWithFormat:@"tried to create AgenorUserDefaults w/o args!"]; - [self release]; - return nil; +- (id) initWithTableURL: (NSURL *) tableURL + uid: (NSString *) userID + fieldName: (NSString *) defaultsFieldName +{ + if ((self = [super init])) + { + if (tableURL && [userID length] > 0 + && [defaultsFieldName length] > 0) + { + parent = [[NSUserDefaults standardUserDefaults] retain]; + fieldName = [defaultsFieldName copy]; + url = [tableURL copy]; + uid = [userID copy]; + } + else + { + [self errorWithFormat: @"missing arguments"]; + [self release]; + self = nil; + } } - self->parent = [[NSUserDefaults standardUserDefaults] retain]; - self->url = [_url copy]; - self->uid = [_uid copy]; - } return self; } -- (id)init { - return [self initWithTableURL:nil uid:nil]; + +- (id) init +{ + [self release]; + + return nil; } -- (void)dealloc { - [self->attributes release]; - [self->lastFetch release]; - [self->parent release]; - [self->url release]; - [self->uid release]; +- (void) dealloc +{ + [values release]; + [lastFetch release]; + [parent release]; + [url release]; + [uid release]; + [fieldName release]; [super dealloc]; } /* accessors */ -- (NSURL *)tableURL { - return self->url; -} -- (NSString *)uid { - return self->uid; +- (NSURL *) tableURL +{ + return url; } -- (NSUserDefaults *)parentDefaults { - return self->parent; +- (NSString *) uid +{ + return uid; } -/* operation */ +- (NSString *) fieldName +{ + return fieldName; +} -- (void)_loadAttributes:(NSArray *)_attrs { - NSMutableArray *fields; - NSMutableDictionary *attrmap; - unsigned i, count; - - fields = [[NSMutableArray alloc] initWithCapacity:16]; - attrmap = [[NSMutableDictionary alloc] initWithCapacity:16]; - for (i = 0, count = [_attrs count]; i < count; i++) { - EOAttribute *attr; - NSString *name; - - attr = [_attrs objectAtIndex:i]; - name = [attr valueForKey:@"name"]; - [attrmap setObject:attr forKey:name]; - - if (![name isEqual:uidColumnName]) - [fields addObject:name]; - } - - ASSIGNCOPY(self->fieldNames, fields); - ASSIGNCOPY(self->attributes, attrmap); - [attrmap release]; - [fields release]; +- (NSUserDefaults *) parentDefaults +{ + return parent; } -- (BOOL)primaryFetchProfile { +/* operation */ + +- (BOOL) primaryFetchProfile +{ GCSChannelManager *cm; - EOAdaptorChannel *channel; - NSDictionary *row; - NSException *ex; - NSString *sql; - NSArray *attrs; + EOAdaptorChannel *channel; + NSDictionary *row; + NSException *ex; + NSString *sql; + NSArray *attrs; + BOOL rc; + + rc = NO; cm = [GCSChannelManager defaultChannelManager]; - if ((channel = [cm acquireOpenChannelForURL:[self tableURL]]) == nil) { + channel = [cm acquireOpenChannelForURL: [self tableURL]]; + if (channel) + { + /* generate SQL */ + sql = [NSString stringWithFormat: (@"SELECT %@" + @" FROM %@" + @" WHERE %@ = '%@'"), + fieldName, [[self tableURL] gcsTableName], + uidColumnName, [self uid]]; + + /* run SQL */ + + ex = [channel evaluateExpressionX: sql]; + if (ex) + { + [self errorWithFormat:@"could not run SQL '%@': %@", sql, ex]; + values = [NSMutableDictionary new]; + } + else + { + /* fetch schema */ + attrs = [channel describeResults: NO /* don't beautify */]; + + /* fetch values */ + row = [channel fetchAttributes: attrs withZone: NULL]; + defFlags.isNew = (row == nil); + [channel cancelFetch]; + + /* remember values */ + [values release]; + values = [[row objectForKey: fieldName] propertyList]; + if (values) + [values retain]; + else + values = [NSMutableDictionary new]; + + ASSIGN(lastFetch, [NSCalendarDate date]); + defFlags.modified = NO; + rc = YES; + } + + [cm releaseChannel:channel]; + } + else [self errorWithFormat:@"failed to acquire channel for URL: %@", [self tableURL]]; - return NO; - } - - /* generate SQL */ - - sql = [[self tableURL] gcsTableName]; - sql = [@"SELECT * FROM " stringByAppendingString:sql]; - sql = [sql stringByAppendingFormat:@" WHERE %@ = '%@'", - uidColumnName, [self uid]]; - - /* run SQL */ - - if ((ex = [channel evaluateExpressionX:sql]) != nil) { - [self errorWithFormat:@"could not run SQL '%@': %@", sql, ex]; - [cm releaseChannel:channel]; - return NO; - } - /* fetch schema */ - - attrs = [channel describeResults:NO /* don't beautify */]; - [self _loadAttributes:attrs]; - - /* fetch values */ - - row = [channel fetchAttributes:attrs withZone:NULL]; - self->defFlags.isNew = (row != nil) ? 0 : 1; - [channel cancelFetch]; - - /* remember values */ - - [self->values release]; self->values = nil; - self->values = (row != nil) - ? [row mutableCopy] - : [[NSMutableDictionary alloc] initWithCapacity:8]; - [self->values removeObjectForKey:uidColumnName]; - - ASSIGN(self->lastFetch, [NSCalendarDate date]); - self->defFlags.modified = 0; - - [cm releaseChannel:channel]; - return YES; -} - -- (NSString *)formatValue:(id)_value forAttribute:(EOAttribute *)_attribute { - NSString *s; - - if (![_value isNotNull]) - return @"NULL"; - - if ([[_attribute externalType] hasPrefix:@"int"]) - return [_value stringValue]; - - s = [_value stringValue]; - s = [s stringByReplacingString:@"'" withString:@"''"]; - s = [[@"'" stringByAppendingString:s] stringByAppendingString:@"'"]; - return s; + return rc; } -- (NSString *)generateSQLForInsert { +- (NSString *) generateSQLForInsert +{ NSMutableString *sql; - unsigned i, count; - - if ([self->values count] == 0) - return nil; - - sql = [NSMutableString stringWithCapacity:2048]; - - [sql appendString:@"INSERT INTO "]; - [sql appendString:[[self tableURL] gcsTableName]]; - [sql appendString:@" ( uid"]; - - for (i = 0, count = [self->fieldNames count]; i < count; i++) { - EOAttribute *attr; - - attr = [self->attributes objectForKey:[self->fieldNames objectAtIndex:i]]; - [sql appendString:@", "]; - [sql appendString:[attr columnName]]; - } - - [sql appendString:@") VALUES ("]; - - [sql appendString:@"'"]; - [sql appendString:[self uid]]; // TODO: escaping necessary? - [sql appendString:@"'"]; - - for (i = 0, count = [self->fieldNames count]; i < count; i++) { - EOAttribute *attr; - id value; - - attr = [self->attributes objectForKey:[self->fieldNames objectAtIndex:i]]; - value = [self->values objectForKey:[self->fieldNames objectAtIndex:i]]; - - [sql appendString:@", "]; - [sql appendString:[self formatValue:value forAttribute:attr]]; - } - - [sql appendString:@")"]; + NSString *serializedDefaults; + +#if LIB_FOUNDATION_LIBRARY + serializedDefaults = [values stringRepresentation]; + + sql = [NSString stringWithFormat: (@"INSERT INTO %@" + @" (%@, %@)" + @" VALUES ('%@', '%@')"), + [[self tableURL] gcsTableName], uidColumnName, fieldName, + [self uid], + [serializedDefaults stringByReplacingString:@"'" withString:@"''"]]; +#else + NSData *serializedDefaultsData; + NSString *error; + + serializedDefaultsData + = [NSPropertyListSerialization dataFromPropertyList: values + format: NSPropertyListOpenStepFormat + errorDescription: &error]; + + if (error) + sql = nil; + else + { + serializedDefaults = [[NSString alloc] initWithData: serializedDefaultsData + encoding: NSUTF8StringEncoding]; + + sql = [NSString stringWithFormat: (@"INSERT INTO %@" + @" (%@, %@)" + @" VALUES ('%@', '%@')"), + [[self tableURL] gcsTableName], uidColumnName, fieldName, + [self uid], + [serializedDefaults stringByReplacingString:@"'" withString:@"''"]]; + [serializedDefaults release]; + } +#endif + return sql; } -- (NSString *)generateSQLForUpdate { +- (NSString *) generateSQLForUpdate +{ NSMutableString *sql; - unsigned i, count; - - if ([self->values count] == 0) - return nil; - - sql = [NSMutableString stringWithCapacity:2048]; - - [sql appendString:@"UPDATE "]; - [sql appendString:[[self tableURL] gcsTableName]]; - [sql appendString:@" SET "]; - - for (i = 0, count = [self->fieldNames count]; i < count; i++) { - EOAttribute *attr; - NSString *name; - id value; - - name = [self->fieldNames objectAtIndex:i]; - value = [self->values objectForKey:name]; - attr = [self->attributes objectForKey:name]; - - if (i != 0) [sql appendString:@", "]; - [sql appendString:[attr columnName]]; - [sql appendString:@" = "]; - [sql appendString:[self formatValue:value forAttribute:attr]]; - } - - [sql appendString:@" WHERE "]; - [sql appendString:uidColumnName]; - [sql appendString:@" = '"]; - [sql appendString:[self uid]]; - [sql appendString:@"'"]; + NSString *serializedDefaults; + +#if LIB_FOUNDATION_LIBRARY + serializedDefaults = [values stringRepresentation]; + + sql = [NSString stringWithFormat: (@"UPDATE %@" + @" SET %@ = '%@'" + @" WHERE %@ = '%@'"), + [[self tableURL] gcsTableName], + fieldName, + [serializedDefaults stringByReplacingString:@"'" withString:@"''"], + uidColumnName, [self uid]]; +#else + NSData *serializedDefaultsData; + NSString *error; + + serializedDefaultsData + = [NSPropertyListSerialization dataFromPropertyList: values + format: NSPropertyListOpenStepFormat + errorDescription: &error]; + error = nil; + if (error) + { + sql = nil; + [error release]; + } + else + { + serializedDefaults = [[NSString alloc] initWithData: serializedDefaultsData + encoding: NSUTF8StringEncoding]; + + sql = [NSString stringWithFormat: (@"UPDATE %@" + @" SET %@ = '%@'" + @" WHERE %@ = '%@'"), + [[self tableURL] gcsTableName], + fieldName, + [serializedDefaults stringByReplacingString:@"'" withString:@"''"], + uidColumnName, [self uid]]; + [serializedDefaults release]; + } +#endif + return sql; } -- (BOOL)primaryStoreProfile { +- (BOOL) primaryStoreProfile +{ GCSChannelManager *cm; - EOAdaptorChannel *channel; - NSException *ex; - NSString *sql; + EOAdaptorChannel *channel; + NSException *ex; + NSString *sql; + BOOL rc; + + rc = NO; cm = [GCSChannelManager defaultChannelManager]; - if ((channel = [cm acquireOpenChannelForURL:[self tableURL]]) == nil) { - [self errorWithFormat:@"failed to acquire channel for URL: %@", - [self tableURL]]; - return NO; - } - - /* run SQL */ - - sql = self->defFlags.isNew - ? [self generateSQLForInsert] - : [self generateSQLForUpdate]; - if ((ex = [channel evaluateExpressionX:sql]) != nil) { - [self errorWithFormat:@"could not run SQL '%@': %@", sql, ex]; - [cm releaseChannel:channel]; - return NO; - } - - /* commit */ - - ex = nil; - if ([[channel adaptorContext] hasOpenTransaction]) - ex = [channel evaluateExpressionX:@"COMMIT TRANSACTION"]; - - [cm releaseChannel:channel]; - - if (ex != nil) { - [self errorWithFormat:@"could not commit transaction for update: %@", ex]; - return NO; - } - - self->defFlags.modified = 0; - self->defFlags.isNew = 0; - return YES; -} - + sql = ((defFlags.isNew) + ? [self generateSQLForInsert] + : [self generateSQLForUpdate]); + if (sql) + { + channel = [cm acquireOpenChannelForURL: [self tableURL]]; + if (channel) + { + ex = [channel evaluateExpressionX:sql]; + if (ex) + [self errorWithFormat: @"could not run SQL '%@': %@", sql, ex]; + else + { + if ([[channel adaptorContext] hasOpenTransaction]) + { + ex = [channel evaluateExpressionX: @"COMMIT TRANSACTION"]; + if (ex) + [self errorWithFormat:@"could not commit transaction for update: %@", ex]; + else + rc = YES; + } + else + rc = YES; + + defFlags.modified = NO; + defFlags.isNew = NO; + } + + [cm releaseChannel: channel]; + } + else + [self errorWithFormat: @"failed to acquire channel for URL: %@", + [self tableURL]]; + } + else + [self errorWithFormat: @"failed to generate SQL for storing defaults"]; -- (BOOL)fetchProfile { - if (self->values != nil) - return YES; - - return [self primaryFetchProfile]; + return rc; } -- (NSArray *)primaryDefaultNames { - if (![self fetchProfile]) - return nil; - - return self->fieldNames; +- (BOOL) fetchProfile +{ + return (values || [self primaryFetchProfile]); } /* value access */ -- (void)setObject:(id)_value forKey:(NSString *)_key { - if (![self fetchProfile]) - return; +- (void) setObject: (id) value + forKey: (NSString *) key +{ + id old; - if (![self->fieldNames containsObject:_key]) { - [self errorWithFormat:@"tried to write key: '%@'", _key]; + if (![self fetchProfile]) return; - } - - /* check whether the value is actually modified */ - if (!self->defFlags.modified) { - id old; - old = [self->values objectForKey:_key]; - if (old == _value || [old isEqual:_value]) /* value didn't change */ - return; - - /* we need to this because our typed accessors convert to strings */ - // TODO: especially problematic with bools - if ([_value isKindOfClass:[NSString class]]) { - if (![old isKindOfClass:[NSString class]]) - if ([[old description] isEqualToString:_value]) - return; + /* check whether the value is actually modified */ + if (!defFlags.modified) + { + old = [values objectForKey: key]; + if (old == value || [old isEqual: value]) /* value didn't change */ + return; + + /* we need to this because our typed accessors convert to strings */ + // TODO: especially problematic with bools + if ([value isKindOfClass: [NSString class]]) { + if (![old isKindOfClass: [NSString class]]) + if ([[old description] isEqualToString: value]) + return; + } } - } - + /* set in hash and mark as modified */ - [self->values setObject:(_value ? _value : [NSNull null]) forKey:_key]; - self->defFlags.modified = 1; + [values setObject: value forKey: key]; + + defFlags.modified = YES; } -- (id)objectForKey:(NSString *)_key { +- (id) objectForKey: (NSString *) key +{ id value; if (![self fetchProfile]) - return nil; - - if (![self->fieldNames containsObject:_key]) - return [self->parent objectForKey:_key]; - - value = [self->values objectForKey:_key]; - return [value isNotNull] ? value : nil; + value = nil; + else + value = [values objectForKey: key]; + + return value; } -- (void)removeObjectForKey:(NSString *)_key { - [self setObject:nil forKey:_key]; +- (void) removeObjectForKey: (NSString *) key +{ + [self setObject: nil forKey: key]; } /* saving changes */ -- (BOOL)synchronize { - if (!self->defFlags.modified) /* was not modified */ - return YES; +- (BOOL) synchronize +{ +// if (!defFlags.modified) /* was not modified */ +// return YES; /* ensure fetched data (more or less guaranteed by modified!=0) */ if (![self fetchProfile]) return NO; /* store */ - if (![self primaryStoreProfile]) { - [self primaryFetchProfile]; - return NO; - } - + if (![self primaryStoreProfile]) + { + [self primaryFetchProfile]; + return NO; + } + /* refetch */ return [self primaryFetchProfile]; } -- (void)flush { - [self->values release]; self->values = nil; - [self->fieldNames release]; self->fieldNames = nil; - [self->attributes release]; self->attributes = nil; - [self->lastFetch release]; self->lastFetch = nil; - self->defFlags.modified = 0; - self->defFlags.isNew = 0; +- (void) flush +{ + [values release]; + [lastFetch release]; + values = nil; + lastFetch = nil; + defFlags.modified = NO; + defFlags.isNew = NO; } /* typed accessors */ -- (NSArray *)arrayForKey:(NSString *)_key { - id obj = [self objectForKey:_key]; - return [obj isKindOfClass:[NSArray class]] ? obj : nil; +- (NSArray *) arrayForKey: (NSString *) key +{ + return [self objectForKey: key]; } -- (NSDictionary *)dictionaryForKey:(NSString *)_key { - id obj = [self objectForKey:_key]; - return [obj isKindOfClass:[NSDictionary class]] ? obj : nil; +- (NSDictionary *) dictionaryForKey: (NSString *) key +{ + return [self objectForKey: key]; } -- (NSData *)dataForKey:(NSString *)_key { - id obj = [self objectForKey:_key]; - return [obj isKindOfClass:[NSData class]] ? obj : nil; +- (NSData *) dataForKey: (NSString *) key +{ + return [self objectForKey: key]; } -- (NSArray *)stringArrayForKey:(NSString *)_key { - id obj = [self objectForKey:_key]; - int n; - Class strClass = [NSString class]; - - if (![obj isKindOfClass:[NSArray class]]) - return nil; - - for (n = [obj count]-1; n >= 0; n--) { - if (![[obj objectAtIndex:n] isKindOfClass:strClass]) - return nil; - } - return obj; +- (NSString *) stringForKey: (NSString *) key +{ + return [self objectForKey: key]; } -- (NSString *)stringForKey:(NSString *)_key { - id obj = [self objectForKey:_key]; - return [obj isKindOfClass:[NSString class]] ? obj : nil; +- (BOOL) boolForKey: (NSString *) key +{ + return [[self objectForKey: key] boolValue]; } -- (BOOL)boolForKey:(NSString *)_key { - // TODO: need special support here for int-DB fields - id obj; - - if ((obj = [self objectForKey:_key]) == nil) - return NO; - if ([obj isKindOfClass:[NSString class]]) { - if ([obj compare:@"YES" options:NSCaseInsensitiveSearch] == NSOrderedSame) - return YES; - } - if ([obj respondsToSelector:@selector(intValue)]) - return [obj intValue] ? YES : NO; - return NO; +- (float) floatForKey: (NSString *) key +{ + return [[self objectForKey: key] floatValue]; } -- (float)floatForKey:(NSString *)_key { - id obj = [self stringForKey:_key]; - return (obj != nil) ? [obj floatValue] : 0.0; -} -- (int)integerForKey:(NSString *)_key { - id obj = [self stringForKey:_key]; - return (obj != nil) ? [obj intValue] : 0; +- (int) integerForKey: (NSString *) key +{ + return [[self objectForKey: key] intValue]; } -- (void)setBool:(BOOL)value forKey:(NSString *)_key { +- (void) setBool: (BOOL) value + forKey: (NSString *) key +{ // TODO: need special support here for int-DB fields - [self setObject:(value ? @"YES" : @"NO") forKey:_key]; -} -- (void)setFloat:(float)value forKey:(NSString *)_key { - [self setObject:[NSString stringWithFormat:@"%f", value] forKey:_key]; -} -- (void)setInteger:(int)value forKey:(NSString *)_key { - [self setObject:[NSString stringWithFormat:@"%d", value] forKey:_key]; + [self setObject: [NSNumber numberWithBool: value] + forKey: key]; } -/* description */ +- (void) setFloat: (float) value + forKey: (NSString *) key +{ + [self setObject: [NSNumber numberWithFloat: value] + forKey: key]; +} -- (NSString *)description { - NSMutableString *ms; - - ms = [NSMutableString stringWithCapacity:16]; - [ms appendFormat:@"<0x%08X[%@]>", self, NSStringFromClass([self class])]; - [ms appendFormat:@" uid=%@", self->uid]; - [ms appendFormat:@" url=%@", [self->url absoluteString]]; - [ms appendFormat:@" parent=0x%08X", self->parent]; - [ms appendString:@">"]; - return ms; +- (void) setInteger: (int) value + forKey: (NSString *) key +{ + [self setObject: [NSNumber numberWithInt: value] + forKey: key]; } @end /* AgenorUserDefaults */ diff --git a/SoObjects/SOGo/AgenorUserManager.h b/SoObjects/SOGo/AgenorUserManager.h index c23fd460..2ad60909 100644 --- a/SoObjects/SOGo/AgenorUserManager.h +++ b/SoObjects/SOGo/AgenorUserManager.h @@ -75,7 +75,8 @@ - (NSURL *)getFreeBusyURLForUID:(NSString *)_uid; -- (NSUserDefaults *)getUserDefaultsForUID:(NSString *)_uid; +- (NSUserDefaults *) getUserDefaultsForUID: (NSString *) uid; +- (NSUserDefaults *) getUserSettingsForUID: (NSString *) uid; - (BOOL)isUserAllowedToChangeSOGoInternetAccess:(NSString *)_uid; diff --git a/SoObjects/SOGo/AgenorUserManager.m b/SoObjects/SOGo/AgenorUserManager.m index b316a11a..619e6662 100644 --- a/SoObjects/SOGo/AgenorUserManager.m +++ b/SoObjects/SOGo/AgenorUserManager.m @@ -1012,22 +1012,39 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; /* defaults */ -- (NSUserDefaults *)getUserDefaultsForUID:(NSString *)_uid { +- (NSUserDefaults *) _getUserDefaultsForUID: (NSString *) uid + fieldName: (NSString *) fieldName +{ id defaults; - if (AgenorProfileURL == nil) { - [self warnWithFormat: - @"no profile configured, cannot retrieve defaults for user: '%@'", - _uid]; - return nil; - } - - /* Note: do not cache, otherwise updates can be quite tricky */ - defaults = [[[AgenorUserDefaults alloc] - initWithTableURL:AgenorProfileURL uid:_uid] autorelease]; + if (AgenorProfileURL) + { + /* Note: do not cache, otherwise updates can be quite tricky */ + defaults = [[AgenorUserDefaults alloc] initWithTableURL: AgenorProfileURL + uid: uid fieldName: fieldName]; + [defaults autorelease]; + } + else + { + [self warnWithFormat: + @"no profile configured, cannot retrieve defaults for user: '%@'", + uid]; + return defaults = nil; + } + return defaults; } +- (NSUserDefaults *) getUserDefaultsForUID: (NSString *) uid +{ + return [self _getUserDefaultsForUID: uid fieldName: @"defaults"]; +} + +- (NSUserDefaults *) getUserSettingsForUID: (NSString *) uid +{ + return [self _getUserDefaultsForUID: uid fieldName: @"settings"]; +} + /* internet access lock */ - (BOOL)isUserAllowedToChangeSOGoInternetAccess:(NSString *)_uid { @@ -1194,15 +1211,4 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; return debugOn; } -/* description */ - -- (NSString *)description { - NSMutableString *ms; - - ms = [NSMutableString stringWithCapacity:16]; - [ms appendFormat:@"<0x%08X[%@]", self, NSStringFromClass([self class])]; - [ms appendString:@">"]; - return ms; -} - @end /* AgenorUserManager */ diff --git a/SoObjects/SOGo/SOGoFolder.h b/SoObjects/SOGo/SOGoFolder.h index 53a75ce9..b3af1fc3 100644 --- a/SoObjects/SOGo/SOGoFolder.h +++ b/SoObjects/SOGo/SOGoFolder.h @@ -44,25 +44,25 @@ GCSFolder *ocsFolder; } -+ (NSString *)globallyUniqueObjectId; ++ (NSString *) globallyUniqueObjectId; /* accessors */ -- (void)setOCSPath:(NSString *)_Path; -- (NSString *)ocsPath; +- (void) setOCSPath: (NSString *)_Path; +- (NSString *) ocsPath; -- (GCSFolder *)ocsFolderForPath:(NSString *)_path; -- (GCSFolder *)ocsFolder; +- (GCSFolder *) ocsFolderForPath: (NSString *)_path; +- (GCSFolder *) ocsFolder; /* lower level fetches */ - (BOOL) nameExistsInFolder: (NSString *) objectName; -- (NSArray *)fetchContentObjectNames; -- (NSDictionary *)fetchContentStringsAndNamesOfAllObjects; +- (NSArray *) fetchContentObjectNames; +- (NSDictionary *) fetchContentStringsAndNamesOfAllObjects; /* folder type */ -- (NSString *)outlookFolderClass; +- (NSString *) outlookFolderClass; - (BOOL) create; - (NSException *) delete; diff --git a/SoObjects/SOGo/SOGoObject.h b/SoObjects/SOGo/SOGoObject.h index 892afff9..e06864b2 100644 --- a/SoObjects/SOGo/SOGoObject.h +++ b/SoObjects/SOGo/SOGoObject.h @@ -52,12 +52,12 @@ + (id) objectWithName: (NSString *)_name inContainer:(id)_container; -- (id)initWithName:(NSString *)_name inContainer:(id)_container; +- (id) initWithName: (NSString *) _name inContainer:(id)_container; /* accessors */ -- (NSString *)nameInContainer; -- (id)container; +- (NSString *) nameInContainer; +- (id) container; - (NSTimeZone *) serverTimeZone; - (NSTimeZone *) userTimeZone; @@ -66,18 +66,18 @@ /* ownership */ - (void) setOwner: (NSString *) newOwner; -- (NSString *)ownerInContext:(id)_ctx; +- (NSString *) ownerInContext: (id) _ctx; /* looking up shared objects */ -- (SOGoUserFolder *)lookupUserFolder; -- (SOGoGroupsFolder *)lookupGroupsFolder; +- (SOGoUserFolder *) lookupUserFolder; +- (SOGoGroupsFolder *) lookupGroupsFolder; -- (void)sleep; +- (void) sleep; /* hierarchy */ -- (NSArray *)fetchSubfolders; /* uses toManyRelationshipKeys */ +- (NSArray *) fetchSubfolders; /* uses toManyRelationshipKeys */ /* operations */ diff --git a/SoObjects/SOGo/SOGoUser.h b/SoObjects/SOGo/SOGoUser.h index 164af564..62dc2ed9 100644 --- a/SoObjects/SOGo/SOGoUser.h +++ b/SoObjects/SOGo/SOGoUser.h @@ -42,6 +42,7 @@ NSString *cn; NSString *email; NSUserDefaults *userDefaults; + NSUserDefaults *userSettings; } /* properties */ @@ -60,7 +61,8 @@ /* defaults */ -- (NSUserDefaults *)userDefaults; +- (NSUserDefaults *) userDefaults; +- (NSUserDefaults *) userSettings; /* folders */ diff --git a/SoObjects/SOGo/SOGoUser.m b/SoObjects/SOGo/SOGoUser.m index d3bb2eaa..6d863d53 100644 --- a/SoObjects/SOGo/SOGoUser.m +++ b/SoObjects/SOGo/SOGoUser.m @@ -37,8 +37,20 @@ @implementation SOGoUser +- (id) init +{ + if ((self = [super init])) + { + userDefaults = nil; + userSettings = nil; + } + + return self; +} + - (void)dealloc { [self->userDefaults release]; + [self->userSettings release]; [self->cn release]; [self->email release]; [super dealloc]; @@ -90,12 +102,26 @@ /* defaults */ -- (NSUserDefaults *)userDefaults { - if (self->userDefaults == nil) { - self->userDefaults = - [[[self userManager] getUserDefaultsForUID:[self login]] retain]; - } - return self->userDefaults; +- (NSUserDefaults *) userDefaults +{ + if (!userDefaults) + { + userDefaults = [[self userManager] getUserDefaultsForUID: [self login]]; + [userDefaults retain]; + } + + return userDefaults; +} + +- (NSUserDefaults *) userSettings +{ + if (!userSettings) + { + userSettings = [[self userManager] getUserSettingsForUID: [self login]]; + [userSettings retain]; + } + + return userSettings; } /* folders */ diff --git a/UI/Common/GNUmakefile b/UI/Common/GNUmakefile index add62ea9..d80d6bf0 100644 --- a/UI/Common/GNUmakefile +++ b/UI/Common/GNUmakefile @@ -14,9 +14,9 @@ CommonUI_OBJC_FILES += \ UIxPrintPageFrame.m \ UIxSortButton.m \ UIxAppNavView.m \ - UIxJSClose.m \ \ UIxAclEditor.m \ + UIxFolderActions.m \ UIxElemBuilder.m \ UIxTabView.m \ UIxTabItem.m \ diff --git a/UI/Common/UIxAclEditor.h b/UI/Common/UIxAclEditor.h index e1dbaa50..d4b047af 100644 --- a/UI/Common/UIxAclEditor.h +++ b/UI/Common/UIxAclEditor.h @@ -33,14 +33,21 @@ NSMutableArray *users; NSMutableArray *assistants; NSMutableArray *delegates; - NSString *ownerCN; + NSString *currentUser; + NSString *ownerLogin; } - (NSArray *) aclsForFolder; -- (NSString *) ownerCN; - (NSString *) assistantsValue; - (NSString *) delegatesValue; +- (NSArray *) usersForFolder; +- (void) setCurrentUser: (NSString *) newCurrentUser; +- (NSString *) currentUser; + +- (NSString *) ownerLogin; +- (NSString *) ownerName; + @end #endif /* UIXACLEDITOR_H */ diff --git a/UI/Common/UIxAclEditor.m b/UI/Common/UIxAclEditor.m index b6917d56..79d97b28 100644 --- a/UI/Common/UIxAclEditor.m +++ b/UI/Common/UIxAclEditor.m @@ -44,7 +44,8 @@ users = [NSMutableArray new]; delegates = [NSMutableArray new]; assistants = [NSMutableArray new]; - ownerCN = nil; + ownerLogin = nil; + currentUser = nil; } return self; @@ -55,8 +56,8 @@ [users release]; [delegates release]; [assistants release]; - if (ownerCN) - [ownerCN release]; + [ownerLogin release]; + [currentUser release]; [super dealloc]; } @@ -73,15 +74,31 @@ return acls; } -- (NSString *) ownerCN +- (NSString *) ownerLogin { - if (!ownerCN) + if (!ownerLogin) { - ownerCN = [[self clientObject] ownerInContext: context]; - [ownerCN retain]; + ownerLogin = [[self clientObject] ownerInContext: context]; + [ownerLogin retain]; } - return ownerCN; + return ownerLogin; +} + +- (NSString *) _displayNameForUID: (NSString *) uid +{ + AgenorUserManager *um; + + um = [AgenorUserManager sharedUserManager]; + + return [NSString stringWithFormat: @"%@ <%@>", + [um getCNForUID: uid], + [um getEmailForUID: uid]]; +} + +- (NSString *) ownerName +{ + return [self _displayNameForUID: [self ownerLogin]]; } - (void) _prepareUsers @@ -89,7 +106,6 @@ NSEnumerator *aclsEnum; AgenorUserManager *um; NSDictionary *currentAcl; - iCalPerson *currentUser; NSString *currentUID; aclsEnum = [[self aclsForFolder] objectEnumerator]; @@ -102,15 +118,15 @@ publishInFreeBusy = YES; else { - currentUser = [um iCalPersonWithUid: currentUID]; - if (![[currentUser cn] isEqualToString: [self ownerCN]]) + if (![[um getCNForUID: currentUID] + isEqualToString: [self ownerLogin]]) { if ([[currentAcl objectForKey: @"c_role"] isEqualToString: SOGoRole_Delegate]) - [delegates addObject: [currentUser cn]]; + [delegates addObject: currentUID]; else - [assistants addObject: [currentUser cn]]; - [users addObject: currentUser]; + [assistants addObject: currentUID]; + [users addObject: currentUID]; } } currentAcl = [aclsEnum nextObject]; @@ -127,6 +143,21 @@ return users; } +- (void) setCurrentUser: (NSString *) newCurrentUser +{ + ASSIGN (currentUser, newCurrentUser); +} + +- (NSString *) currentUser +{ + return currentUser; +} + +- (NSString *) currentUserDisplayName +{ + return [self _displayNameForUID: currentUser]; +} + - (NSArray *) delegates { if (!prepared) @@ -161,7 +192,11 @@ - (NSString *) toolbar { - return (([[self ownerCN] isEqualToString: [[context activeUser] login]]) + NSString *currentLogin; + + currentLogin = [[context activeUser] login]; + + return (([[self ownerLogin] isEqualToString: currentLogin]) ? @"SOGoAclOwner.toolbar" : @"SOGoAclAssistant.toolbar"); } diff --git a/UI/Common/UIxFolderActions.h b/UI/Common/UIxFolderActions.h new file mode 100644 index 00000000..5a08a684 --- /dev/null +++ b/UI/Common/UIxFolderActions.h @@ -0,0 +1,54 @@ +/* UIxFolderActions.h - this file is part of SOGo + * + * Copyright (C) 2007 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef UIXFOLDERACTIONS_H +#define UIXFOLDERACTIONS_H + +#import + +@class SOGoFolder; +@class NSString; +@class NSUserDefaults; +@class NSMutableString; +@class NSMutableDictionary; + +@interface UIxFolderActions : WODirectAction +{ + SOGoFolder *clientObject; + AgenorUserManager *um; + NSUserDefaults *ud; + NSString *owner; + NSString *login; + NSString *baseFolder; + NSMutableString *subscriptionPointer; + NSMutableDictionary *moduleSettings; +} + +- (WOResponse *) subscribeAction; +- (WOResponse *) unsubscribeAction; +- (WOResponse *) canAccessContentAction; +- (WOResponse *) activateFolderAction; +- (WOResponse *) deactivateFolderAction; + +@end + +#endif /* UIXFOLDERACTIONS_H */ diff --git a/UI/Common/UIxFolderActions.m b/UI/Common/UIxFolderActions.m new file mode 100644 index 00000000..473aaaef --- /dev/null +++ b/UI/Common/UIxFolderActions.m @@ -0,0 +1,203 @@ +/* UIxFolderActions.m - this file is part of SOGo + * + * Copyright (C) 2007 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import +#import +#import + +#import +#import +#import +#import + +#import +#import +#import +#import + +#import "UIxFolderActions.h" + +@implementation UIxFolderActions + +#warning some of this code could probably be moved in one of the \ + clientObject classes... + +- (void) _setupContext +{ + NSString *clientClass; + + login = [[context activeUser] login]; + clientObject = [self clientObject]; + owner = [clientObject ownerInContext: nil]; + + clientClass = NSStringFromClass([clientObject class]); + if ([clientClass isEqualToString: @"SOGoContactGCSFolder"]) + baseFolder = @"Contacts"; + else if ([clientClass isEqualToString: @"SOGoAppointmentFolder"]) + baseFolder = @"Calendar"; + else + baseFolder = nil; + + um = [AgenorUserManager sharedUserManager]; + ud = [um getUserSettingsForUID: login]; + moduleSettings = [ud objectForKey: baseFolder]; + if (!moduleSettings) + { + moduleSettings = [NSMutableDictionary new]; + [moduleSettings autorelease]; + } + [ud setObject: moduleSettings forKey: baseFolder]; + + subscriptionPointer = [NSMutableString stringWithFormat: @"%@:%@", + owner, baseFolder]; + if ([baseFolder isEqualToString: @"Contacts"]) + [subscriptionPointer appendFormat: @"/%@", + [clientObject nameInContainer]]; +} + +- (WOResponse *) _realActionWithFolderName: (NSDictionary *) folderDict +{ + WOResponse *response; + NSMutableDictionary *folderSubscription; + + response = [context response]; + if ([owner isEqualToString: login]) + { + [response setStatus: 403]; + [response appendContentString: + @"You cannot (un)subscribe to a folder that you own!"]; + } + else + { + folderSubscription + = [moduleSettings objectForKey: @"SubscribedFolders"]; + if (!folderSubscription) + { + folderSubscription = [NSMutableDictionary dictionary]; + [moduleSettings setObject: folderSubscription + forKey: @"SubscribedFolders"]; + } + if (folderDict) + [folderSubscription setObject: folderDict + forKey: subscriptionPointer]; + else + [folderSubscription removeObjectForKey: subscriptionPointer]; + + [ud synchronize]; + [response setStatus: 204]; + } + + return response; +} + +- (WOResponse *) subscribeAction +{ + NSString *email; + NSMutableDictionary *folderDict; + NSString *folderName; + + [self _setupContext]; + email = [NSString stringWithFormat: @"%@ <%@>", + [um getCNForUID: owner], [um getEmailForUID: owner]]; + if ([baseFolder isEqualToString: @"Contacts"]) + folderName = [NSString stringWithFormat: @"%@ (%@)", + [clientObject nameInContainer], email]; + else + folderName = email; + + folderDict = [NSMutableDictionary new]; + [folderDict setObject: folderName forKey: @"displayName"]; + [folderDict setObject: [NSNumber numberWithBool: NO] forKey: @"active"]; + + return [self _realActionWithFolderName: folderDict]; +} + +- (WOResponse *) unsubscribeAction +{ + [self _setupContext]; + + return [self _realActionWithFolderName: nil]; +} + +- (WOResponse *) canAccessContentAction +{ + WOResponse *response; + SoSecurityManager *securityManager; + BOOL result; + + securityManager = [SoSecurityManager sharedSecurityManager]; + result = (![securityManager validatePermission: SoPerm_AccessContentsInformation + onObject: [self clientObject] + inContext: context]); + + response = [context response]; + [response setStatus: 200]; + [response setHeader: @"text/plain; charset=\"ascii\"" + forKey: @"content-type"]; + [response appendContentString: (result) ? @"1" : @"0"]; + + return response; +} + +- (WOResponse *) _realFolderActivation: (BOOL) makeActive +{ + WOResponse *response; + NSMutableDictionary *folderSubscription, *folderDict; + NSNumber *active; + + response = [context response]; + + [self _setupContext]; + active = [NSNumber numberWithBool: makeActive]; + if ([owner isEqualToString: login]) + [moduleSettings setObject: active forKey: @"activateUserFolder"]; + else + { + folderSubscription + = [moduleSettings objectForKey: @"SubscribedFolders"]; + if (folderSubscription) + { + folderDict = [folderSubscription objectForKey: subscriptionPointer]; + if (folderDict) + [folderDict setObject: active + forKey: @"active"]; + } + } + + [ud synchronize]; + [response setStatus: 204]; + + return response; +} + +- (WOResponse *) activateFolderAction +{ + return [self _realFolderActivation: YES]; +} + +- (WOResponse *) deactivateFolderAction +{ + return [self _realFolderActivation: NO]; +} + +@end diff --git a/UI/Common/product.plist b/UI/Common/product.plist index 8061b201..d0166ea5 100644 --- a/UI/Common/product.plist +++ b/UI/Common/product.plist @@ -1,47 +1,72 @@ { /* -*-javascript-*- */ - requires = ( MAIN, Mailer ); + requires = ( MAIN, Mailer ); - publicResources = ( - calendar.css, - uix.css, - menu_logo_top.gif, - line_left.gif, - line_stretch.gif, - line_right.gif, - box_topleft.gif, - box_top.gif, - box_topright.gif, - box_left.gif, - box_right.gif, - box_botleft.gif, - box_bottom.gif, - box_botright.gif, - tab_selected.gif, - tab_.gif, - corner_right.gif, - closewindow.gif, - OGoLogo.gif, - upward_sorted.gif, - downward_sorted.gif, - non_sorted.gif + publicResources = ( + calendar.css, + uix.css, + menu_logo_top.gif, + line_left.gif, + line_stretch.gif, + line_right.gif, + box_topleft.gif, + box_top.gif, + box_topright.gif, + box_left.gif, + box_right.gif, + box_botleft.gif, + box_bottom.gif, + box_botright.gif, + tab_selected.gif, + tab_.gif, + corner_right.gif, + closewindow.gif, + OGoLogo.gif, + upward_sorted.gif, + downward_sorted.gif, + non_sorted.gif ); - factories = { - }; + factories = { + }; - categories = { - SOGoFolder = { - methods = { - acls = { - protectedBy = "ReadAcls"; - pageName = "UIxAclEditor"; - }; - saveAcls = { - protectedBy = "SaveAcls"; - pageName = "UIxAclEditor"; - actionName = "saveAcls"; - }; - }; - }; - }; + categories = { + SOGoFolder = { + methods = { + subscribe = { + protectedBy = "View"; + actionClass = "UIxFolderActions"; + actionName = "subscribe"; + }; + unsubscribe = { + protectedBy = "View"; + actionClass = "UIxFolderActions"; + actionName = "unsubscribe"; + }; + canAccessContent = { + protectedBy = "View"; + actionClass = "UIxFolderActions"; + actionName = "canAccessContent"; + }; + activateFolder = { + protectedBy = "View"; + actionClass = "UIxFolderActions"; + actionName = "activateFolder"; + }; + deactivateFolder = { + protectedBy = "View"; + actionClass = "UIxFolderActions"; + actionName = "deactivateFolder"; + }; + acls = { + protectedBy = "ReadAcls"; + pageName = "UIxAclEditor"; + }; + saveAcls = { + protectedBy = "SaveAcls"; + pageName = "UIxAclEditor"; + actionName = "saveAcls"; + }; + }; + }; + }; } diff --git a/UI/Contacts/English.lproj/Localizable.strings b/UI/Contacts/English.lproj/Localizable.strings index 0067b60c..c6256673 100644 --- a/UI/Contacts/English.lproj/Localizable.strings +++ b/UI/Contacts/English.lproj/Localizable.strings @@ -86,9 +86,6 @@ "Recipient" = "Recipient"; "Carbon Copy" = "Carbon Copy"; "Blind Carbon Copy" = "Blind Carbon Copy"; -"Add Attendee..." = "Add Attendee..."; -"Add Assistant" = "Add Assistant"; -"Add Delegate" = "Add Delegate"; "New Addressbook..." = "New Addressbook..."; "Subscribe to an Addressbook..." = "Subscribe to an Addressbook..."; @@ -97,3 +94,8 @@ "Name of the Address Book" = "Name of the Address Book"; "Are you sure you want to delete the selected address book?" = "Are you sure you want to delete the selected address book?"; + +"You cannot subscribe to a folder that you own!" += "You cannot subscribe to a folder that you own!"; +"Unable to subscribe to that folder!" += "Unable to subscribe to that folder!"; diff --git a/UI/Contacts/French.lproj/Localizable.strings b/UI/Contacts/French.lproj/Localizable.strings index 45053a70..660de024 100644 --- a/UI/Contacts/French.lproj/Localizable.strings +++ b/UI/Contacts/French.lproj/Localizable.strings @@ -98,11 +98,6 @@ "Recipient" = "Destinataire"; "Carbon Copy" = "Copie carbone"; "Blind Carbon Copy" = "C. carbone cachée"; -"Add Attendee..." = "Ajouter participant..."; -"Add Calendar..." = "Ajouter agenda..."; -"Add Address Book..." = "Ajouter carnet..."; -"Add Assistant" = "Ajouter comme assistant"; -"Add Delegate" = "Ajouter comme délégué"; "New Addressbook..." = "Nouveau carnet d'adresses..."; "Subscribe to an Addressbook..." = "S'inscrire à un carnet d'adresses..."; @@ -111,3 +106,8 @@ "Name of the Address Book" = "Nom du carnet d'adresses"; "Are you sure you want to delete the selected address book?" = "Voulez-vous vraiment supprimer le carnet d'adresses sélectionné ?"; + +"You cannot subscribe to a folder that you own!" += "Vous ne pouvez pas vous inscrire à un dossier qui vous appartient!"; +"Unable to subscribe to that folder!" += "Impossible de vous inscrire à ce dossier!"; diff --git a/UI/Contacts/GNUmakefile b/UI/Contacts/GNUmakefile index 2c8b9a36..ed831d32 100644 --- a/UI/Contacts/GNUmakefile +++ b/UI/Contacts/GNUmakefile @@ -9,9 +9,7 @@ ContactsUI_PRINCIPAL_CLASS = ContactsUIProduct ContactsUI_LANGUAGES = English French ContactsUI_OBJC_FILES = \ - UIxContactsAclsSelection.m \ - UIxContactsAddressBooksSelection.m \ - UIxContactsCalendarsSelection.m \ + UIxContactsUserFolders.m \ UIxContactsMailerSelection.m \ \ ContactsUIProduct.m \ @@ -20,7 +18,6 @@ ContactsUI_OBJC_FILES = \ UIxContactEditor.m \ UIxContactsListView.m \ UIxContactsListViewContainer.m \ - UIxContactSelector.m \ UIxContactFoldersView.m \ ContactsUI_RESOURCE_FILES += \ diff --git a/UI/Contacts/UIxContactFoldersView.m b/UI/Contacts/UIxContactFoldersView.m index 88534001..45e98dd1 100644 --- a/UI/Contacts/UIxContactFoldersView.m +++ b/UI/Contacts/UIxContactFoldersView.m @@ -27,11 +27,15 @@ #import #import +#import +#import + #import #import #import #import #import +#import #import "common.h" @@ -84,32 +88,13 @@ return response; } -- (id) selectForSchedulerAction -{ - return [self _selectActionForApplication: @"scheduler-contacts"]; -} - - (id) selectForMailerAction { return [self _selectActionForApplication: @"mailer-contacts"]; } -- (id) selectForCalendarsAction -{ - return [self _selectActionForApplication: @"calendars-contacts"]; -} - -- (id) selectForAddressBooksAction -{ - return [self _selectActionForApplication: @"addressbooks-contacts"]; -} - -- (id) selectForAclsAction -{ - return [self _selectActionForApplication: @"acls-contacts"]; -} - - (NSArray *) _searchResults: (NSString *) contact + ldapFoldersOnly: (BOOL) ldapFoldersOnly { NSMutableArray *results; SOGoContactFolders *topFolder; @@ -124,10 +109,12 @@ currentFolder = [sogoContactFolders nextObject]; while (currentFolder) { - [results addObjectsFromArray: [currentFolder - lookupContactsWithFilter: contact - sortBy: @"cn" - ordering: NSOrderedAscending]]; + if (!ldapFoldersOnly + || [currentFolder isKindOfClass: [SOGoContactLDAPFolder class]]) + [results addObjectsFromArray: [currentFolder + lookupContactsWithFilter: contact + sortBy: @"cn" + ordering: NSOrderedAscending]]; currentFolder = [sogoContactFolders nextObject]; } [topFolder release]; @@ -202,33 +189,176 @@ { NSString *contact; id result; + BOOL ldapFoldersOnly; contact = [self queryParameterForKey: @"search"]; - if ([contact length]) - result = [self _responseForResults: [self _searchResults: contact]]; + ldapFoldersOnly = [[self queryParameterForKey: @"ldap-only"] boolValue]; + if ([contact length] > 0) + result + = [self _responseForResults: [self _searchResults: contact + ldapFoldersOnly: ldapFoldersOnly]]; else result = [NSException exceptionWithHTTPStatus: 400 reason: @"missing 'search' parameter"]; - + return result; } -- (id ) updateAdditionalAddressBooksAction +- (NSArray *) _gcsFoldersFromFolder: (SOGoContactFolders *) contactFolders +{ + NSMutableArray *gcsFolders; + NSEnumerator *contactSubfolders; + SOGoContactGCSFolder *currentContactFolder; + NSString *folderName, *displayName; + NSMutableDictionary *currentDictionary; + + gcsFolders = [NSMutableArray new]; + [gcsFolders autorelease]; + + contactSubfolders = [[contactFolders contactFolders] objectEnumerator]; + currentContactFolder = [contactSubfolders nextObject]; + while (currentContactFolder) + { + if ([currentContactFolder + isKindOfClass: [SOGoContactGCSFolder class]]) + { + folderName = [NSString stringWithFormat: @"/Contacts/%@", + [currentContactFolder nameInContainer]]; + currentDictionary = [NSMutableDictionary new]; + [currentDictionary autorelease]; + displayName = [[currentContactFolder ocsFolder] folderName]; + [currentDictionary setObject: displayName forKey: @"displayName"]; + [currentDictionary setObject: folderName forKey: @"name"]; + [currentDictionary setObject: @"contact" forKey: @"type"]; + [gcsFolders addObject: currentDictionary]; + } + currentContactFolder = [contactSubfolders nextObject]; + } + + return gcsFolders; +} + +- (NSArray *) _foldersForUID: (NSString *) uid + ofType: (NSString *) folderType +{ + NSObject *topFolder, *userFolder; + SOGoContactFolders *contactFolders; + NSMutableArray *folders; + NSMutableDictionary *currentDictionary; + + folders = [NSMutableArray new]; + [folders autorelease]; + + topFolder = [[[self clientObject] container] container]; + userFolder = [topFolder lookupName: uid inContext: context acquire: NO]; + + /* FIXME: should be moved in the SOGo* classes. Maybe by having a SOGoFolderManager. */ +#warning this might need adjustments whenever we permit multiple calendar folders per-user + if ([folderType length] == 0 || [folderType isEqualToString: @"calendar"]) + { + currentDictionary = [NSMutableDictionary new]; + [currentDictionary autorelease]; + [currentDictionary setObject: [self labelForKey: @"Calendar"] + forKey: @"displayName"]; + [currentDictionary setObject: @"/Calendar" forKey: @"name"]; + [currentDictionary setObject: @"calendar" forKey: @"type"]; + [folders addObject: currentDictionary]; + } + if ([folderType length] == 0 || [folderType isEqualToString: @"contact"]) + { + contactFolders = [userFolder lookupName: @"Contacts" + inContext: context acquire: NO]; + [folders + addObjectsFromArray: [self _gcsFoldersFromFolder: contactFolders]]; + } + + return folders; +} + +- (NSString *) _foldersStringForFolders: (NSEnumerator *) folders +{ + NSMutableString *foldersString; + NSDictionary *currentFolder; + + foldersString = [NSMutableString new]; + [foldersString autorelease]; + + currentFolder = [folders nextObject]; + while (currentFolder) + { + [foldersString appendFormat: @";%@:%@:%@", + [currentFolder objectForKey: @"displayName"], + [currentFolder objectForKey: @"name"], + [currentFolder objectForKey: @"type"]]; + currentFolder = [folders nextObject]; + } + + return foldersString; +} + +- (WOResponse *) _foldersResponseForResults: (NSArray *) results + withType: (NSString *) folderType { WOResponse *response; - NSUserDefaults *ud; + NSString *uid, *foldersString; + NSMutableString *responseString; + NSDictionary *result; + NSEnumerator *resultsEnum; + NSArray *folders; - ud = [[context activeUser] userDefaults]; - [ud setObject: [self queryParameterForKey: @"ids"] - forKey: @"additionaladdressbooks"]; - [ud synchronize]; response = [context response]; - [response setStatus: 200]; - [response setHeader: @"text/html; charset=\"utf-8\"" forKey: @"content-type"]; + + if ([results count]) + { + [response setStatus: 200]; + [response setHeader: @"text/plain; charset=iso-8859-1" + forKey: @"Content-Type"]; + + responseString = [NSMutableString new]; + resultsEnum = [results objectEnumerator]; + result = [resultsEnum nextObject]; + while (result) + { + uid = [result objectForKey: @"c_uid"]; + folders = [self _foldersForUID: uid ofType: folderType]; + foldersString + = [self _foldersStringForFolders: [folders objectEnumerator]]; + [responseString appendFormat: @"%@:%@%@\n", + uid, [self _emailForResult: result], foldersString]; + result = [resultsEnum nextObject]; + } + [response appendContentString: responseString]; + [responseString release]; + } + else + [response setStatus: 404]; return response; } +- (id ) foldersSearchAction +{ + NSString *contact, *folderType; + id result; + BOOL ldapOnly; + + contact = [self queryParameterForKey: @"search"]; + if ([contact length] > 0) + { + ldapOnly = [[self queryParameterForKey: @"ldap-only"] boolValue]; + folderType = [self queryParameterForKey: @"type"]; + result = [self _foldersResponseForResults: + [self _searchResults: contact + ldapFoldersOnly: ldapOnly] + withType: folderType]; + } + else + result = [NSException exceptionWithHTTPStatus: 400 + reason: @"missing 'search' parameter"]; + + return result; +} + - (SOGoContactGCSFolder *) contactFolderForUID: (NSString *) uid { SOGoFolder *upperContainer; @@ -256,40 +386,4 @@ ? contactFolder : nil); } -- (id ) checkRightsAction -{ - WOResponse *response; - NSUserDefaults *ud; - NSString *uids; - NSMutableString *rights; - NSArray *ids; - unsigned int count, max; - BOOL result; - - ud = [[context activeUser] userDefaults]; - uids = [ud objectForKey: @"additionaladdressbooks"]; - - response = [context response]; - [response setStatus: 200]; - [response setHeader: @"text/plain; charset=\"utf-8\"" - forKey: @"content-type"]; - rights = [NSMutableString string]; - if ([uids length] > 0) - { - ids = [uids componentsSeparatedByString: @","]; - max = [ids count]; - for (count = 0; count < max; count++) - { - result = ([self contactFolderForUID: [ids objectAtIndex: count]] != nil); - if (count == 0) - [rights appendFormat: @"%d", result]; - else - [rights appendFormat: @",%d", result]; - } - } - [response appendContentString: rights]; - - return response; -} - @end diff --git a/UI/Contacts/UIxContactsAclsSelection.m b/UI/Contacts/UIxContactsAclsSelection.m deleted file mode 100644 index eed1fa33..00000000 --- a/UI/Contacts/UIxContactsAclsSelection.m +++ /dev/null @@ -1,30 +0,0 @@ -/* - 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. -*/ - -#import - -@interface UIxContactsAclsSelection : UIxComponent - -@end - -@implementation UIxContactsAclsSelection - -@end /* UIxContactsAclsSelection */ diff --git a/UI/Contacts/UIxContactsAddressBooksSelection.m b/UI/Contacts/UIxContactsAddressBooksSelection.m deleted file mode 100644 index 53232a1b..00000000 --- a/UI/Contacts/UIxContactsAddressBooksSelection.m +++ /dev/null @@ -1,30 +0,0 @@ -/* - 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. -*/ - -#import - -@interface UIxContactsAddressBooksSelection : UIxComponent - -@end - -@implementation UIxContactsAddressBooksSelection - -@end /* UIxContactsAddressBooksSelection */ diff --git a/UI/Contacts/UIxContactsCalendarsSelection.m b/UI/Contacts/UIxContactsCalendarsSelection.m deleted file mode 100644 index 7dc4d729..00000000 --- a/UI/Contacts/UIxContactsCalendarsSelection.m +++ /dev/null @@ -1,30 +0,0 @@ -/* - 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. -*/ - -#import - -@interface UIxContactsCalendarsSelection : UIxComponent - -@end - -@implementation UIxContactsCalendarsSelection - -@end /* UIxContactsCalendarsSelection */ diff --git a/UI/Contacts/UIxContactsListView.m b/UI/Contacts/UIxContactsListView.m index a709758b..41f27e89 100644 --- a/UI/Contacts/UIxContactsListView.m +++ b/UI/Contacts/UIxContactsListView.m @@ -74,39 +74,13 @@ return searchText; } -- (NSString *) selectorComponentClass -{ - return selectorComponentClass; -} - -- (id) mailerContactsAction +- (id ) mailerContactsAction { selectorComponentClass = @"UIxContactsMailerSelection"; return self; } -- (id) calendarsContactsAction -{ - selectorComponentClass = @"UIxContactsCalendarsSelection"; - - return self; -} - -- (id) addressBooksContactsAction -{ - selectorComponentClass = @"UIxContactsAddressBooksSelection"; - - return self; -} - -- (id) aclsContactsAction -{ - selectorComponentClass = @"UIxContactsAclsSelection"; - - return self; -} - - (id ) deleteAction { id result; @@ -196,4 +170,23 @@ return YES; } +- (WOResponse *) canAccessContentAction +{ + WOResponse *response; + NSString *clientClass; + + clientClass = NSStringFromClass([[self clientObject] class]); + + response = [context response]; + [response setStatus: 200]; + [response setHeader: @"text/plain; charset=\"ascii\"" + forKey: @"content-type"]; + [response + appendContentString: + ([clientClass isEqualToString: @"SOGoContactLDAPFolder"]) + ? @"1" : @"0"]; + + return response; +} + @end /* UIxContactsListView */ diff --git a/UI/Contacts/UIxContactsListViewContainer.h b/UI/Contacts/UIxContactsListViewContainer.h index 7bed4f89..5be9899f 100644 --- a/UI/Contacts/UIxContactsListViewContainer.h +++ b/UI/Contacts/UIxContactsListViewContainer.h @@ -34,6 +34,7 @@ NSString *foldersPrefix; NSString *selectorComponentClass; NSString *currentAdditionalFolder; + NSDictionary *additionalFolders; id currentFolder; } @@ -43,15 +44,14 @@ - (NSArray *) contactFolders; -- (NSString *) contactFolderId; - (NSString *) currentContactFolderId; - (NSString *) currentContactFolderName; -- (NSString *) additionalAddressBooks; - (NSArray *) additionalFolders; - (void) setCurrentAdditionalFolder: (NSString *) newCurrentAdditionalFolder; - (NSString *) currentAdditionalFolder; +- (NSString *) currentAdditionalFolderName; @end diff --git a/UI/Contacts/UIxContactsListViewContainer.m b/UI/Contacts/UIxContactsListViewContainer.m index b6e218f6..34fa3a32 100644 --- a/UI/Contacts/UIxContactsListViewContainer.m +++ b/UI/Contacts/UIxContactsListViewContainer.m @@ -21,11 +21,13 @@ */ #import +#import #import #import #import +#import #import #import @@ -41,11 +43,18 @@ { foldersPrefix = nil; selectorComponentClass = nil; + additionalFolders = nil; } return self; } +- (void) dealloc +{ + [additionalFolders release]; + [super dealloc]; +} + - (void) setSelectorComponentClass: (NSString *) aComponentClass { selectorComponentClass = aComponentClass; @@ -101,13 +110,6 @@ return foldersPrefix; } -- (NSString *) contactFolderId -{ - return [NSString stringWithFormat: @"%@/%@", - [self foldersPrefix], - [[self clientObject] nameInContainer]]; -} - - (NSArray *) contactFolders { SOGoContactFolders *folderContainer; @@ -129,32 +131,23 @@ return [self labelForKey: [currentFolder displayName]]; } -- (BOOL) isFolderCurrent -{ - return [[self currentContactFolderId] isEqualToString: [self contactFolderId]]; -} - -- (NSString *) additionalAddressBooks -{ - NSUserDefaults *ud; - - ud = [[context activeUser] userDefaults]; - - return [ud objectForKey: @"additionaladdressbooks"]; -} - - (NSArray *) additionalFolders { - NSString *folders; - NSArray *folderNames; + AgenorUserManager *um; + NSUserDefaults *ud; + NSString *login; - folders = [self additionalAddressBooks]; - if ([folders length] > 0) - folderNames = [folders componentsSeparatedByString: @","]; - else - folderNames = nil; + if (!additionalFolders) + { + um = [AgenorUserManager sharedUserManager]; + login = [[context activeUser] login]; + ud = [um getUserSettingsForUID: login]; + additionalFolders + = [[ud objectForKey: @"Contacts"] objectForKey: @"SubscribedFolders"]; + [additionalFolders retain]; + } - return folderNames; + return [additionalFolders allKeys]; } - (void) setCurrentAdditionalFolder: (NSString *) newCurrentAdditionalFolder @@ -167,6 +160,12 @@ return currentAdditionalFolder; } +- (NSString *) currentAdditionalFolderName +{ + return [[additionalFolders objectForKey: currentAdditionalFolder] + objectForKey: @"displayName"]; +} + - (BOOL) hasContactSelectionButtons { return (selectorComponentClass != nil); diff --git a/UI/Scheduler/UIxCalCalendarsListView.h b/UI/Contacts/UIxContactsUserFolders.h similarity index 64% rename from UI/Scheduler/UIxCalCalendarsListView.h rename to UI/Contacts/UIxContactsUserFolders.h index e3ed293e..4b9117cc 100644 --- a/UI/Scheduler/UIxCalCalendarsListView.h +++ b/UI/Contacts/UIxContactsUserFolders.h @@ -1,6 +1,6 @@ -/* UIxCalCalendarsListView.h - this file is part of SOGo +/* UIxContactsUserFolders.h - this file is part of SOGo * - * Copyright (C) 2006 Inverse groupe conseil + * Copyright (C) 2007 Inverse groupe conseil * * Author: Wolfgang Sourdeau * @@ -20,23 +20,14 @@ * Boston, MA 02111-1307, USA. */ -#ifndef UIXCALCALENDARSLISTVIEW_H -#define UIXCALCALENDARSLISTVIEW_H +#ifndef UIXCONTACTSUSERFOLDERS_H +#define UIXCONTACTSUSERFOLDERS_H #import -@class NSMutableArray; -@class NSMutableDictionary; -@class iCalPerson; - -@interface UIxCalCalendarsListView : UIxComponent -{ - NSMutableArray *checkedContacts; - NSMutableArray *contacts; - NSMutableDictionary *colors; - iCalPerson *currentContactPerson; -} +@interface UIxContactsUserFolders : UIxComponent @end -#endif /* UIXCALCALENDARSLISTVIEW_H */ + +#endif /* UIXCONTACTSUSERFOLDERS_H */ diff --git a/UI/Contacts/UIxContactsUserFolders.m b/UI/Contacts/UIxContactsUserFolders.m new file mode 100644 index 00000000..f9418745 --- /dev/null +++ b/UI/Contacts/UIxContactsUserFolders.m @@ -0,0 +1,27 @@ +/* UIxContactsUserFolders.m - this file is part of SOGo + * + * Copyright (C) 2007 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import "UIxContactsUserFolders.h" + +@implementation UIxContactsUserFolders + +@end diff --git a/UI/Contacts/product.plist b/UI/Contacts/product.plist index 6e4d7ea8..663ab8d9 100644 --- a/UI/Contacts/product.plist +++ b/UI/Contacts/product.plist @@ -1,5 +1,5 @@ { /* -*-javascript-*- */ - requires = ( MAIN, CommonUI, Contacts ); + requires = ( MAIN, MainUI, CommonUI, Contacts ); publicResources = (); @@ -22,35 +22,20 @@ pageName = "UIxContactFoldersView"; actionName = "newAb"; }; - scheduler-contacts = { - protectedBy = "View"; - pageName = "UIxContactFoldersView"; - actionName = "selectForScheduler"; - }; mailer-contacts = { protectedBy = "View"; pageName = "UIxContactFoldersView"; actionName = "selectForMailer"; }; - calendars-contacts = { - protectedBy = "View"; - pageName = "UIxContactFoldersView"; - actionName = "selectForCalendars"; - }; - addressbooks-contacts = { - protectedBy = "View"; - pageName = "UIxContactFoldersView"; - actionName = "selectForAddressBooks"; - }; - acls-contacts = { + contactSearch = { protectedBy = "View"; pageName = "UIxContactFoldersView"; - actionName = "selectForAcls"; + actionName = "contactSearch"; }; - contactSearch = { + foldersSearch = { protectedBy = "View"; pageName = "UIxContactFoldersView"; - actionName = "contactSearch"; + actionName = "foldersSearch"; }; updateAdditionalAddressBooks = { protectedBy = "View"; @@ -64,13 +49,17 @@ saveAcls = { protectedBy = "SaveAcls"; pageName = "UIxAclEditor"; - actionName = "saveAcls"; + actionName = "saveAcls"; }; checkRights = { protectedBy = "View"; pageName = "UIxContactFoldersView"; actionName = "checkRights"; }; + userFolders = { + protectedBy = "View"; + pageName = "UIxContactsUserFolders"; + }; }; }; @@ -94,27 +83,12 @@ mailer-contacts = { protectedBy = "View"; pageName = "UIxContactsListView"; - actionName = "mailerContacts"; - }; - calendars-contacts = { - protectedBy = "View"; - pageName = "UIxContactsListView"; - actionName = "calendarsContacts"; - }; - acls-contacts = { - protectedBy = "View"; - pageName = "UIxContactsListView"; - actionName = "aclsContacts"; - }; - addressbooks-contacts = { - protectedBy = "View"; - pageName = "UIxContactsListView"; - actionName = "addressBooksContacts"; + actionName = "mailerContacts"; }; delete = { protectedBy = "View"; pageName = "UIxContactsListView"; - actionName = "delete"; + actionName = "delete"; }; }; }; @@ -136,31 +110,16 @@ pageName = "UIxContactEditor"; actionName = "new"; }; - scheduler-contacts = { - protectedBy = "View"; - pageName = "UIxContactsListView"; - actionName = "schedulerContacts"; - }; mailer-contacts = { protectedBy = "View"; pageName = "UIxContactsListView"; actionName = "mailerContacts"; }; - calendars-contacts = { - protectedBy = "View"; + canAccessContent = { + protectedBy = "View"; pageName = "UIxContactsListView"; - actionName = "calendarsContacts"; - }; - acls-contacts = { - protectedBy = "View"; - pageName = "UIxContactsListView"; - actionName = "aclsContacts"; - }; - addressbooks-contacts = { - protectedBy = "View"; - pageName = "UIxContactsListView"; - actionName = "addressBooksContacts"; - }; + actionName = "canAccessContent"; + }; }; }; diff --git a/UI/MainUI/SOGoUserHomePage.m b/UI/MainUI/SOGoUserHomePage.m index 4cd16e76..7731f9ea 100644 --- a/UI/MainUI/SOGoUserHomePage.m +++ b/UI/MainUI/SOGoUserHomePage.m @@ -20,7 +20,15 @@ * Boston, MA 02111-1307, USA. */ +#import +#import +#import #import +#import +#import + +#import +#import #import @interface SOGoUserHomePage : UIxComponent @@ -39,4 +47,116 @@ return [self redirectToLocation: url]; } +- (void) _fillFreeBusyItems: (NSMutableArray *) items + withRecords: (NSEnumerator *) records + fromStartDate: (NSCalendarDate *) startDate + toEndDate: (NSCalendarDate *) endDate +{ + NSDictionary *record; + int count, startInterval, endInterval, value; + NSNumber *status; + NSCalendarDate *currentDate; + + record = [records nextObject]; + while (record) + { + status = [record objectForKey: @"status"]; + + value = [[record objectForKey: @"startdate"] intValue]; + currentDate = [NSCalendarDate dateWithTimeIntervalSince1970: value]; + if ([currentDate earlierDate: startDate] == currentDate) + startInterval = 0; + else + startInterval + = ([currentDate timeIntervalSinceDate: startDate] / 900); + + value = [[record objectForKey: @"enddate"] intValue]; + currentDate = [NSCalendarDate dateWithTimeIntervalSince1970: value]; + if ([currentDate earlierDate: endDate] == endDate) + endInterval = [items count] - 1; + else + endInterval = ([currentDate timeIntervalSinceDate: startDate] / 900); + + for (count = startInterval; count < endInterval; count++) + [items replaceObjectAtIndex: count withObject: status]; + + record = [records nextObject]; + } +} + +- (NSString *) _freeBusyAsTextFromStartDate: (NSCalendarDate *) startDate + toEndDate: (NSCalendarDate *) endDate + forFreeBusy: (SOGoFreeBusyObject *) fb +{ + NSEnumerator *records; + NSMutableArray *freeBusyItems; + NSTimeInterval interval; + int count, intervals; + + interval = [endDate timeIntervalSinceDate: startDate] + 60; + intervals = interval / 900; /* slices of 15 minutes */ + freeBusyItems = [NSMutableArray arrayWithCapacity: intervals]; + for (count = 1; count < intervals; count++) + [freeBusyItems addObject: @"0"]; + + records = [[fb fetchFreeBusyInfosFrom: startDate to: endDate] objectEnumerator]; + [self _fillFreeBusyItems: freeBusyItems withRecords: records + fromStartDate: startDate toEndDate: endDate]; + + return [freeBusyItems componentsJoinedByString: @","]; +} + +- (NSString *) _freeBusyAsText +{ + SOGoFreeBusyObject *co; + NSCalendarDate *startDate, *endDate; + NSString *queryDay, *additionalDays; + NSTimeZone *uTZ; + + co = [self clientObject]; + uTZ = [co userTimeZone]; + + queryDay = [self queryParameterForKey: @"sday"]; + if ([queryDay length]) + startDate = [NSCalendarDate dateFromShortDateString: queryDay + andShortTimeString: @"0000" + inTimeZone: uTZ]; + else + { + startDate = [NSCalendarDate calendarDate]; + [startDate setTimeZone: uTZ]; + startDate = [startDate hour: 0 minute: 0]; + } + + queryDay = [self queryParameterForKey: @"eday"]; + if ([queryDay length]) + endDate = [NSCalendarDate dateFromShortDateString: queryDay + andShortTimeString: @"2359" + inTimeZone: uTZ]; + else + endDate = [startDate hour: 23 minute: 59]; + + additionalDays = [self queryParameterForKey: @"additional"]; + if ([additionalDays length] > 0) + endDate = [endDate dateByAddingYears: 0 months: 0 + days: [additionalDays intValue] + hours: 0 minutes: 0 seconds: 0]; + + return [self _freeBusyAsTextFromStartDate: startDate toEndDate: endDate + forFreeBusy: co]; +} + +- (id ) readFreeBusyAction +{ + WOResponse *response; + + response = [context response]; + [response setStatus: 200]; + [response setHeader: @"text/plain; charset=iso-8859-1" + forKey: @"Content-Type"]; + [response appendContentString: [self _freeBusyAsText]]; + + return response; +} + @end diff --git a/UI/MainUI/product.plist b/UI/MainUI/product.plist index 2ee0e399..6895273f 100644 --- a/UI/MainUI/product.plist +++ b/UI/MainUI/product.plist @@ -17,7 +17,7 @@ }; SOGoUserFolder = { superclass = "SOGoFolder"; - protectedBy = "HomePage Access"; + /* protectedBy = "HomePage Access"; */ defaultRoles = { "Homepage Access" = ( "Owner", "Assistant", "Delegate", "FreeBusy" ); "WebDAV Access" = ( "Owner", "Assistant", "Delegate", "FreeBusy" ); diff --git a/UI/SOGoUI/GNUmakefile b/UI/SOGoUI/GNUmakefile index d0c92e46..13ea2c5f 100644 --- a/UI/SOGoUI/GNUmakefile +++ b/UI/SOGoUI/GNUmakefile @@ -14,6 +14,7 @@ FHS_HEADER_DIRS = SOGoUI libSOGoUI_HEADER_FILES += \ \ + UIxJSClose.h \ UIxComponent.h \ SOGoDateFormatter.h \ SOGoAptFormatter.h \ @@ -22,6 +23,7 @@ libSOGoUI_HEADER_FILES += \ libSOGoUI_OBJC_FILES += \ \ + UIxJSClose.m \ UIxComponent.m \ SOGoDateFormatter.m \ SOGoAptFormatter.m \ diff --git a/UI/SOGoUI/UIxComponent.m b/UI/SOGoUI/UIxComponent.m index 52f05e55..0758c504 100644 --- a/UI/SOGoUI/UIxComponent.m +++ b/UI/SOGoUI/UIxComponent.m @@ -32,7 +32,7 @@ #import #import -#import "../Common/UIxJSClose.h" +#import "UIxJSClose.h" #import "UIxComponent.h" diff --git a/UI/Scheduler/French.lproj/Localizable.strings b/UI/Scheduler/French.lproj/Localizable.strings index adb78b5d..37002e78 100644 --- a/UI/Scheduler/French.lproj/Localizable.strings +++ b/UI/Scheduler/French.lproj/Localizable.strings @@ -362,10 +362,11 @@ validate_endbeforestart = "La date de fin est avant la date de début !"; "No free-busy information" = "Pas d'information"; /* FreeBusy panel buttons */ -"Previous slot" = "Période précédente"; -"Next slot" = "Période suivante"; +"Suggest time slot:" = "Suggérer un créneau horaire :"; +"Previous slot" = "Précédent"; +"Next slot" = "Prochain"; "Previous hour" = "Heure précédente"; -"Next hour" = "Heure suivante"; +"Next hour" = "Prochaine heure"; "closeThisWindowMessage" = "Merci! Vous pouvez maintenant fermer cette fenêtre."; "Multicolumn Day View" = "Multicolonne"; diff --git a/UI/Scheduler/GNUmakefile b/UI/Scheduler/GNUmakefile index b90b510e..d3594c4b 100644 --- a/UI/Scheduler/GNUmakefile +++ b/UI/Scheduler/GNUmakefile @@ -20,7 +20,6 @@ SchedulerUI_OBJC_FILES = \ \ UIxComponent+Agenor.m \ UIxCalView.m \ - UIxCalCalendarsListView.m \ UIxCalAptListView.m \ UIxCalTasksListView.m \ UIxCalDayView.m \ @@ -32,6 +31,7 @@ SchedulerUI_OBJC_FILES = \ \ UIxAttendeesEditor.m \ UIxComponentEditor.m \ + UIxCalendarSelector.m \ UIxAppointmentView.m \ UIxAppointmentEditor.m \ UIxAppointmentProposal.m \ @@ -40,12 +40,10 @@ SchedulerUI_OBJC_FILES = \ UIxTaskProposal.m \ UIxCalSelectTab.m \ UIxCalDateLabel.m \ - UIxCalBackForthNavView.m \ UIxDatePicker.m \ UIxTimeDateControl.m \ UIxCalInlineAptView.m \ UIxCalInlineMonthAptView.m \ - UIxCalScheduleOverview.m \ UIxCalParticipationStatusView.m \ UIxCalMonthOverview.m diff --git a/UI/Scheduler/UIxCalBackForthNavView.m b/UI/Scheduler/UIxCalBackForthNavView.m deleted file mode 100644 index d8e76b36..00000000 --- a/UI/Scheduler/UIxCalBackForthNavView.m +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright (C) 2004 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. -*/ -// $Id$ - - -#include - -/* - Associations: - - methodName -> maps to href - prevQueryParameters -> queryDictionary - currentQueryParameters -> queryDictionary - nextQueryParameters -> queryDictionary - label -> user presentable name to display for "this" - */ - -@interface UIxCalBackForthNavView : WOComponent -{ -} - -@end - - -@implementation UIxCalBackForthNavView - -- (BOOL)synchronizesVariablesWithBindings { - return NO; -} - -@end diff --git a/UI/Scheduler/UIxCalCalendarsListView.m b/UI/Scheduler/UIxCalCalendarsListView.m deleted file mode 100644 index b25de820..00000000 --- a/UI/Scheduler/UIxCalCalendarsListView.m +++ /dev/null @@ -1,215 +0,0 @@ -/* UIxCalCalendarsListView.m - this file is part of SOGo - * - * Copyright (C) 2006 Inverse groupe conseil - * - * Author: Wolfgang Sourdeau - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This file 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#import -#import -#import -#import - -#import -#import - -#import "UIxCalCalendarsListView.h" - -static inline char -darkenedColor (const char value) -{ - char newValue; - - if (value >= '0' && value <= '9') - newValue = ((value - '0') / 2) + '0'; - else if (value >= 'a' && value <= 'f') - newValue = ((value + 10 - 'a') / 2) + '0'; - else if (value >= 'A' && value <= 'F') - newValue = ((value + 10 - 'A') / 2) + '0'; - else - newValue = value; - - return newValue; -} - -@implementation UIxCalCalendarsListView - -- (id) init -{ - if ((self = [super init])) - { - contacts = nil; - checkedContacts = nil; - currentContactPerson = nil; - colors = nil; - } - - return self; -} - -- (void) dealloc -{ - if (currentContactPerson) - [currentContactPerson release]; - if (contacts) - [contacts release]; - if (checkedContacts) - [checkedContacts release]; - if (colors) - [colors release]; - [super dealloc]; -} - -- (NSString *) _colorForNumber: (unsigned int) number -{ - unsigned int index, currentValue; - unsigned char colorTable[] = { 1, 1, 1 }; - NSString *color; - - if (number == 0) - color = @"#ccf"; - else if (number == NSNotFound) - color = @"#f00"; - else - { - currentValue = number; - index = 0; - while (currentValue) - { - if (currentValue & 1) - colorTable[index]++; - if (index == 3) - index = 0; - currentValue >>= 1; - index++; - } - color = [NSString stringWithFormat: @"#%2x%2x%2x", - (255 / colorTable[2]) - 1, - (255 / colorTable[1]) - 1, - (255 / colorTable[0]) - 1]; - } - - return color; -} - -- (void) _addContactId: (NSString *) contactId - withUm: (AgenorUserManager *) um - andNumber: (unsigned int) count -{ - NSString *contactRealId; - iCalPerson *currentContact; - - if ([contactId hasPrefix: @"-"]) - contactRealId = [contactId substringFromIndex: 1]; - else - contactRealId = contactId; - - currentContact = [um iCalPersonWithUid: contactRealId]; - [contacts addObject: currentContact]; - if (contactId == contactRealId) - [checkedContacts addObject: currentContact]; - [colors setObject: [self _colorForNumber: count] - forKey: contactRealId]; -} - -- (void) _setupContacts -{ - SOGoUser *user; - NSString *list, *currentId; - NSEnumerator *rawContacts; - AgenorUserManager *um; - unsigned int count; - - contacts = [NSMutableArray new]; - checkedContacts = [NSMutableArray new]; - colors = [NSMutableDictionary new]; - - um = [AgenorUserManager sharedUserManager]; - user = [context activeUser]; - list = [[user userDefaults] stringForKey: @"calendaruids"]; - if ([list length] == 0) - list = [self shortUserNameForDisplay]; - - rawContacts - = [[list componentsSeparatedByString: @","] objectEnumerator]; - currentId = [rawContacts nextObject]; - count = 0; - while (currentId) - { - [self _addContactId: currentId withUm: um andNumber: count]; - currentId = [rawContacts nextObject]; - count++; - } -} - -- (NSArray *) contacts -{ - if (!contacts) - [self _setupContacts]; - - return contacts; -} - -- (NSArray *) checkedContacts -{ - if (!checkedContacts) - [self _setupContacts]; - - return checkedContacts; -} - -- (void) setCurrentContactPerson: (iCalPerson *) contact -{ - if (currentContactPerson) - [currentContactPerson release]; - currentContactPerson = contact; - if (currentContactPerson) - [currentContactPerson retain]; -} - -- (NSString *) currentContactLogin -{ - return [currentContactPerson cn]; -} - -- (NSString *) currentContactSpanBG -{ - return [colors objectForKey: [currentContactPerson cn]]; -} - -- (NSString *) currentContactAptBorder -{ - NSString *spanBG; - char cColor[8]; - unsigned int count; - - spanBG = [colors objectForKey: [currentContactPerson cn]]; - [spanBG getCString: cColor]; - cColor[7] = 0; - for (count = 1; count < 7; count++) - cColor[count] = darkenedColor(cColor[count]); - - return [NSString stringWithCString: cColor]; -} - -- (NSDictionary *) colors -{ - return colors; -} - -@end diff --git a/UI/Scheduler/UIxCalDayTable.m b/UI/Scheduler/UIxCalDayTable.m index 409bbdcf..0cb213e2 100644 --- a/UI/Scheduler/UIxCalDayTable.m +++ b/UI/Scheduler/UIxCalDayTable.m @@ -201,7 +201,7 @@ - (NSString *) labelForDay { - return [NSString stringWithFormat: @"%@ %@", + return [NSString stringWithFormat: @"%@
%@", [dateFormatter shortDayOfWeek: [currentTableDay dayOfWeek]], [dateFormatter stringForObjectValue: currentTableDay]]; } diff --git a/UI/Scheduler/UIxCalDayView.h b/UI/Scheduler/UIxCalDayView.h index ae74b19e..ee4fbeda 100644 --- a/UI/Scheduler/UIxCalDayView.h +++ b/UI/Scheduler/UIxCalDayView.h @@ -25,24 +25,23 @@ #define __UIxCalDayView_H_ -#include "UIxCalView.h" +#import "UIxCalView.h" @interface UIxCalDayView : UIxCalView -{ - NSCalendarDate *currentDate; -} -- (void)setCurrentDate:(NSCalendarDate *)_date; -- (NSCalendarDate *)currentDate; -- (BOOL)isCurrentDateInApt; - -- (NSDictionary *)currentDateQueryParameters; +- (NSDictionary *) dayBeforePrevDayQueryParameters; +- (NSDictionary *) prevDayQueryParameters; +- (NSDictionary *) nextDayQueryParameters; +- (NSDictionary *) dayAfterNextDayQueryParameters; +- (NSDictionary *) currentDateQueryParameters; -- (NSArray *)dateRange; +- (NSCalendarDate *) startDate; -/* appointments */ -- (NSArray *)aptsForCurrentDate; -- (BOOL)hasAptsForCurrentDate; +- (NSString *) dayBeforeYesterdayName; +- (NSString *) yesterdayName; +- (NSString *) currentDayName; +- (NSString *) tomorrowName; +- (NSString *) dayAfterTomorrowName; @end diff --git a/UI/Scheduler/UIxCalDayView.m b/UI/Scheduler/UIxCalDayView.m index ddd0729c..fcca9b5e 100644 --- a/UI/Scheduler/UIxCalDayView.m +++ b/UI/Scheduler/UIxCalDayView.m @@ -36,97 +36,97 @@ #import "UIxCalDayView.h" -@interface UIxCalDayView (PrivateAPI) -- (BOOL)isCurrentDateInApt:(id)_apt; -- (NSArray *)_getDatesFrom:(NSCalendarDate *)_from to:(NSCalendarDate *)_to; -@end +// @interface UIxCalDayView (PrivateAPI) +// - (BOOL)isCurrentDateInApt:(id)_apt; +// - (NSArray *)_getDatesFrom:(NSCalendarDate *)_from to:(NSCalendarDate *)_to; +// @end @implementation UIxCalDayView -- (void) dealloc -{ - [self->currentDate release]; - [super dealloc]; -} - -- (void) setCurrentDate: (NSCalendarDate *) _date -{ - ASSIGN(self->currentDate, _date); -} - -- (NSCalendarDate *) currentDate -{ - return self->currentDate; -} - -- (BOOL) isCurrentDateInApt -{ - return [self isCurrentDateInApt: [self appointment]]; -} - -- (BOOL) isCurrentDateInApt: (id) _apt -{ - NSCalendarDate *dateStart, *dateEnd, *aptStart, *aptEnd; - NGCalendarDateRange *dateRange, *aptRange; +// - (void) dealloc +// { +// [self->currentDate release]; +// [super dealloc]; +// } + +// - (void) setCurrentDate: (NSCalendarDate *) _date +// { +// ASSIGN(self->currentDate, _date); +// } + +// - (NSCalendarDate *) currentDate +// { +// return self->currentDate; +// } + +// - (BOOL) isCurrentDateInApt +// { +// return [self isCurrentDateInApt: [self appointment]]; +// } + +// - (BOOL) isCurrentDateInApt: (id) _apt +// { +// NSCalendarDate *dateStart, *dateEnd, *aptStart, *aptEnd; +// NGCalendarDateRange *dateRange, *aptRange; - dateStart = self->currentDate; - dateEnd = [dateStart dateByAddingYears:0 months:0 days:0 - hours:1 minutes:0 seconds:0]; - dateRange = [NGCalendarDateRange calendarDateRangeWithStartDate:dateStart - endDate:dateEnd]; - aptStart = [self->appointment valueForKey:@"startDate"]; - aptEnd = [self->appointment valueForKey:@"endDate"]; - aptRange = [NGCalendarDateRange calendarDateRangeWithStartDate:aptStart - endDate:aptEnd]; - - return [dateRange doesIntersectWithDateRange:aptRange]; -} - -- (NSArray *) dateRange -{ - /* default range is from dayStartHour to dayEndHour. Any values before - or after are also fine */ - - NSCalendarDate *min, *max; - NSArray *aptDateRanges; - - min = [[self startDate] hour:[self dayStartHour] minute:0]; - max = [[self startDate] hour:[self dayEndHour] minute:0]; - - aptDateRanges = [[self appointments] valueForKey: @"startDate"]; - if([aptDateRanges count] != 0) { - NSCalendarDate *d; - - aptDateRanges - = [aptDateRanges sortedArrayUsingSelector: @selector(compareAscending:)]; - d = [aptDateRanges objectAtIndex:0]; - if ([d isDateOnSameDay:min]) - min = (NSCalendarDate *)[d earlierDate:min]; - d = [aptDateRanges objectAtIndex:[aptDateRanges count] - 1]; - if ([d isDateOnSameDay:max]) - max = (NSCalendarDate *)[d laterDate:max]; - } +// dateStart = self->currentDate; +// dateEnd = [dateStart dateByAddingYears:0 months:0 days:0 +// hours:1 minutes:0 seconds:0]; +// dateRange = [NGCalendarDateRange calendarDateRangeWithStartDate:dateStart +// endDate:dateEnd]; +// aptStart = [self->appointment valueForKey:@"startDate"]; +// aptEnd = [self->appointment valueForKey:@"endDate"]; +// aptRange = [NGCalendarDateRange calendarDateRangeWithStartDate:aptStart +// endDate:aptEnd]; + +// return [dateRange doesIntersectWithDateRange:aptRange]; +// } + +// - (NSArray *) dateRange +// { +// /* default range is from dayStartHour to dayEndHour. Any values before +// or after are also fine */ + +// NSCalendarDate *min, *max; +// NSArray *aptDateRanges; + +// min = [[self startDate] hour:[self dayStartHour] minute:0]; +// max = [[self startDate] hour:[self dayEndHour] minute:0]; + +// aptDateRanges = [[self appointments] valueForKey: @"startDate"]; +// if([aptDateRanges count] != 0) { +// NSCalendarDate *d; + +// aptDateRanges +// = [aptDateRanges sortedArrayUsingSelector: @selector(compareAscending:)]; +// d = [aptDateRanges objectAtIndex:0]; +// if ([d isDateOnSameDay:min]) +// min = (NSCalendarDate *)[d earlierDate:min]; +// d = [aptDateRanges objectAtIndex:[aptDateRanges count] - 1]; +// if ([d isDateOnSameDay:max]) +// max = (NSCalendarDate *)[d laterDate:max]; +// } - return [self _getDatesFrom:min to:max]; -} - -- (NSArray *) _getDatesFrom: (NSCalendarDate *) _from - to: (NSCalendarDate *) _to -{ - NSMutableArray *dates; - unsigned i, count, offset; - - offset = [_from hourOfDay]; - count = ([_to hourOfDay] + 1) - offset; - dates = [[NSMutableArray alloc] initWithCapacity:count]; - for(i = 0; i < count; i++) { - NSCalendarDate *date; +// return [self _getDatesFrom:min to:max]; +// } + +// - (NSArray *) _getDatesFrom: (NSCalendarDate *) _from +// to: (NSCalendarDate *) _to +// { +// NSMutableArray *dates; +// unsigned i, count, offset; + +// offset = [_from hourOfDay]; +// count = ([_to hourOfDay] + 1) - offset; +// dates = [[NSMutableArray alloc] initWithCapacity:count]; +// for(i = 0; i < count; i++) { +// NSCalendarDate *date; - date = [_from hour:offset + i minute:0]; - [dates addObject:date]; - } - return [dates autorelease]; -} +// date = [_from hour:offset + i minute:0]; +// [dates addObject:date]; +// } +// return [dates autorelease]; +// } /* URLs */ @@ -156,12 +156,12 @@ NSString *hmString; NSCalendarDate *date; - date = [self currentDate]; + date = [self selectedDate]; hmString = [NSString stringWithFormat:@"%.2d%.2d", [date hourOfDay], [date minuteOfHour]]; qp = [[self queryParameters] mutableCopy]; [self setSelectedDateQueryParameter:date inDictionary:qp]; - [qp setObject:hmString forKey:@"hm"]; + [qp setObject: hmString forKey:@"hm"]; return [qp autorelease]; } @@ -172,92 +172,49 @@ return [[self selectedDate] beginOfDay]; } -- (NSCalendarDate *) endDate -{ - return [[self selectedDate] endOfDay]; -} - /* appointments */ -- (NSArray *) appointments -{ - return [self fetchCoreAppointmentsInfos]; -} - -- (NSArray *)aptsForCurrentDate { - NSArray *apts; - NSMutableArray *filtered; - unsigned i, count; - NSCalendarDate *start, *end; - - start = self->currentDate; - end = [start dateByAddingYears:0 - months:0 - days:0 - hours:0 - minutes:59 - seconds:59]; +// - (NSArray *)allDayApts { +// NSCalendarDate *start; +// NSArray *apts; +// NSMutableArray *filtered; +// unsigned i, count; - apts = [self appointments]; - filtered = [[NSMutableArray alloc] initWithCapacity:1]; - count = [apts count]; - for (i = 0; i < count; i++) { - id apt; - NSCalendarDate *aptStartDate; +// if (self->allDayApts) +// return self->allDayApts; + +// start = [self startDate]; +// apts = [self appointments]; +// filtered = [[NSMutableArray alloc] initWithCapacity:1]; +// count = [apts count]; +// for (i = 0; i < count; i++) { +// id apt; +// NSNumber *bv; - apt = [apts objectAtIndex:i]; - aptStartDate = [apt valueForKey:@"startDate"]; - if([aptStartDate isGreaterThanOrEqualTo:start] && - [aptStartDate isLessThan:end]) - { - [filtered addObject:apt]; - } - } +// apt = [apts objectAtIndex:i]; +// bv = [apt valueForKey:@"isallday"]; +// if ([bv boolValue]) { +// [filtered addObject:apt]; +// } +// else { +// NSCalendarDate *aptStartDate; + +// aptStartDate = [apt valueForKey:@"startDate"]; +// if([aptStartDate isLessThan:start]) { +// [filtered addObject:apt]; +// } +// } +// } - return [filtered autorelease]; -} - -- (NSArray *)allDayApts { - NSCalendarDate *start; - NSArray *apts; - NSMutableArray *filtered; - unsigned i, count; - - if (self->allDayApts) - return self->allDayApts; - - start = [self startDate]; - apts = [self appointments]; - filtered = [[NSMutableArray alloc] initWithCapacity:1]; - count = [apts count]; - for (i = 0; i < count; i++) { - id apt; - NSNumber *bv; - - apt = [apts objectAtIndex:i]; - bv = [apt valueForKey:@"isallday"]; - if ([bv boolValue]) { - [filtered addObject:apt]; - } - else { - NSCalendarDate *aptStartDate; - - aptStartDate = [apt valueForKey:@"startDate"]; - if([aptStartDate isLessThan:start]) { - [filtered addObject:apt]; - } - } - } - - ASSIGN(self->allDayApts, filtered); - [filtered release]; - return self->allDayApts; -} - -- (BOOL) hasAptsForCurrentDate -{ - return [[self aptsForCurrentDate] count] != 0; -} +// ASSIGN(self->allDayApts, filtered); +// [filtered release]; +// return self->allDayApts; +// } + +// - (BOOL) hasAptsForCurrentDate +// { +// return [[self aptsForCurrentDate] count] != 0; +// } - (NSString *) _dayNameWithOffsetFromToday: (int) offset { diff --git a/UI/Scheduler/UIxCalMainView.m b/UI/Scheduler/UIxCalMainView.m index fc2bcad5..80b66f66 100644 --- a/UI/Scheduler/UIxCalMainView.m +++ b/UI/Scheduler/UIxCalMainView.m @@ -114,78 +114,4 @@ static NSMutableArray *yearMenuItems = nil; return self; } -- (id ) updateCalendarsAction -{ - WOResponse *response; - NSUserDefaults *ud; - - ud = [[context activeUser] userDefaults]; - [ud setObject: [self queryParameterForKey: @"ids"] - forKey: @"calendaruids"]; - [ud synchronize]; - response = [context response]; - [response setStatus: 200]; - [response setHeader: @"text/html; charset=\"utf-8\"" forKey: @"content-type"]; - - return response; -} - -- (NSString *) _rightsForUIDs: (NSString *) uids -{ - NSEnumerator *ids; - NSString *uid; - NSMutableString *rights; - SOGoAppointmentFolder *refFolder, *currentFolder; - SoSecurityManager *securityManager; - BOOL result; - - securityManager = [SoSecurityManager sharedSecurityManager]; - refFolder = [self clientObject]; - - rights = [NSMutableString string]; - if ([uids length] > 0) - { - ids = [[uids componentsSeparatedByString: @","] objectEnumerator]; - uid = [ids nextObject]; - while (uid) - { - currentFolder - = [refFolder - lookupCalendarFolderForUID: (([uid hasPrefix: @"-"]) - ? [uid substringFromIndex: 1] - : uid)]; - result = (![securityManager validatePermission: SoPerm_AccessContentsInformation - onObject: currentFolder - inContext: context]); - if ([rights length] == 0) - [rights appendFormat: @"%d", result]; - else - [rights appendFormat: @",%d", result]; - uid = [ids nextObject]; - } - } - - return rights; -} - -- (id ) checkRightsAction -{ - WOResponse *response; - NSUserDefaults *ud; - NSString *uids, *rights; - - ud = [[context activeUser] userDefaults]; - uids = [ud stringForKey: @"calendaruids"]; - - response = [context response]; - [response setStatus: 200]; - [response setHeader: @"text/plain; charset=\"utf-8\"" - forKey: @"content-type"]; - - rights = [self _rightsForUIDs: uids]; - [response appendContentString: rights]; - - return response; -} - @end diff --git a/UI/Scheduler/UIxCalScheduleOverview.m b/UI/Scheduler/UIxCalScheduleOverview.m deleted file mode 100644 index 5fe7a0f3..00000000 --- a/UI/Scheduler/UIxCalScheduleOverview.m +++ /dev/null @@ -1,392 +0,0 @@ -/* - Copyright (C) 2004 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 - -@class NSMutableArray; - -@interface UIxCalScheduleOverview : UIxComponent -{ - NSMutableArray *userApts; - NSMutableArray *foreignApts; - id item; - NSMutableArray *partNames; - NSMutableArray *partStates; - NSString *userParticipationStatus; - unsigned participantIndex; - unsigned userIndex; -} - -- (NSCalendarDate *)startDate; -- (NSCalendarDate *)endDate; - -- (NSArray *)userAppointments; -- (NSArray *)foreignAppointments; - -- (BOOL)hasUserAppointments; -- (BOOL)hasForeignAppointments; -- (BOOL)hasAnyAppointments; - -- (void)fetchInfos; - -- (NSString *)appointmentBaseURL; - -- (unsigned)participantsCount; -- (unsigned)maxRenderedParticipantsCount; -- (unsigned)renderedParticipantsCount; -- (unsigned)truncatedParticipantsCount; -- (BOOL)didTruncateParticipants; - -- (NSString *)getUserPartStateFromApt:(id)_apt; - -- (BOOL)shouldIgnoreRejectedAppointments; -- (BOOL)shouldIgnoreAcceptedAppointments; -- (BOOL)shouldShowRejectedAndAcceptedAppointments; - -@end - -#include -#include "UIxComponent+Agenor.h" -#include "SoObjects/Appointments/SOGoAppointmentFolder.h" -#include "common.h" - -@implementation UIxCalScheduleOverview - -- (void)dealloc { - [self->userApts release]; - [self->foreignApts release]; - [self->item release]; - [self->partNames release]; - [self->partStates release]; - [self->userParticipationStatus release]; - [super dealloc]; -} - - -/* accessors */ - -- (void)setItem:(id)_item { - NSString *ps, *email; - NSArray *partmails; - unsigned idx; - - ASSIGN(self->item, _item); - - [self->partNames release]; - [self->partStates release]; - ps = [self->item valueForKey:@"participants"]; - self->partNames = [[ps componentsSeparatedByString:@"\n"] mutableCopy]; - ps = [self->item valueForKey:@"partstates"]; - self->partStates = [[ps componentsSeparatedByString:@"\n"] mutableCopy]; - ps = [self->item valueForKey:@"partmails"]; - partmails = [ps componentsSeparatedByString:@"\n"]; - - /* reorder partNames/partStates */ - - /* ensure organizer is first entry */ - email = [self->item valueForKey:@"orgmail"]; - if ([email isNotNull]) { - idx = [partmails indexOfObject:email]; - if (idx != NSNotFound && idx != 0) { - id obj; - - obj = [self->partNames objectAtIndex:idx]; - [self->partNames insertObject:obj atIndex:0]; /* frontmost */ - [self->partNames removeObjectAtIndex:idx + 1]; - obj = [self->partStates objectAtIndex:idx]; - [self->partStates insertObject:obj atIndex:0]; /* frontmost */ - [self->partStates removeObjectAtIndex:idx + 1]; - } - } - /* user is either second, first or none at all */ - [self->userParticipationStatus release]; - email = [self emailForUser]; - idx = [partmails indexOfObject:email]; - if (idx != NSNotFound && idx != 0 && idx != 1) { - id obj; - - self->userIndex = 1; - obj = [self->partNames objectAtIndex:idx]; - [self->partNames insertObject:obj atIndex:self->userIndex]; /* second */ - [self->partNames removeObjectAtIndex:idx + 1]; - obj = [self->partStates objectAtIndex:idx]; - [self->partStates insertObject:obj atIndex:self->userIndex]; /* second */ - [self->partStates removeObjectAtIndex:idx + 1]; - } - else { - self->userIndex = idx; - } - if (self->userIndex != NSNotFound) - self->userParticipationStatus = - [[self->partStates objectAtIndex:self->userIndex] retain]; - else - self->userParticipationStatus = nil; -} -- (id)item { - return self->item; -} - -- (void)setParticipantIndex:(unsigned)_participantIndex { - self->participantIndex = _participantIndex; -} -- (unsigned)participantIndex { - return self->participantIndex; -} - -- (unsigned)userIndex { - return self->userIndex; -} - -- (BOOL)isFirstParticipant { - return self->participantIndex == 0 ? YES : NO; -} - -- (BOOL)hasUserAppointments { - // NOTE: this has been disabled for Agenor 0.8 on client's request -#if 1 - return NO; -#else - return [[self userAppointments] count] > 0; -#endif -} -- (BOOL)hasForeignAppointments { - return [[self foreignAppointments] count] > 0; -} -- (BOOL)hasAnyAppointments { - return ([self hasUserAppointments] || - [self hasForeignAppointments]) ? YES : NO; -} - -- (unsigned)participantsCount { - return [self->partNames count]; -} - -- (NSString *)participant { - return [self->partNames objectAtIndex:self->participantIndex]; -} - -- (NSString *)participationStatus { - return [self->partStates objectAtIndex:self->participantIndex]; -} - -- (unsigned)maxRenderedParticipantsCount { - return 3; -} - -- (unsigned)renderedParticipantsCount { - if ([self didTruncateParticipants]) - return [self maxRenderedParticipantsCount]; - return [self participantsCount]; -} - -- (unsigned)truncatedParticipantsCount { - return [self participantsCount] - [self renderedParticipantsCount]; -} - -- (BOOL)didTruncateParticipants { - return [self participantsCount] > - ([self maxRenderedParticipantsCount] + 1) ? YES : NO; -} - -- (unsigned)rowspan { - unsigned count; - - count = [self renderedParticipantsCount]; - if ([self didTruncateParticipants]) - count += 1; - return count; -} - -- (NSString *)userParticipationStatus { - return self->userParticipationStatus; -} - -- (BOOL)shouldIgnoreRejectedAppointments { - return ![self shouldShowRejectedAndAcceptedAppointments]; -} - -- (BOOL)shouldIgnoreAcceptedAppointments { - return ![self shouldShowRejectedAndAcceptedAppointments]; -} - -- (BOOL)shouldShowRejectedAndAcceptedAppointments { - NSString *value; - - value = [[[self context] request] formValueForKey:@"dr"]; - if (!value) return NO; - return [value boolValue]; -} - -- (NSString *)toggleShowHideAptsQueryParameter { - BOOL shouldShow; - - shouldShow = [self shouldShowRejectedAndAcceptedAppointments]; - return shouldShow ? @"0" : @"1"; -} - -- (NSString *)toggleShowHideAptsText { - if ([self shouldShowRejectedAndAcceptedAppointments]) - return @"Hide already accepted and rejected appointments"; - return @"Show already accepted and rejected appointments"; -} - - -- (NSString *)getUserPartStateFromApt:(id)_apt { - NSString *email; - NSArray *ps, *pms; - unsigned idx; - - email = [self emailForUser]; - pms = [[_apt valueForKey:@"partmails"] - componentsSeparatedByString:@"\n"]; - idx = [pms indexOfObject:email]; - if (idx == NSNotFound) return nil; - ps = [[_apt valueForKey:@"partstates"] - componentsSeparatedByString:@"\n"]; - return [ps objectAtIndex:idx]; -} - - -/* fetching */ - -- (NSCalendarDate *)startDate { - return [[NSCalendarDate date] beginOfDay]; -} - -/* ZNeK: is a month ok? */ -- (NSCalendarDate *)endDate { - NSCalendarDate *date; - - date = [NSCalendarDate date]; - date = [date dateByAddingYears:0 months:1 days:0 - hours:0 minutes:0 seconds:0]; - date = [date endOfDay]; - return date; -} - -- (NSArray *)userAppointments { - if (!self->userApts) { - [self fetchInfos]; - } - return self->userApts; -} - -- (NSArray *)foreignAppointments { - if (!self->foreignApts) { - [self fetchInfos]; - } - return self->foreignApts; -} - -- (void) fetchInfos { - static NSArray *orders = nil; - id aptFolder; - NSArray *apts; - NSString *userEmail; - unsigned i, count; - - if (!orders) { - EOSortOrdering *so; - so = [EOSortOrdering sortOrderingWithKey:@"startDate" - selector:EOCompareAscending]; - orders = [[NSArray alloc] initWithObjects:so, nil]; - } - - aptFolder = [self clientObject]; - apts = [aptFolder fetchCoreInfosFrom: [self startDate] - to: [self endDate] - component: @"vevent"]; - userEmail = [self emailForUser]; - count = [apts count]; - - self->userApts = [[NSMutableArray alloc] initWithCapacity:count]; - self->foreignApts = [[NSMutableArray alloc] initWithCapacity:count]; - - for (i = 0; i < count; i++) { - id apt; - NSString *orgEmail; - - apt = [apts objectAtIndex:i]; - orgEmail = [(NSDictionary *)apt objectForKey:@"orgmail"]; - if (orgEmail && [orgEmail isEqualToString:userEmail]) { - [self->userApts addObject:apt]; - } - else { - BOOL shouldAdd = YES; - - if ([self shouldIgnoreAcceptedAppointments] || - [self shouldIgnoreRejectedAppointments]) - { - NSString *userPartStat; - - userPartStat = [self getUserPartStateFromApt:apt]; - if (userPartStat) { - if ([self shouldIgnoreAcceptedAppointments] && - [userPartStat isEqualToString:@"1"]) - shouldAdd = NO; - else if ([self shouldIgnoreRejectedAppointments] && - [userPartStat isEqualToString:@"2"]) - shouldAdd = NO; - } - } - if (shouldAdd) - [self->foreignApts addObject:apt]; - } - } - [self->userApts sortUsingKeyOrderArray:orders]; - [self->foreignApts sortUsingKeyOrderArray:orders]; -} - - -/* URLs */ - -- (NSString *)appointmentBaseURL { - id pkey; - - if (![(pkey = [self->item valueForKey:@"uid"]) isNotNull]) - return nil; - - return [[self clientObject] baseURLForAptWithUID:[pkey stringValue] - inContext:[self context]]; -} -- (NSString *)appointmentViewURL { - return [[self appointmentBaseURL] stringByAppendingPathComponent:@"view"]; -} -- (NSString *)acceptAppointmentURL { - return [[self appointmentBaseURL] stringByAppendingPathComponent:@"accept"]; -} -- (NSString *)declineAppointmentURL { - return [[self appointmentBaseURL] stringByAppendingPathComponent:@"decline"]; -} - - -/* access protection */ - -- (BOOL)canAccess { - NSString *owner; - - owner = [[self clientObject] ownerInContext:[self context]]; - if (!owner) - return NO; - return [[[[self context] activeUser] login] isEqualToString:owner]; -} - -@end diff --git a/UI/Scheduler/UIxCalView.h b/UI/Scheduler/UIxCalView.h index 9446c0ad..4b2eeb10 100644 --- a/UI/Scheduler/UIxCalView.h +++ b/UI/Scheduler/UIxCalView.h @@ -18,6 +18,7 @@ @interface UIxCalView : UIxComponent { NSArray *appointments; + NSMutableArray *calendarFolders; NSMutableDictionary *componentsData; NSArray *tasks; NSArray *allDayApts; diff --git a/UI/Scheduler/UIxCalView.m b/UI/Scheduler/UIxCalView.m index 74b68328..11047344 100644 --- a/UI/Scheduler/UIxCalView.m +++ b/UI/Scheduler/UIxCalView.m @@ -56,12 +56,15 @@ static BOOL shouldDisplayWeekend = NO; = [[SOGoAptFormatter alloc] initWithDisplayTimeZone: tz]; [self configureFormatters]; componentsData = [NSMutableDictionary new]; + calendarFolders = nil; } + return self; } - (void) dealloc { + [calendarFolders release]; [componentsData release]; [appointments release]; [allDayApts release]; @@ -446,37 +449,120 @@ static BOOL shouldDisplayWeekend = NO; return [[self startDate] tomorrow]; } -- (NSArray *) activeCalendarFolders +#warning We only support ONE calendar per user at this time +- (BOOL) _appendSubscribedFolders: (NSDictionary *) subscribedFolders { - NSUserDefaults *ud; - NSEnumerator *calendarUIDs; - SOGoAppointmentFolder *currentFolder; - NSMutableArray *folders; - NSString *currentUID; - SoSecurityManager *securityManager; - - securityManager = [SoSecurityManager sharedSecurityManager]; - - folders = [NSMutableArray array]; - ud = [[context activeUser] userDefaults]; - calendarUIDs = [[[ud stringForKey: @"calendaruids"] - componentsSeparatedByString: @","] objectEnumerator]; - currentUID = [calendarUIDs nextObject]; - while (currentUID) + NSEnumerator *keys; + NSString *currentKey; + NSMutableDictionary *currentCalendar; + BOOL firstShouldBeActive; + unsigned int count; + + firstShouldBeActive = YES; + + keys = [[subscribedFolders allKeys] objectEnumerator]; + currentKey = [keys nextObject]; + count = 1; + while (currentKey) { - if (![currentUID hasPrefix: @"-"]) - { - currentFolder = [[self clientObject] lookupCalendarFolderForUID: currentUID]; - if (currentFolder - && ![securityManager validatePermission: SoPerm_AccessContentsInformation - onObject: currentFolder - inContext: context]) - [folders addObject: currentFolder]; - } - currentUID = [calendarUIDs nextObject]; + currentCalendar = [NSMutableDictionary new]; + [currentCalendar autorelease]; + [currentCalendar + setDictionary: [subscribedFolders objectForKey: currentKey]]; + [currentCalendar setObject: currentKey forKey: @"folder"]; + [calendarFolders addObject: currentCalendar]; + if ([[currentCalendar objectForKey: @"active"] boolValue]) + firstShouldBeActive = NO; + count++; + currentKey = [keys nextObject]; + } + + return firstShouldBeActive; +} + +- (void) _setupCalendarFolders +{ + NSMutableDictionary *userCalendar, *calendarDict; + SOGoUser *activeUser; + BOOL firstActive; + + calendarFolders = [NSMutableArray new]; + activeUser = [context activeUser]; + + userCalendar = [NSMutableDictionary new]; + [userCalendar autorelease]; + [userCalendar setObject: @"/" forKey: @"folder"]; + [userCalendar setObject: [self labelForKey: @"Calendar"] + forKey: @"displayName"]; + [calendarFolders addObject: userCalendar]; + + calendarDict = [[activeUser userSettings] objectForKey: @"Calendar"]; + firstActive = [[calendarDict objectForKey: @"activateUserFolder"] boolValue]; + firstActive = ([self _appendSubscribedFolders: + [calendarDict objectForKey: @"SubscribedFolders"]] + || firstActive); + [userCalendar setObject: [NSNumber numberWithBool: firstActive] + forKey: @"active"]; +} + +- (SOGoAppointmentFolder *) _aptFolder: (NSString *) folder + withClientObject: (SOGoAppointmentFolder *) clientObject +{ + SOGoAppointmentFolder *aptFolder; + NSArray *folderParts; + + if ([folder isEqualToString: @"/"]) + aptFolder = clientObject; + else + { + folderParts = [folder componentsSeparatedByString: @":"]; + aptFolder + = [clientObject lookupCalendarFolderForUID: + [folderParts objectAtIndex: 0]]; + } + + return aptFolder; +} + +- (NSArray *) calendarFolders +{ + if (!calendarFolders) + [self _setupCalendarFolders]; + + return calendarFolders; +} + +- (NSArray *) _activeCalendarFolders +{ + NSMutableArray *activeFolders; + NSEnumerator *folders; + NSDictionary *currentFolderDict; + SOGoAppointmentFolder *currentFolder, *clientObject; + + activeFolders = [NSMutableArray new]; + [activeFolders autorelease]; + + if (!calendarFolders) + [self _setupCalendarFolders]; + + clientObject = [self clientObject]; + + folders = [calendarFolders objectEnumerator]; + currentFolderDict = [folders nextObject]; + while (currentFolderDict) + { + if ([[currentFolderDict objectForKey: @"active"] boolValue]) + { + currentFolder + = [self _aptFolder: [currentFolderDict objectForKey: @"folder"] + withClientObject: clientObject]; + [activeFolders addObject: currentFolder]; + } + + currentFolderDict = [folders nextObject]; } - return folders; + return activeFolders; } - (NSArray *) _fetchCoreInfosForComponent: (NSString *) component @@ -490,7 +576,7 @@ static BOOL shouldDisplayWeekend = NO; if (!infos) { infos = [NSMutableArray array]; - folders = [[self activeCalendarFolders] objectEnumerator]; + folders = [[self _activeCalendarFolders] objectEnumerator]; currentFolder = [folders nextObject]; while (currentFolder) { diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index 03479b99..1b8c8d7d 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -816,6 +816,7 @@ inContext: (WOContext *) _ctx { NSCalendarDate *now; + SOGoCalendarComponent *clientObject; [super takeValuesFromRequest: _rq inContext: _ctx]; @@ -826,8 +827,10 @@ [component setUrl: url]; [self _handleAttendeesEdition]; [self _handleOrganizer]; - if ([[self clientObject] isNew]) + clientObject = [self clientObject]; + if ([clientObject isNew]) { + [component setUid: [clientObject nameInContainer]]; [component setCreated: now]; [component setTimeStampAsDate: now]; [component setPriority: @"0"]; diff --git a/UI/Contacts/UIxContactSelector.h b/UI/Scheduler/UIxContactSelector.h similarity index 100% rename from UI/Contacts/UIxContactSelector.h rename to UI/Scheduler/UIxContactSelector.h diff --git a/UI/Contacts/UIxContactSelector.m b/UI/Scheduler/UIxContactSelector.m similarity index 100% rename from UI/Contacts/UIxContactSelector.m rename to UI/Scheduler/UIxContactSelector.m diff --git a/UI/Scheduler/UIxTaskEditor.m b/UI/Scheduler/UIxTaskEditor.m index d4330911..4a34ac6b 100644 --- a/UI/Scheduler/UIxTaskEditor.m +++ b/UI/Scheduler/UIxTaskEditor.m @@ -465,7 +465,7 @@ else { [todo setCompleted: nil]; - [todo setPercentComplete: 0]; + [todo setPercentComplete: @"0"]; [todo setStatus: @"IN-PROCESS"]; } diff --git a/UI/Scheduler/product.plist b/UI/Scheduler/product.plist index 8b9b78fb..c96c9bfc 100644 --- a/UI/Scheduler/product.plist +++ b/UI/Scheduler/product.plist @@ -1,5 +1,5 @@ { - requires = ( MAIN, CommonUI, Appointments, Contacts, ContactsUI ); + requires = ( MAIN, MainUI, CommonUI, Appointments, Contacts, ContactsUI ); publicResources = ( previous_week.gif, @@ -102,11 +102,6 @@ pageName = "UIxCalMainView"; actionName = "updateCalendars"; }; - checkRights = { - protectedBy = "View"; - pageName = "UIxCalMainView"; - actionName = "checkRights"; - }; editAttendees = { protectedBy = "View"; pageName = "UIxAttendeesEditor"; diff --git a/UI/Templates/ContactsUI/UIxContactsAclsSelection.wox b/UI/Templates/ContactsUI/UIxContactsAclsSelection.wox deleted file mode 100644 index 7a106ace..00000000 --- a/UI/Templates/ContactsUI/UIxContactsAclsSelection.wox +++ /dev/null @@ -1,21 +0,0 @@ - -
-
- -
diff --git a/UI/Templates/ContactsUI/UIxContactsAddressBooksSelection.wox b/UI/Templates/ContactsUI/UIxContactsAddressBooksSelection.wox deleted file mode 100644 index daf472d7..00000000 --- a/UI/Templates/ContactsUI/UIxContactsAddressBooksSelection.wox +++ /dev/null @@ -1,16 +0,0 @@ - -
- -
diff --git a/UI/Templates/ContactsUI/UIxContactsCalendarsSelection.wox b/UI/Templates/ContactsUI/UIxContactsCalendarsSelection.wox deleted file mode 100644 index 06888b3e..00000000 --- a/UI/Templates/ContactsUI/UIxContactsCalendarsSelection.wox +++ /dev/null @@ -1,16 +0,0 @@ - -
- -
diff --git a/UI/Templates/ContactsUI/UIxContactsFilterPanel.wox b/UI/Templates/ContactsUI/UIxContactsFilterPanel.wox index 54614dc0..916ce36c 100644 --- a/UI/Templates/ContactsUI/UIxContactsFilterPanel.wox +++ b/UI/Templates/ContactsUI/UIxContactsFilterPanel.wox @@ -16,7 +16,9 @@
- +
diff --git a/UI/Templates/ContactsUI/UIxContactsListViewContainer.wox b/UI/Templates/ContactsUI/UIxContactsListViewContainer.wox index ca5c54bf..45d90f3b 100644 --- a/UI/Templates/ContactsUI/UIxContactsListViewContainer.wox +++ b/UI/Templates/ContactsUI/UIxContactsListViewContainer.wox @@ -58,23 +58,15 @@ /> -
    +
    • -
    @@ -113,8 +105,4 @@ - - diff --git a/UI/Templates/ContactsUI/UIxContactsMailerSelection.wox b/UI/Templates/ContactsUI/UIxContactsMailerSelection.wox index a6e1c1b3..7b391ccb 100644 --- a/UI/Templates/ContactsUI/UIxContactsMailerSelection.wox +++ b/UI/Templates/ContactsUI/UIxContactsMailerSelection.wox @@ -1,26 +1,24 @@ - -
    - + +
    +
    +
    -
    - -
    + label:value="Carbon Copy" + name="cc"/>
    + +
    diff --git a/UI/Templates/ContactsUI/UIxContactsUserFolders.wox b/UI/Templates/ContactsUI/UIxContactsUserFolders.wox new file mode 100644 index 00000000..b6b95e63 --- /dev/null +++ b/UI/Templates/ContactsUI/UIxContactsUserFolders.wox @@ -0,0 +1,21 @@ + + + + + +
    +
    +
    + +
    +
    diff --git a/UI/Templates/MailerUI/UIxMailFilterPanel.wox b/UI/Templates/MailerUI/UIxMailFilterPanel.wox index c3647767..349b5c0b 100644 --- a/UI/Templates/MailerUI/UIxMailFilterPanel.wox +++ b/UI/Templates/MailerUI/UIxMailFilterPanel.wox @@ -35,12 +35,7 @@ + menuid="searchMenu" /> diff --git a/UI/Templates/SchedulerUI/UIxCalBackForthNavView.wox b/UI/Templates/SchedulerUI/UIxCalBackForthNavView.wox deleted file mode 100644 index d8bc6558..00000000 --- a/UI/Templates/SchedulerUI/UIxCalBackForthNavView.wox +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - -
    - previous - - - - next -
    diff --git a/UI/Templates/SchedulerUI/UIxCalCalendarsListView.wox b/UI/Templates/SchedulerUI/UIxCalCalendarsListView.wox deleted file mode 100644 index 24d547b1..00000000 --- a/UI/Templates/SchedulerUI/UIxCalCalendarsListView.wox +++ /dev/null @@ -1,23 +0,0 @@ - - - - - diff --git a/UI/Templates/SchedulerUI/UIxCalDayTable.wox b/UI/Templates/SchedulerUI/UIxCalDayTable.wox index 42022b7d..15662a4c 100644 --- a/UI/Templates/SchedulerUI/UIxCalDayTable.wox +++ b/UI/Templates/SchedulerUI/UIxCalDayTable.wox @@ -43,7 +43,8 @@
    + >
    + menuid="searchMenu" /> diff --git a/UI/Templates/SchedulerUI/UIxCalMainView.wox b/UI/Templates/SchedulerUI/UIxCalMainView.wox index ec44153e..a0c4675b 100644 --- a/UI/Templates/SchedulerUI/UIxCalMainView.wox +++ b/UI/Templates/SchedulerUI/UIxCalMainView.wox @@ -75,10 +75,9 @@ >
    -
    +
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - -
    - -
    - -
    - - - - - - - -
    - - ... - -
    - - - - - - - - - - - - - - - - - - -
    - - ... - -
    -
    \ No newline at end of file diff --git a/UI/Templates/ContactsUI/UIxContactSelector.wox b/UI/Templates/SchedulerUI/UIxContactSelector.wox similarity index 100% rename from UI/Templates/ContactsUI/UIxContactSelector.wox rename to UI/Templates/SchedulerUI/UIxContactSelector.wox diff --git a/UI/Templates/UIxAclEditor.wox b/UI/Templates/UIxAclEditor.wox index f32d4841..d0d6d55f 100644 --- a/UI/Templates/UIxAclEditor.wox +++ b/UI/Templates/UIxAclEditor.wox @@ -1,37 +1,64 @@ - + + -
    -
    - - - -
    - -
    - + +
    + + + +
    + + + +
    + + + + + +
      +
    • + +
    • +
      +
    - - + +
    + +
    + +
    diff --git a/UI/WebServerResources/ContactsUI.js b/UI/WebServerResources/ContactsUI.js index 5ac0bfba..caee6cdb 100644 --- a/UI/WebServerResources/ContactsUI.js +++ b/UI/WebServerResources/ContactsUI.js @@ -1,70 +1,13 @@ -/* - Copyright (C) 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. -*/ -/* JavaScript for SOGo Mailer */ - -/* - DOM ids available in mail list view: - row_$msgid - div_$msgid - readdiv_$msgid - unreaddiv_$msgid - - Window Properties: - width, height - bool: resizable, scrollbars, toolbar, location, directories, status, - menubar, copyhistory -*/ +/* JavaScript for SOGoContacts */ var cachedContacts = new Array(); -var currentContactFolder = ''; -var currentFolderIsExternal = false; -var contactSelectorAction = 'addressbooks-contacts'; +var currentContactFolder = '/personal'; function openContactWindow(sender, url) { var msgWin = window.open(url, null, "width=450,height=600,resizable=0"); msgWin.focus(); } -function clickedUid(sender, contactuid) { - resetSelection(window); - openContactWindow(sender, contactuid, - CurrentContactFolderURL() - + "/" + contactuid + "/edit"); - return true; -} - -function doubleClickedUid(sender, contactuid) { - alert("DOUBLE Clicked " + contactuid); - - return false; -} - -function toggleMailSelect(sender) { - var row; - row = $(sender.name); - row.className = sender.checked ? "tableview_selected" : "tableview"; -} - -/* mail editor */ - function validateEditorInput(sender) { var errortext = ""; var field; @@ -84,25 +27,7 @@ function validateEditorInput(sender) { return true; } -function onContactsFolderTreeItemClick(element) { - var topNode = $('d'); - var contactsFolder = element.parentNode.getAttribute("dataname"); - - if (topNode.selectedEntry) - topNode.selectedEntry.deselect(); - element.select(); - topNode.selectedEntry = element; - - openContactsFolder(contactsFolder); -} - -function CurrentContactFolderURL() { - return ((currentFolderIsExternal) - ? UserFolderURL + "../" + currentContactFolder + "/Contacts/personal" - : ApplicationBaseURL + currentContactFolder); -} - -function openContactsFolder(contactsFolder, params, external) { +function openContactsFolder(contactsFolder, params) { if (contactsFolder != currentContactFolder || params) { if (contactsFolder == currentContactFolder) { var contactsList = $("contactsList"); @@ -115,11 +40,8 @@ function openContactsFolder(contactsFolder, params, external) { selection = null; currentContactFolder = contactsFolder; - if (external) - currentFolderIsExternal = true; - else - currentFolderIsExternal = false; - var url = CurrentContactFolderURL() + "/view?noframe=1&sort=cn&desc=0"; + var url = URLForFolderID(currentContactFolder) + + "/view?noframe=1&sort=cn&desc=0"; if (params) url += '&' + params; @@ -135,7 +57,7 @@ function openContactsFolder(contactsFolder, params, external) { function openContactsFolderAtIndex(element) { var idx = element.getAttribute("idx"); - var url = CurrentContactFolderURL() + "/view?noframe=1&idx=" + idx; + var url = URLForFolderID(currentContactFolder) + "/view?noframe=1&idx=" + idx; if (document.contactsListAjaxRequest) { document.contactsListAjaxRequest.aborted = true; @@ -243,8 +165,8 @@ function loadContact(idx) { div.innerHTML = cachedContacts[currentContactFolder + "/" + idx]; } else { - var url = (CurrentContactFolderURL() + "/" - + idx + "/view?noframe=1"); + var url = (URLForFolderID(currentContactFolder) + + "/" + idx + "/view?noframe=1"); document.contactAjaxRequest = triggerAjaxRequest(url, contactLoadCallback, idx); } @@ -304,7 +226,7 @@ function onContactRowDblClick(event, node) { var contactId = node.getAttribute('id'); openContactWindow(null, - CurrentContactFolderURL() + URLForFolderID(currentContactFolder) + "/" + contactId + "/edit"); return false; @@ -315,7 +237,7 @@ function onMenuEditContact(event, node) { var contactId = node.getAttribute('id'); openContactWindow(null, - CurrentContactFolderURL() + URLForFolderID(currentContactFolder) + "/" + contactId + "/edit"); return false; @@ -325,7 +247,7 @@ function onMenuWriteToContact(event, node) { var node = getParentMenu(node).menuTarget.parentNode; var contactId = node.getAttribute('id'); - openMailComposeWindow(CurrentContactFolderURL() + openMailComposeWindow(ApplicationBaseURL + currentContactFolder + "/" + contactId + "/write"); return false; @@ -343,7 +265,7 @@ function onToolbarEditSelectedContacts(event) { for (var i = 0; i < rows.length; i++) { openContactWindow(null, - CurrentContactFolderURL() + URLForFolderID(currentContactFolder) + "/" + rows[i] + "/edit"); } @@ -355,7 +277,7 @@ function onToolbarWriteToSelectedContacts(event) { var rows = contactsList.getSelectedRowsId(); for (var i = 0; i < rows.length; i++) - openMailComposeWindow(CurrentContactFolderURL() + openMailComposeWindow(ApplicationBaseURL + currentContactFolder + "/" + rows[i] + "/write"); return false; @@ -374,7 +296,7 @@ function uixDeleteSelectedContacts(sender) { /* send AJAX request (synchronously) */ - url = (CurrentContactFolderURL() + "/" + url = (URLForFolderID(currentContactFolder) + "/" + rows[i] + "/delete"); http = createHTTPClient(); http.open("POST", url, false /* not async */); @@ -394,7 +316,7 @@ function uixDeleteSelectedContacts(sender) { } if (failCount > 0) - alert("Could not delete " + failCount + " messages!"); + alert("Could not delete the selected contacts!"); return false; } @@ -419,7 +341,7 @@ function onHeaderClick(event) { document.contactsListAjaxRequest.aborted = true; document.contactsListAjaxRequest.abort(); } - url = CurrentContactFolderURL() + "/" + this.link; + url = URLForFolderID(currentContactFolder) + "/" + this.link; if (!this.link.match(/noframe=/)) url += "&noframe=1"; document.contactsListAjaxRequest @@ -434,145 +356,63 @@ function registerDraggableMessageNodes() { function newContact(sender) { openContactWindow(sender, - CurrentContactFolderURL() + "/new"); + URLForFolderID(currentContactFolder) + "/new"); return false; /* stop following the link */ } function onFolderSelectionChange() { - var folderList = $("contactFolders"); - var nodes = folderList.getSelectedNodes(); - $("contactView").innerHTML = ''; - - if (nodes[0].hasClassName("denied")) { - var div = $("contactsListContent"); - div.innerHTML = ""; - } - else { - var newFolder; - var externalFolder = nodes[0].getAttribute("external-addressbook"); - if (externalFolder) - newFolder = externalFolder; - else - newFolder = nodes[0].getAttribute("id"); - - openContactsFolder(newFolder, null, externalFolder); - } + var folderList = $("contactFolders"); + var nodes = folderList.getSelectedNodes(); + $("contactView").innerHTML = ''; + + if (nodes[0].hasClassName("denied")) { + var div = $("contactsListContent"); + div.innerHTML = ""; + } + else + openContactsFolder(nodes[0].getAttribute("id"), null); } function onSearchFormSubmit() { var searchValue = $("searchValue"); - openContactsFolder(currentContactFolder, "search=" + searchValue.value); + openContactsFolder(URLForFolderID(currentContactFolder), + "search=" + searchValue.value); return false; } -function onConfirmContactSelection(tag) { - var folderLi = $(currentContactFolder); - var currentContactFolderName = folderLi.innerHTML; - var selectorList = null; - var initialValues = null; +function onConfirmContactSelection(event) { + var tag = this.getAttribute("name"); + var folderLi = $(currentContactFolder); + var currentContactFolderName = folderLi.innerHTML; + var selectorList = null; + var initialValues = null; - if (selector) - { + if (selector) { var selectorId = selector.getAttribute("id"); selectorList = opener.window.document.getElementById('uixselector-' + selectorId + '-uidList'); initialValues = selectorList.value; - } - - var contactsList = $("contactsList"); - var rows = contactsList.getSelectedRows(); - for (i = 0; i < rows.length; i++) { - var cid = rows[i].getAttribute("contactid"); - var cname = '' + rows[i].getAttribute("contactname"); - var email = '' + rows[i].cells[1].innerHTML; - opener.window.addContact(tag, currentContactFolderName + '/' + cname, - cid, cname, email); - } - - if (selector && selector.changeNotification - && selectorList.value != initialValues) - selector.changeNotification("addition"); - - return false; -} - -function onConfirmAddressBookSelection() { - var folderLi = $(currentContactFolder); - var currentContactFolderName = folderLi.innerHTML; - - var selector = window.opener.document.getElementById("contactFolders"); - var initialValues = selector.getAttribute("additional-addressbooks"); - if (!initialValues) - initialValues = ""; - var newValues = initialValues; - - var contactsList = $("contactsList"); - var rows = contactsList.getSelectedRows(); - for (i = 0; i < rows.length; i++) { - var cid = rows[i].getAttribute("contactid"); - var cname = '' + rows[i].getAttribute("contactname"); - var email = '' + rows[i].cells[1].innerHTML; - var re = new RegExp("(^|,)" + cid + "($|,)"); - if (!re.test(newValues)) { - if (newValues.length) - newValues += "," + cid; - else - newValues = cid; - } - } - - if (newValues != initialValues) - window.opener.setTimeout("setAdditionalAddressBooks(\"" - + newValues + "\");", 100); + } - return false; -} + var contactsList = $("contactsList"); + var rows = contactsList.getSelectedRows(); + for (i = 0; i < rows.length; i++) { + var cid = rows[i].getAttribute("contactid"); + var cname = '' + rows[i].getAttribute("contactname"); + var email = '' + rows[i].cells[1].innerHTML; + opener.window.addContact(tag, currentContactFolderName + '/' + cname, + cid, cname, email); + } -function setAdditionalAddressBooks(additionalAddressBooks) { - var urlstr = (ApplicationBaseURL + "/updateAdditionalAddressBooks?ids=" - + additionalAddressBooks); - if (document.addressBooksAjaxRequest) { - document.addressBooksAjaxRequest.aborted = true; - document.addressBooksAjaxRequest.abort(); - } - document.addressBooksAjaxRequest - = triggerAjaxRequest(urlstr, - addressBooksCallback, additionalAddressBooks); -} + if (selector && selector.changeNotification + && selectorList.value != initialValues) + selector.changeNotification("addition"); -function addressBooksCallback(http) { - if (http.readyState == 4) { - if (http.status == 200) { - var ul = $("contactFolders"); - - var children = ul.childNodesWithTag("li"); - for (var i = 0; i < children.length; i++) - if (children[i].getAttribute("external-addressbook")) - ul.removeChild(children[i]); - - ul.setAttribute("additional-addressbooks", http.callbackData); - if (http.callbackData.length > 0) { - var list = http.callbackData.split(","); - var newCode = ""; - for (var i = 0; i < list.length; i++) { - var username = list[i]; - newCode += ( "
  • " ); - newCode += ( username + "
  • " ); - } - ul.innerHTML += newCode; - } - } - document.addressBooksAjaxRequest = null; - } - else - log ("ajax fuckage 3"); + event.preventDefault(); } function onContactMailTo(node) { @@ -580,7 +420,7 @@ function onContactMailTo(node) { } function refreshContacts(contactId) { - openContactsFolder(currentContactFolder, "reload=true", currentFolderIsExternal); + openContactsFolder(currentContactFolder, "reload=true"); cachedContacts[currentContactFolder + "/" + contactId] = null; loadContact(contactId); @@ -601,63 +441,62 @@ function onAddressBookNew(event) { event.preventDefault(); } +function appendAddressBook(name, folder) { + var li = document.createElement("li"); + li.setAttribute("id", folder); + li.appendChild(document.createTextNode(name)); + li.addEventListener("mousedown", listRowMouseDownHandler, false); + li.addEventListener("click", onRowClick, false); + li.addEventListener("contextmenu", onContactFoldersContextMenu, false); + $("contactFolders").appendChild(li); +} + function newAbCallback(http) { if (http.readyState == 4 && http.status == 201) { - var ul = $("contactFolders"); var name = http.callbackData; - var li = document.createElement("li"); - li.setAttribute("id", "/" + name); - li.appendChild(document.createTextNode(name)); - li.addEventListener("mousedown", listRowMouseDownHandler, false); - li.addEventListener("click", onRowClick, false); - li.addEventListener("contextmenu", onContactFoldersContextMenu, false); - ul.appendChild(li); + appendAddressBook(name, "/" + name); } else log ("ajax fuckage 4:" + http.status); } +function newUserFolderCallback(folderData) { + var folder = $(folderData["folder"]); + if (!folder) + appendAddressBook(folderData["folderName"], folderData["folder"]); +} + function onAddressBookAdd(event) { - var selector = $("contactFolders"); - var selectorURL = '?popup=YES&selectorId=contactFolders'; - - urlstr = ApplicationBaseURL; - if (urlstr[urlstr.length-1] != '/') - urlstr += '/'; - urlstr += ("../../" + UserLogin + "/Contacts/" - + contactSelectorAction + selectorURL); -// log (urlstr); - var w = window.open(urlstr, "Addressbook", - "width=640,height=400,resizable=1,scrollbars=0"); - w.selector = selector; - w.opener = window; - w.focus(); + openUserFolderSelector(newUserFolderCallback, "contact"); - event.preventDefault(); + event.preventDefault(); +} + +function onFolderUnsubscribeCB(folderId) { + var node = $(folderId); + node.parentNode.removeChild(node); + var personal = $("/personal"); + personal.select(); + onFolderSelectionChange(); } function onAddressBookRemove(event) { var selector = $("contactFolders"); var nodes = selector.getSelectedNodes(); - if (nodes.length > 0) { - var cid = nodes[0].getAttribute("external-addressbook"); - if (cid) { - var initialValues = selector.getAttribute("additional-addressbooks"); - var re = new RegExp("(^|,)" + cid + "($|,)"); - var newValues = initialValues.replace(re, ""); - if (initialValues != newValues) - setAdditionalAddressBooks(newValues); - } - else { - nodes[0].deselect(); - var folderId = nodes[0].getAttribute("id").substr(1); - deletePersonalAddressBook(folderId); - } - - var personal = $("/personal"); - personal.select(); - onFolderSelectionChange(); + if (nodes.length > 0) { + nodes[0].deselect(); + var folderId = nodes[0].getAttribute("id"); + var folderIdElements = folderId.split(":"); + if (folderIdElements.length > 1) + unsubscribeFromFolder(folderId, onFolderUnsubscribeCB, folderId); + else { + var abId = folderIdElements[0].substr(1); + deletePersonalAddressBook(abId); + var personal = $("/personal"); + personal.select(); + onFolderSelectionChange(); + } } event.preventDefault(); @@ -719,19 +558,26 @@ function configureDragHandles() { } function lookupDeniedFolders() { - var rights; - var http = createHTTPClient(); - if (http) { - http.url = ApplicationBaseURL + "/checkRights"; - http.open("GET", http.url, false /* not async */); - http.send(""); - if (http.status == 200 - && http.responseText.length > 0) { - rights = http.responseText.split(","); - } + var list = $("contactFolders").childNodesWithTag("li"); + for (var i = 0; i < list.length; i++) { + var folderID = list[i].getAttribute("id"); + var url = URLForFolderID(folderID) + "/canAccessContent"; + triggerAjaxRequest(url, deniedFoldersLookupCallback, folderID); } +} - return rights; +function deniedFoldersLookupCallback(http) { + if (http.readyState == 4) { + var denied = true; + + if (http.status == 200) + denied = (http.responseText == "0"); + var entry = $(http.callbackData); + if (denied) + entry.addClassName("denied"); + else + entry.removeClassName("denied"); + } } function configureAbToolbar() { @@ -754,31 +600,21 @@ function configureContactFolders() { lis[i].addEventListener("contextmenu", onContactFoldersContextMenu, false); } - var denieds = lookupDeniedFolders(); - if (denieds) { - var start = (lis.length - denieds.length); - for (var i = start; i < lis.length; i++) { - if (denieds[i-start] == "1") - lis[i].removeClassName("denied"); - else - lis[i].addClassName("denied"); - } - } + lookupDeniedFolders(); contactFolders.style.visibility = "visible;"; + + var personalFolder = $("/personal"); + personalFolder.select(); } } function onAccessRightsMenuEntryMouseUp(event) { var folders = $("contactFolders"); var selected = folders.getSelectedNodes()[0]; - var external = selected.getAttribute("external-addressbook"); var title = this.innerHTML; - if (external) - url = UserFolderURL + "../" + external + "/Contacts/personal/acls"; - else - url = ApplicationBaseURL + selected.getAttribute("id") + "/acls"; + var url = URLForFolderID(selected.getAttribute("id")) - openAclWindow(url, title); + openAclWindow(url + "/acls", title); } function initializeMenus() { @@ -789,11 +625,34 @@ function initializeMenus() { menuEntry.addEventListener("mouseup", onAccessRightsMenuEntryMouseUp, false); } +function configureSearchField() { + var searchValue = $("searchValue"); + + searchValue.addEventListener("mousedown", onSearchMouseDown, false); + searchValue.addEventListener("click", popupSearchMenu, false); + searchValue.addEventListener("blur", onSearchBlur, false); + searchValue.addEventListener("focus", onSearchFocus, false); + searchValue.addEventListener("keydown", onSearchKeyDown, false); +} + +function configureSelectionButtons() { + var container = $("contactSelectionButtons"); + if (container) { + var buttons = container.childNodesWithTag("input"); + for (var i = 0; i < buttons.length; i++) + buttons[i].addEventListener("click", onConfirmContactSelection, + false); + } +} + var initContacts = { handleEvent: function (event) { if (!document.body.hasClassName("popup")) { configureAbToolbar(); + configureSearchField(); } + else + configureSelectionButtons(); configureContactFolders(); // initDnd(); } diff --git a/UI/WebServerResources/MailerUI.css b/UI/WebServerResources/MailerUI.css index f10b370a..4a27af53 100644 --- a/UI/WebServerResources/MailerUI.css +++ b/UI/WebServerResources/MailerUI.css @@ -452,26 +452,6 @@ table.linked_attachment_meta font-style: italic; } -/* folder tree (js) )*/ -DIV.dTreeNode A SPAN.nodeName -{ - margin: 0px .2em; - padding-left: .2em; - padding-right: .2em; -} - -DIV.dTreeNode A._selected SPAN.nodeName -{ - background: #4b6983; - color: #fff; -} - -DIV.dTreeNode SPAN._dragOver -{ - background: #4b6983; - color: #fff; -} - /* drag-n-drop */ IMG.dragMessage { diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js index 9be2fc50..47d933db 100644 --- a/UI/WebServerResources/MailerUI.js +++ b/UI/WebServerResources/MailerUI.js @@ -1,37 +1,4 @@ -/* - Copyright (C) 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. -*/ -/* JavaScript for SOGo Mailer */ - -/* - DOM ids available in mail list view: - row_$msgid - div_$msgid - readdiv_$msgid - unreaddiv_$msgid - - Window Properties: - width, height - bool: resizable, scrollbars, toolbar, location, directories, status, - menubar, copyhistory -*/ +/* JavaScript for SOGoMail */ var currentMessages = new Array(); var maxCachedMessages = 20; @@ -1013,32 +980,42 @@ function openInbox(node) { } } -var initMailer = { - handleEvent: function (event) { - if (!document.body.hasClassName("popup")) { - var inboxFound = false; - configureMessageListEvents(); - initDnd(); - var tree = $("d"); - var nodes = document.getElementsByClassName("node", tree); - for (i = 0; i < nodes.length; i++) { - nodes[i].addEventListener("click", onMailboxTreeItemClick, false); - nodes[i].addEventListener("contextmenu", onFolderMenuClick, false); - if (!inboxFound - && nodes[i].parentNode.getAttribute("datatype") == "inbox") { - openInbox(nodes[i]); - inboxFound = true; - } - } - } - - /* -, 'onMailboxTreeItemClick(this);' -