+2007-09-14 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * SoObjects/SOGo/SOGoObject.m ([SOGoObject -labelForKey:key]): new
+ method that returns translated strings for controller bundles
+ (same as what UIxComponent does for view bundles).
+ ([SOGoObject -pathArrayToSOGoObject]): new method that returns
+ the real path to a subscribed folder (if subscribed).
+ ([SOGoObject +globallyUniqueObjectId]): move method from SOGoFolder.
+ ([SOGoObject -globallyUniqueObjectId]): new instance method
+ calling its class equivalent.
+
+2007-09-12 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * UI/MainUI/SOGoRootPage.m ([SOGoRootPage -defaultAction]): test
+ whether the user is logged in and if so, redirect to his/her
+ homepage.
+ ([SOGoRootPage -appendToResponse:inContext:]): removed useless
+ method.
+
+2007-09-11 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * SoObjects/SOGo/SOGoFolder.m ([SOGoFolder
+ +folderWithName:aNameandDisplayName:aDisplayNameinContainer:aContainer]):
+ new method.
+ ([SOGoFolder -displayName]): new method.
+ ([SOGoFolder -delete]): accept to proceed only if nameInContainer
+ != "personal".
+
+ * SoObjects/Contacts/SOGoContactLDAPFolder.m
+ ([SOGoContactLDAPFolder
+ +folderWithName:aNameandDisplayName:aDisplayNameinContainer:aContainer]):
+ renamed from "contactFolderWithName..." for compatibility with SOGoFolder.
+
+ * SoObjects/Contacts/SOGoContactGCSFolder.m ([SOGoContactGCSFolder
+ +contactFolderWithName:aNameandDisplayName:aDisplayNameinContainer:aContainer]):
+ removed method, reimplemented in SOGoFolder.
+ ([SOGoContactGCSFolder -displayName]): removed method,
+ reimplemented in SOGoFolder.
+ ([-delete]): removed method, modified in SOGoFolder.
+
+ * SoObjects/Contacts/SOGoContactFolders.[hm]: modified class to be
+ a subclass of SOGoParentFolder.
+
+ * SoObjects/SOGo/SOGoParentFolder.[hm]: new class module derived
+ from SOGoContactFolders and modified to be more content-independent.
+
+ * UI/MailerUI/UIxMailActions.m ([UIxMailActions -markMessageUnreadAction])
+ ([UIxMailActions -markMessageReadAction]): new methods moved from
+ UIxMailListView and adapted to invoke the client object directly,
+ since the previous versions had to to a lookup from the parent
+ SOGoMailFolder.
+
+ * UI/MailerUI/UIxMailListView.m ([-markMessageUnreadAction]): move
+ method into UIxMailActions.
+ ([-markMessageReadAction]): same as above.
+ ([-viewAction]): removed useless method.
+ ([-javaScriptOK]): removed useless method.
+ ([-isJavaScriptRequest]): removed useless method.
+ ([-lookupActiveMessage]): removed useless method.
+
+ * UI/Common/WODirectAction+SOGo.m ([WODirectAction
+ -responseWithStatus:status]): new method that returns a WOResponse
+ initialized with the specified status code.
+ ([WODirectAction -responseWith204]): new method that invokes the
+ above one with "204" as parameter.
+ ([WODirectAction -redirectToLocation:newLocation]): rewrote method
+ to make use of -responseWithStatus:.
+
+ * UI/SOGoUI/UIxComponent.m ([UIxComponent -responseWith204]): new
+ method that returns a WOResponse initialized with the 204 status
+ code.
+
+ * UI/MailerUI/UIxMailListView.m ([UIxMailListView -sortedUIDs]):
+ always use a "not deleted" search qualifier along with the user
+ qualifier (if present).
+
2007-09-10 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/Contacts/UIxContactFoldersView.m ([UIxContactFoldersView
- fixed a bug where a false positive happening whenever a wrong user login was
given during an indirect bind;
- deleting a message no longer expunges its parent folder;
+- implemented support for multiple calendars;
+- it is not possible to rename folders;
- fixed search in message content;
- countless bugfixes;
--- /dev/null
+"Personal Calendar" = "Personal Calendar";
--- /dev/null
+"Personal Calendar" = "Agenda personnel";
Appointments_PRINCIPAL_CLASS = SOGoAppointmentsProduct
-# Appointments_LANGUAGES = English French
+Appointments_LANGUAGES = English French German
+
+Appointments_LOCALIZED_RESOURCE_FILES=Localizable.strings
Appointments_OBJC_FILES = \
Product.m \
SOGoAppointmentObject.m \
SOGoTaskObject.m \
SOGoAppointmentFolder.m \
+ SOGoAppointmentFolders.m \
SOGoGroupAppointmentFolder.m \
SOGoFreeBusyObject.m \
\
--- /dev/null
+"Personal Calendar" = "Personal Calendar";
NSMutableDictionary *uidToFilename;
}
+- (BOOL) isActive;
+
/* selection */
- (NSArray *) calendarUIDs;
- (NSArray *) fetchAllSOGoAppointments;
-- (NSArray *) calendarFolders;
-
- (NSString *) roleForComponentsWithAccessClass: (iCalAccessClass) accessClass
forUser: (NSString *) uid;
return logger;
}
-- (BOOL) folderIsMandatory
-{
- return YES;
-}
-
/* selection */
- (NSArray *) calendarUIDs
privacySqlString = @"and (c_isopaque = 1)";
else
{
-#warning we do not manage all the user's possible emails
+#warning we do not manage all the possible user emails
email = [[activeUser primaryIdentity] objectForKey: @"email"];
privacySqlString
component: _component];
}
-
- (NSArray *) fetchFreeBusyInfosFrom: (NSCalendarDate *) _startDate
to: (NSCalendarDate *) _endDate
{
/* Note: can return NSNull objects in the array! */
NSMutableArray *folders;
NSEnumerator *e;
- NSString *uid;
-
+ NSString *uid, *ownerLogin;
+ id folder;
+
+ ownerLogin = [self ownerInContext: context];
+
if ([_uids count] == 0) return nil;
folders = [NSMutableArray arrayWithCapacity:16];
e = [_uids objectEnumerator];
- while ((uid = [e nextObject])) {
- id folder;
-
- folder = [self lookupCalendarFolderForUID: uid];
- if (![folder isNotNull])
- [self logWithFormat:@"Note: did not find folder for uid: '%@'", uid];
+ while ((uid = [e nextObject]))
+ {
+ if ([uid isEqualToString: ownerLogin])
+ folder = self;
+ else
+ {
+ folder = [self lookupCalendarFolderForUID: uid];
+ if (![folder isNotNull])
+ [self logWithFormat:@"Note: did not find folder for uid: '%@'", uid];
+ }
- /* Note: intentionally add 'null' folders to allow a mapping */
- [folders addObject:folder ? folder : [NSNull null]];
- }
+ [folders addObject: folder];
+ }
+
return folders;
}
return events;
}
-#warning We only support ONE calendar per user at this time
-- (BOOL) _appendSubscribedFolders: (NSDictionary *) subscribedFolders
- toFolderList: (NSMutableArray *) calendarFolders
-{
- NSEnumerator *keys;
- NSString *currentKey;
- NSMutableDictionary *currentCalendar;
- BOOL firstShouldBeActive;
- unsigned int count;
-
- firstShouldBeActive = YES;
-
- keys = [[subscribedFolders allKeys] objectEnumerator];
- currentKey = [keys nextObject];
- count = 1;
- while (currentKey)
- {
- 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;
-}
+// #warning We only support ONE calendar per user at this time
+// - (BOOL) _appendSubscribedFolders: (NSDictionary *) subscribedFolders
+// toFolderList: (NSMutableArray *) calendarFolders
+// {
+// NSEnumerator *keys;
+// NSString *currentKey;
+// NSMutableDictionary *currentCalendar;
+// BOOL firstShouldBeActive;
+// unsigned int count;
+
+// firstShouldBeActive = YES;
+
+// keys = [[subscribedFolders allKeys] objectEnumerator];
+// currentKey = [keys nextObject];
+// count = 1;
+// while (currentKey)
+// {
+// 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;
+// }
-- (NSArray *) calendarFolders
-{
- NSMutableDictionary *userCalendar, *calendarDict;
- NSMutableArray *calendarFolders;
- SOGoUser *calendarUser;
- BOOL firstActive;
-
- calendarFolders = [NSMutableArray new];
- [calendarFolders autorelease];
-
- calendarUser = [SOGoUser userWithLogin: [self ownerInContext: context]
- roles: nil];
- userCalendar = [NSMutableDictionary new];
- [userCalendar autorelease];
- [userCalendar setObject: @"/" forKey: @"folder"];
- [userCalendar setObject: @"Calendar" forKey: @"displayName"];
- [calendarFolders addObject: userCalendar];
-
- calendarDict = [[calendarUser userSettings] objectForKey: @"Calendar"];
- firstActive = [[calendarDict objectForKey: @"activateUserFolder"] boolValue];
- firstActive = ([self _appendSubscribedFolders:
- [calendarDict objectForKey: @"SubscribedFolders"]
- toFolderList: calendarFolders]
- || firstActive);
- [userCalendar setObject: [NSNumber numberWithBool: firstActive]
- forKey: @"active"];
-
- return calendarFolders;
-}
+// - (NSArray *) calendarFolders
+// {
+// NSMutableDictionary *userCalendar, *calendarDict;
+// NSMutableArray *calendarFolders;
+// SOGoUser *calendarUser;
+// BOOL firstActive;
+
+// calendarFolders = [NSMutableArray new];
+// [calendarFolders autorelease];
+
+// calendarUser = [SOGoUser userWithLogin: [self ownerInContext: context]
+// roles: nil];
+// userCalendar = [NSMutableDictionary new];
+// [userCalendar autorelease];
+// [userCalendar setObject: @"/" forKey: @"folder"];
+// [userCalendar setObject: @"Calendar" forKey: @"displayName"];
+// [calendarFolders addObject: userCalendar];
+
+// calendarDict = [[calendarUser userSettings] objectForKey: @"Calendar"];
+// firstActive = [[calendarDict objectForKey: @"activateUserFolder"] boolValue];
+// firstActive = ([self _appendSubscribedFolders:
+// [calendarDict objectForKey: @"SubscribedFolders"]
+// toFolderList: calendarFolders]
+// || firstActive);
+// [userCalendar setObject: [NSNumber numberWithBool: firstActive]
+// forKey: @"active"];
+
+// return calendarFolders;
+// }
// - (NSArray *) fetchContentObjectNames
// {
return @"IPF.Appointment";
}
-/* hack until we permit more than 1 cal per user */
-- (NSArray *) _fixedPath: (NSArray *) objectPath
+- (BOOL) isActive
{
- NSMutableArray *newPath;
+ NSUserDefaults *settings;
+ NSArray *activeFolders;
- newPath = [NSMutableArray arrayWithArray: objectPath];
- if ([newPath count] > 2)
- {
- if (![[newPath objectAtIndex: 2] isEqualToString: @"personal"])
- [newPath insertObject: @"personal" atIndex: 2];
- }
- else
- [newPath addObject: @"personal"];
-
- return newPath;
-}
+ settings = [[context activeUser] userSettings];
+ activeFolders
+ = [[settings objectForKey: @"Calendar"] objectForKey: @"ActiveFolders"];
-- (NSArray *) aclUsersForObjectAtPath: (NSArray *) objectPathArray
-{
- return [super aclUsersForObjectAtPath: [self _fixedPath: objectPathArray]];
-}
-
-- (NSArray *) aclsForUser: (NSString *) uid
- forObjectAtPath: (NSArray *) objectPathArray
-{
- return [super aclsForUser: uid
- forObjectAtPath: [self _fixedPath: objectPathArray]];
-}
-
-- (void) setRoles: (NSArray *) roles
- forUser: (NSString *) uid
- forObjectAtPath: (NSArray *) objectPathArray
-{
- [super setRoles: roles
- forUser: uid
- forObjectAtPath: [self _fixedPath: objectPathArray]];
-}
-
-- (void) removeAclsForUsers: (NSArray *) users
- forObjectAtPath: (NSArray *) objectPathArray
-{
- [super removeAclsForUsers: users
- forObjectAtPath: [self _fixedPath: objectPathArray]];
+ return [activeFolders containsObject: nameInContainer];
}
@end /* SOGoAppointmentFolder */
@interface SOGoAppointmentObject : SOGoCalendarComponent
-/* folder management */
-
-- (id) lookupHomeFolderForUID: (NSString *) _uid
- inContext: (id) _ctx;
-- (NSArray *) lookupCalendarFoldersForUIDs: (NSArray *) _uids
- inContext: (id) _ctx;
-
/* "iCal multifolder saves" */
- (NSException *) saveContentString: (NSString *) _iCal
#import <SoObjects/SOGo/SOGoPermissions.h>
#import "NSArray+Appointments.h"
+#import "SOGoAppointmentFolder.h"
+
#import "SOGoAppointmentObject.h"
@implementation SOGoAppointmentObject
return uids;
}
-/* folder management */
-
-- (id)lookupHomeFolderForUID:(NSString *)_uid inContext:(id)_ctx {
- // TODO: what does this do? lookup the home of the organizer?
- return [[self container] lookupHomeFolderForUID:_uid inContext:_ctx];
-}
-- (NSArray *)lookupCalendarFoldersForUIDs:(NSArray *)_uids inContext:(id)_ctx {
- return [[self container] lookupCalendarFoldersForUIDs:_uids inContext:_ctx];
-}
-
/* store in all the other folders */
- (NSException *) saveContentString: (NSString *) _iCal
id folder;
NSException *allErrors = nil;
- e = [[self lookupCalendarFoldersForUIDs:_uids inContext: context]
- objectEnumerator];
+ e = [[container lookupCalendarFoldersForUIDs:_uids inContext: context]
+ objectEnumerator];
while ((folder = [e nextObject]) != nil) {
NSException *error;
SOGoAppointmentObject *apt;
id folder;
NSException *allErrors = nil;
- e = [[self lookupCalendarFoldersForUIDs:_uids inContext: context]
- objectEnumerator];
+ e = [[container lookupCalendarFoldersForUIDs:_uids inContext: context]
+ objectEnumerator];
while ((folder = [e nextObject])) {
NSException *error;
SOGoAppointmentObject *apt;
@interface SOGoTaskObject : SOGoCalendarComponent
-/* folder management */
-
-- (id) lookupHomeFolderForUID: (NSString *) _uid
- inContext: (id) _ctx;
-- (NSArray *) lookupCalendarFoldersForUIDs: (NSArray *) _uids
- inContext: (id) _ctx;
-
/* "iCal multifolder saves" */
- (NSException *) saveContentString: (NSString *) _iCal
#import "NSArray+Appointments.h"
#import "SOGoAptMailNotification.h"
+#import "SOGoAppointmentFolder.h"
#import "SOGoTaskObject.h"
return uids;
}
-/* folder management */
-
-- (id)lookupHomeFolderForUID:(NSString *)_uid inContext:(id)_ctx {
- // TODO: what does this do? lookup the home of the organizer?
- return [[self container] lookupHomeFolderForUID:_uid inContext:_ctx];
-}
-
-- (NSArray *)lookupCalendarFoldersForUIDs:(NSArray *)_uids inContext:(id)_ctx {
- return [[self container] lookupCalendarFoldersForUIDs:_uids inContext:_ctx];
-}
-
/* store in all the other folders */
- (NSException *)saveContentString:(NSString *)_iCal inUIDs:(NSArray *)_uids {
id folder;
NSException *allErrors = nil;
- e = [[self lookupCalendarFoldersForUIDs: _uids inContext: context]
+ e = [[container lookupCalendarFoldersForUIDs: _uids inContext: context]
objectEnumerator];
while ((folder = [e nextObject]) != nil) {
NSException *error;
id folder;
NSException *allErrors = nil;
- e = [[self lookupCalendarFoldersForUIDs: _uids inContext: context]
+ e = [[container lookupCalendarFoldersForUIDs: _uids inContext: context]
objectEnumerator];
while ((folder = [e nextObject])) {
NSException *error;
};
classes = {
+ SOGoAppointmentFolder = {
+ superclass = "SOGoParentFolder";
+ };
SOGoAppointmentFolder = {
superclass = "SOGoFolder";
defaultRoles = {
--- /dev/null
+"Personal Address Book" = "Personal Address Book";
--- /dev/null
+"Personal Address Book" = "Carnet d'adresses personnel";
--- /dev/null
+"Personal Calendar" = "Personal Calendar";
@protocol SOGoContactFolder <NSObject>
-+ (id <SOGoContactFolder>) contactFolderWithName: (NSString *) aName
- andDisplayName: (NSString *) aDisplayName
- inContainer: (SOGoObject *) aContainer;
-
-- (id <SOGoContactFolder>) initWithName: (NSString *) aName
- andDisplayName: (NSString *) aDisplayName
- inContainer: (SOGoObject *) aContainer;
-
-- (NSString *) displayName;
-
- (NSArray *) lookupContactsWithFilter: (NSString *) filter
sortBy: (NSString *) sortKey
ordering: (NSComparisonResult) sortOrdering;
/* SOGoContactFolders.h - this file is part of SOGo
*
- * Copyright (C) 2006 Inverse groupe conseil
+ * Copyright (C) 2006, 2007 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
#ifndef SOGOCONTACTFOLDERS_H
#define SOGOCONTACTFOLDERS_H
-#import <SOGo/SOGoObject.h>
+#import <SoObjects/SOGo/SOGoParentFolder.h>
-@class NSMutableDictionary;
-@class NSString;
-@class WOResponse;
-
-@interface SOGoContactFolders : SOGoObject
-{
- NSMutableDictionary *contactFolders;
- NSString *OCSPath;
-}
-
-- (NSString *) defaultSourceName;
-
-- (void) setBaseOCSPath: (NSString *) newOCSPath;
-
-- (NSArray *) contactFolders;
-
-- (WOResponse *) newFolderWithName: (NSString *) name;
+@interface SOGoContactFolders : SOGoParentFolder
@end
/* SOGoContactFolders.m - this file is part of SOGo
*
- * Copyright (C) 2006 Inverse groupe conseil
+ * Copyright (C) 2006, 2007 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* Boston, MA 02111-1307, USA.
*/
-/* exchange folder types: */
/* MailItems IPF.Note
ContactItems IPF.Contact
AppointmentItems IPF.Appointment
TaskItems IPF.Task
JournalItems IPF.Journal */
-#import <Foundation/NSDictionary.h>
+#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
-
-#import <NGObjWeb/NSException+HTTP.h>
-#import <NGObjWeb/WOApplication.h>
-#import <NGObjWeb/WOContext.h>
-#import <NGObjWeb/WOContext+SoObjects.h>
-#import <NGObjWeb/WOResponse.h>
-#import <NGObjWeb/SoUser.h>
-
-#import <GDLContentStore/GCSFolderManager.h>
-#import <GDLContentStore/GCSChannelManager.h>
-#import <GDLAccess/EOAdaptorChannel.h>
-#import <GDLContentStore/NSURL+GCS.h>
+#import <Foundation/NSEnumerator.h>
#import <SoObjects/SOGo/LDAPUserManager.h>
-#import <SoObjects/SOGo/SOGoPermissions.h>
#import "SOGoContactGCSFolder.h"
#import "SOGoContactLDAPFolder.h"
@implementation SOGoContactFolders
-- (id) init
-{
- if ((self = [super init]))
- {
- contactFolders = nil;
- OCSPath = nil;
- }
-
- return self;
-}
-
-- (void) dealloc
++ (NSString *) gcsFolderType
{
- if (contactFolders)
- [contactFolders release];
- if (OCSPath)
- [OCSPath release];
- [super dealloc];
-}
-
-- (void) _fetchPersonalFolders: (NSString *) sql
- withChannel: (EOAdaptorChannel *) fc
-{
- NSArray *attrs;
- NSDictionary *row;
- SOGoContactGCSFolder *ab;
- BOOL hasPersonal;
- NSString *key, *path;
-
- hasPersonal = NO;
- [fc evaluateExpressionX: sql];
- attrs = [fc describeResults: NO];
- row = [fc fetchAttributes: attrs withZone: NULL];
- while (row)
- {
- ab = [SOGoContactGCSFolder
- contactFolderWithName: [row objectForKey: @"c_path4"]
- andDisplayName: [row objectForKey: @"c_foldername"]
- inContainer: self];
- key = [row objectForKey: @"c_path4"];
- hasPersonal = (hasPersonal || [key isEqualToString: @"personal"]);
- [ab setOCSPath: [NSString stringWithFormat: @"%@/%@",
- OCSPath, key]];
- [contactFolders setObject: ab forKey: key];
- row = [fc fetchAttributes: attrs withZone: NULL];
- }
-
- if (!hasPersonal)
- {
- ab = [SOGoContactGCSFolder contactFolderWithName: @"personal"
- andDisplayName: @"Contacts"
- inContainer: self];
- path = [NSString stringWithFormat:
- @"/Users/%@/Contacts/personal",
- [self ownerInContext: context]];
- [ab setOCSPath: path];
- [contactFolders setObject: ab forKey: @"personal"];
- }
+ return @"Contact";
}
-- (void) appendPersonalSources
++ (Class) subFolderClass
{
- GCSChannelManager *cm;
- EOAdaptorChannel *fc;
- NSURL *folderLocation;
- NSString *sql;
-
- cm = [GCSChannelManager defaultChannelManager];
- folderLocation
- = [[GCSFolderManager defaultFolderManager] folderInfoLocation];
- fc = [cm acquireOpenChannelForURL: folderLocation];
- if (fc)
- {
- sql = [NSString
- stringWithFormat: (@"SELECT c_path4, c_foldername FROM %@"
- @" WHERE c_path2 = '%@'"
- @" AND c_folder_type = 'Contact'"),
- [folderLocation gcsTableName], [self ownerInContext: context]];
- [self _fetchPersonalFolders: sql withChannel: fc];
- [cm releaseChannel: fc];
-// sql = [sql stringByAppendingFormat:@" WHERE %@ = '%@'",
-// uidColumnName, [self uid]];
- }
+ return [SOGoContactGCSFolder class];
}
- (void) appendSystemSources
while (currentSourceID)
{
displayName = [um displayNameForSourceWithID: currentSourceID];
- currentFolder = [SOGoContactLDAPFolder contactFolderWithName: currentSourceID
+ currentFolder = [SOGoContactLDAPFolder folderWithName: currentSourceID
andDisplayName: displayName
inContainer: self];
[currentFolder setLDAPSource: [um sourceWithID: currentSourceID]];
- [contactFolders setObject: currentFolder forKey: currentSourceID];
+ [subFolders setObject: currentFolder forKey: currentSourceID];
currentSourceID = [sourceIDs nextObject];
}
}
-- (WOResponse *) newFolderWithName: (NSString *) name
-{
- SOGoContactGCSFolder *newFolder;
- WOResponse *response;
-
- newFolder = [SOGoContactGCSFolder contactFolderWithName: name
- andDisplayName: name
- inContainer: self];
- if ([newFolder isKindOfClass: [NSException class]])
- response = (WOResponse *) newFolder;
- else
- {
- [newFolder setOCSPath: [NSString stringWithFormat: @"%@/%@",
- OCSPath, name]];
- if ([newFolder create])
- {
- response = [WOResponse new];
- [response setStatus: 201];
- [response autorelease];
- }
- else
- response = [NSException exceptionWithHTTPStatus: 400
- reason: @"The new folder could not be created"];
- }
-
- return response;
-}
-
-- (void) initContactSources
-{
- if (!contactFolders)
- {
- contactFolders = [NSMutableDictionary new];
- [self appendPersonalSources];
- [self appendSystemSources];
- }
-}
-
-- (id) lookupName: (NSString *) name
- inContext: (WOContext *) lookupContext
- acquire: (BOOL) acquire
-{
- id obj;
-
- /* first check attributes directly bound to the application */
- obj = [super lookupName: name inContext: lookupContext acquire: NO];
- if (!obj)
- {
- if (!contactFolders)
- [self initContactSources];
-
- obj = [contactFolders objectForKey: name];
- if (!obj)
- obj = [NSException exceptionWithHTTPStatus: 404];
- }
-
- return obj;
-}
-
-- (NSArray *) toManyRelationshipKeys
-{
- if (!contactFolders)
- [self initContactSources];
-
- return [contactFolders allKeys];
-}
-
-- (NSArray *) contactFolders
-{
- if (!contactFolders)
- [self initContactSources];
-
- return [contactFolders allValues];
-}
-
-/* acls */
-- (NSArray *) aclsForUser: (NSString *) uid
-{
- return nil;
-}
-
-- (BOOL) davIsCollection
-{
- return YES;
-}
-
-- (NSString *) davContentType
-{
- return @"httpd/unix-directory";
-}
-
-- (void) setBaseOCSPath: (NSString *) newOCSPath
-{
- if (OCSPath)
- [OCSPath release];
- OCSPath = newOCSPath;
- if (OCSPath)
- [OCSPath retain];
-}
-
-/* web interface */
-- (NSString *) defaultSourceName
+- (NSString *) defaultFolderName
{
- return @"personal";
+ return @"Personal Address Book";
}
@end
@class NSString;
@interface SOGoContactGCSFolder : SOGoFolder <SOGoContactFolder>
-{
- NSString *displayName;
-}
@end
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
+
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/SoObject+SoDAV.h>
#import <NGObjWeb/WOContext.h>
@implementation SOGoContactGCSFolder
-+ (id <SOGoContactFolder>) contactFolderWithName: (NSString *) aName
- andDisplayName: (NSString *) aDisplayName
- inContainer: (SOGoObject *) aContainer
-{
- SOGoContactGCSFolder *folder;
-
- folder = [[self alloc] initWithName: aName
- andDisplayName: aDisplayName
- inContainer: aContainer];
- [folder autorelease];
-
- return folder;
-}
-
-- (void) dealloc
-{
- [displayName release];
- [super dealloc];
-}
-
-- (id <SOGoContactFolder>) initWithName: (NSString *) newName
- andDisplayName: (NSString *) newDisplayName
- inContainer: (SOGoObject *) newContainer
-{
- if ((self = [self initWithName: newName
- inContainer: newContainer]))
- ASSIGN (displayName, newDisplayName);
-
- return self;
-}
-
-- (BOOL) folderIsMandatory
-{
- return [nameInContainer isEqualToString: @"personal"];
-}
-
-- (NSString *) displayName
-{
- return displayName;
-}
-
/* name lookup */
- (id <SOGoContactObject>) lookupContactWithId: (NSString *) recordId
BOOL isPut;
isPut = NO;
- /* first check attributes directly bound to the application */
obj = [super lookupName:_key inContext:_ctx acquire:NO];
if (!obj)
{
return @"vcard-collection";
}
-- (NSException *) delete
-{
- return (([nameInContainer isEqualToString: @"personal"])
- ? [NSException exceptionWithHTTPStatus: 403
- reason: @"the 'personal' folder cannot be deleted"]
- : [super delete]);
-}
-
// /* GET */
// - (id) GETAction: (id)_ctx
BOOL ignoreSoObjectHunger;
}
-- (id <SOGoContactFolder>) initWithName: (NSString *) newName
- andDisplayName: (NSString *) newDisplayName
- inContainer: (SOGoObject *) newContainer;
++ (id) folderWithName: (NSString *) aName
+ andDisplayName: (NSString *) aDisplayName
+ inContainer: (id) aContainer;
+- (id) initWithName: (NSString *) newName
+ andDisplayName: (NSString *) newDisplayName
+ inContainer: (id) newContainer;
- (void) setLDAPSource: (LDAPSource *) newLdapSource;
@end
@implementation SOGoContactLDAPFolder
-+ (id <SOGoContactFolder>) contactFolderWithName: (NSString *) aName
- andDisplayName: (NSString *) aDisplayName
- inContainer: (SOGoObject *) aContainer
++ (id) folderWithName: (NSString *) aName
+ andDisplayName: (NSString *) aDisplayName
+ inContainer: (id) aContainer
{
- SOGoContactLDAPFolder *folder;
+ id folder;
folder = [[self alloc] initWithName: aName
andDisplayName: aDisplayName
return self;
}
-- (id <SOGoContactFolder>) initWithName: (NSString *) newName
- andDisplayName: (NSString *) newDisplayName
- inContainer: (SOGoObject *) newContainer
+- (id) initWithName: (NSString *) newName
+ andDisplayName: (NSString *) newDisplayName
+ inContainer: (id) newContainer
{
if ((self = [self initWithName: newName
inContainer: newContainer]))
}
/* acls */
+- (NSString *) ownerInContext: (WOContext *) noContext
+{
+ return @"nobody";
+}
+
/* TODO: this might change one day when we support LDAP acls */
- (NSArray *) aclsForUser: (NSString *) uid
{
classes = {
SOGoContactFolders = {
- superclass = "SOGoFolder";
- protectedBy = "Access Contents Information";
- defaultRoles = {
- "Access Contents Information" = ( "Authenticated" );
- "WebDAV Access" = ( "Authenticated" );
- };
+ superclass = "SOGoParentFolder";
};
SOGoContactGCSFolder = {
superclass = "SOGoFolder";
libSOGo_HEADER_FILES = \
SOGoObject.h \
- SOGoFolder.h \
SOGoContentObject.h \
+ SOGoFolder.h \
+ SOGoParentFolder.h \
SOGoUserFolder.h \
SOGoGroupsFolder.h \
SOGoGroupFolder.h \
libSOGo_OBJC_FILES = \
SOGoObject.m \
- SOGoFolder.m \
SOGoContentObject.m \
+ SOGoFolder.m \
+ SOGoParentFolder.m \
SOGoUserFolder.m \
SOGoGroupsFolder.m \
SOGoGroupFolder.m \
@interface NSDictionary (SOGoDictionaryUtilities)
++ (NSDictionary *) dictionaryFromStringsFile: (NSString *) file;
+
- (NSString *) jsonRepresentation;
- (NSString *) keysWithFormat: (NSString *) keyFormat;
*/
#import <Foundation/NSArray.h>
+#import <Foundation/NSData.h>
#import <Foundation/NSString.h>
#import "NSArray+Utilities.h"
@implementation NSDictionary (SOGoDictionaryUtilities)
++ (NSDictionary *) dictionaryFromStringsFile: (NSString *) file
+{
+ NSString *serialized;
+ NSMutableData *content;
+ NSDictionary *newDictionary;
+
+ content = [NSMutableData new];
+ [content appendBytes: "{" length: 1];
+ [content appendData: [NSData dataWithContentsOfFile: file]];
+ [content appendBytes: "}" length: 1];
+ serialized = [[NSString alloc] initWithData: content
+ encoding: NSUTF8StringEncoding];
+ [content release];
+ newDictionary = [serialized propertyList];
+ [serialized release];
+
+ return newDictionary;
+}
+
- (NSString *) jsonRepresentation
{
NSMutableArray *values;
needsLocation = NO;
tmp = [[self nameInContainer] stringByDeletingPathExtension];
if ([tmp isEqualToString:@"new"]) {
- tmp = [[[self container] class] globallyUniqueObjectId];
+ tmp = [self globallyUniqueObjectId];
needsLocation = YES;
[self debugWithFormat:
- (NSArray *) aclUsers
{
- return [container aclUsersForObjectAtPath: [self pathArrayToSoObject]];
+ return [container aclUsersForObjectAtPath: [self pathArrayToSOGoObject]];
}
- (NSArray *) aclsForUser: (NSString *) uid
acls = [NSMutableArray array];
ownAcls = [container aclsForUser: uid
- forObjectAtPath: [self pathArrayToSoObject]];
+ forObjectAtPath: [self pathArrayToSOGoObject]];
[acls addObjectsFromArray: ownAcls];
containerAcls = [container aclsForUser: uid];
if ([containerAcls count] > 0)
@interface SOGoFolder : SOGoObject
{
- NSString *ocsPath;
+ NSMutableString *displayName;
+ NSString *ocsPath;
GCSFolder *ocsFolder;
NSMutableDictionary *aclCache;
}
-+ (NSString *) globallyUniqueObjectId;
++ (id) folderWithSubscriptionReference: (NSString *) reference
+ inContainer: (id) aContainer;
/* accessors */
+- (void) setDisplayName: (NSString *) newDisplayName;
+- (NSString *) displayName;
+
- (void) setOCSPath: (NSString *)_Path;
- (NSString *) ocsPath;
- (NSString *) outlookFolderClass;
- (BOOL) folderIsMandatory;
+- (NSString *) folderType;
- (BOOL) create;
- (NSException *) delete;
-
+- (void) renameTo: (NSString *) newName;
/* dav */
- (NSArray *) davNamespaces;
02111-1307, USA.
*/
-#import <unistd.h>
-#import <stdlib.h>
-
#import <Foundation/NSArray.h>
#import <Foundation/NSDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSURL.h>
+#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/SoObject.h>
#import <NGObjWeb/SoObject+SoDAV.h>
#import <NGObjWeb/SoSelectorInvocation.h>
#import <NGExtensions/NSObject+Logs.h>
#import <EOControl/EOQualifier.h>
#import <GDLAccess/EOAdaptorChannel.h>
+#import <GDLContentStore/GCSChannelManager.h>
#import <GDLContentStore/GCSFolderManager.h>
#import <GDLContentStore/GCSFolder.h>
#import <GDLContentStore/GCSFolderType.h>
+#import <GDLContentStore/NSURL+GCS.h>
#import <SaxObjC/XMLNamespaces.h>
#import "NSArray+Utilities.h"
NSStringFromClass([self superclass]), [super version]);
}
-+ (NSString *) globallyUniqueObjectId
++ (id) folderWithSubscriptionReference: (NSString *) reference
+ inContainer: (id) aContainer
{
- /*
- 4C08AE1A-A808-11D8-AC5A-000393BBAFF6
- SOGo-Web-28273-18283-288182
- printf( "%x", *(int *) &f);
- */
- static int pid = 0;
- static int sequence = 0;
- static float rndm = 0;
- float f;
-
- if (pid == 0)
- { /* break if we fork ;-) */
- pid = getpid();
- rndm = random();
- }
- sequence++;
- f = [[NSDate date] timeIntervalSince1970];
- return [NSString stringWithFormat:@"%0X-%0X-%0X-%0X",
- pid, *(int *)&f, sequence++, random];
+ id newFolder;
+ NSArray *elements, *pathElements;
+ NSString *ocsPath, *objectPath, *owner, *ocsName, *folderName;
+
+ elements = [reference componentsSeparatedByString: @":"];
+ owner = [elements objectAtIndex: 0];
+ objectPath = [elements objectAtIndex: 1];
+ pathElements = [objectPath componentsSeparatedByString: @"/"];
+ if ([pathElements count] > 1)
+ ocsName = [pathElements objectAtIndex: 1];
+ else
+ ocsName = @"personal";
+
+ ocsPath = [NSString stringWithFormat: @"/Users/%@/%@/%@",
+ owner, [pathElements objectAtIndex: 0], ocsName];
+ folderName = [NSString stringWithFormat: @"%@_%@", owner, ocsName];
+ newFolder = [[self alloc] initWithName: folderName
+ inContainer: aContainer];
+ [newFolder setOCSPath: ocsPath];
+ [newFolder setOwner: owner];
+
+ return newFolder;
}
- (id) init
{
if ((self = [super init]))
{
+ displayName = nil;
ocsPath = nil;
ocsFolder = nil;
aclCache = [NSMutableDictionary new];
[ocsFolder release];
[ocsPath release];
[aclCache release];
+ [displayName release];
[super dealloc];
}
- (void) setOCSPath: (NSString *) _path
{
- if ([ocsPath isEqualToString:_path])
- return;
-
- if (ocsPath)
- [self warnWithFormat:@"GCS path is already set! '%@'", _path];
-
- ASSIGNCOPY(ocsPath, _path);
+ if (![ocsPath isEqualToString:_path])
+ {
+ if (ocsPath)
+ [self warnWithFormat: @"GCS path is already set! '%@'", _path];
+ ASSIGN (ocsPath, _path);
+ }
}
- (NSString *) ocsPath
- (BOOL) folderIsMandatory
{
- [self subclassResponsibility: _cmd];
+ return [nameInContainer isEqualToString: @"personal"];
+}
+
+- (void) _setDisplayNameFromRow: (NSDictionary *) row
+{
+ NSString *currentLogin, *ownerLogin;
+ NSDictionary *ownerIdentity;
- return NO;
+ displayName
+ = [NSMutableString stringWithString: [row objectForKey: @"c_foldername"]];
+ currentLogin = [[context activeUser] login];
+ ownerLogin = [self ownerInContext: context];
+ if (![currentLogin isEqualToString: ownerLogin])
+ {
+ ownerIdentity = [[SOGoUser userWithLogin: ownerLogin roles: nil]
+ primaryIdentity];
+ [displayName appendFormat: @" (%@ <%@>)",
+ [ownerIdentity objectForKey: @"fullName"],
+ [ownerIdentity objectForKey: @"email"]];
+ }
+}
+
+- (void) _fetchDisplayName
+{
+ GCSChannelManager *cm;
+ EOAdaptorChannel *fc;
+ NSURL *folderLocation;
+ NSString *sql;
+ NSArray *attrs;
+ NSDictionary *row;
+
+ cm = [GCSChannelManager defaultChannelManager];
+ folderLocation
+ = [[GCSFolderManager defaultFolderManager] folderInfoLocation];
+ fc = [cm acquireOpenChannelForURL: folderLocation];
+ if (fc)
+ {
+ sql
+ = [NSString stringWithFormat: (@"SELECT c_foldername FROM %@"
+ @" WHERE c_path = '%@'"),
+ [folderLocation gcsTableName], ocsPath];
+ [fc evaluateExpressionX: sql];
+ attrs = [fc describeResults: NO];
+ row = [fc fetchAttributes: attrs withZone: NULL];
+ if (row)
+ [self _setDisplayNameFromRow: row];
+ [fc cancelFetch];
+ [cm releaseChannel: fc];
+ }
+}
+
+- (void) setDisplayName: (NSString *) newDisplayName
+{
+ ASSIGN (displayName, newDisplayName);
+}
+
+- (NSString *) displayName
+{
+ if (!displayName)
+ [self _fetchDisplayName];
+
+ return displayName;
+}
+
+- (NSString *) davDisplayName
+{
+ return [self displayName];
}
- (GCSFolder *) ocsFolder
{
NSException *result;
+// [self dieHard];
result = [[self folderManager] createFolderOfType: [self folderType]
+ withName: displayName
atPath: ocsPath];
return (result == nil);
- (NSException *) delete
{
- return [[self folderManager] deleteFolderAtPath: ocsPath];
+ NSException *error;
+
+ if ([nameInContainer isEqualToString: @"personal"])
+ error = [NSException exceptionWithHTTPStatus: 403
+ reason: @"folder 'personal' cannot be deleted"];
+ else
+ error = [[self folderManager] deleteFolderAtPath: ocsPath];
+
+ return error;
+}
+
+- (void) renameTo: (NSString *) newName
+{
+ GCSChannelManager *cm;
+ EOAdaptorChannel *fc;
+ NSURL *folderLocation;
+ NSString *sql;
+
+ [displayName release];
+ displayName = nil;
+
+ cm = [GCSChannelManager defaultChannelManager];
+ folderLocation
+ = [[GCSFolderManager defaultFolderManager] folderInfoLocation];
+ fc = [cm acquireOpenChannelForURL: folderLocation];
+ if (fc)
+ {
+ sql
+ = [NSString stringWithFormat: (@"UPDATE %@ SET c_foldername = '%@'"
+ @" WHERE c_path = '%@'"),
+ [folderLocation gcsTableName], newName, ocsPath];
+ [fc evaluateExpressionX: sql];
+ [cm releaseChannel: fc];
+// sql = [sql stringByAppendingFormat:@" WHERE %@ = '%@'",
+// uidColumnName, [self uid]];
+ }
}
- (NSArray *) fetchContentObjectNames
/* acls */
- (NSArray *) aclUsers
{
- return [self aclUsersForObjectAtPath: [self pathArrayToSoObject]];
+ return [self aclUsersForObjectAtPath: [self pathArrayToSOGoObject]];
}
- (NSArray *) aclsForUser: (NSString *) uid
acls = [NSMutableArray array];
ownAcls = [self aclsForUser: uid
- forObjectAtPath: [self pathArrayToSoObject]];
+ forObjectAtPath: [self pathArrayToSOGoObject]];
[acls addObjectsFromArray: ownAcls];
if ([container respondsToSelector: @selector (aclsForUser:)])
{
{
return [self setRoles: roles
forUser: uid
- forObjectAtPath: [self pathArrayToSoObject]];
+ forObjectAtPath: [self pathArrayToSOGoObject]];
}
- (void) removeAclsForUsers: (NSArray *) users
{
return [self removeAclsForUsers: users
- forObjectAtPath: [self pathArrayToSoObject]];
+ forObjectAtPath: [self pathArrayToSOGoObject]];
}
- (NSString *) defaultUserID
id container;
}
++ (NSString *) globallyUniqueObjectId;
+- (NSString *) globallyUniqueObjectId;
+
+ (id) objectWithName: (NSString *)_name inContainer:(id)_container;
- (id) initWithName: (NSString *) _name inContainer:(id)_container;
- (NSString *) nameInContainer;
- (id) container;
+- (NSArray *) pathArrayToSOGoObject;
+
- (NSURL *) davURL;
- (NSURL *) soURL;
- (NSURL *) soURLToBaseContainerForUser: (NSString *) uid;
- (NSURL *) soURLToBaseContainerForCurrentUser;
+- (NSString *) labelForKey: (NSString *) key;
+
/* ownership */
- (void) setOwner: (NSString *) newOwner;
/* etag support */
-- (NSException *)matchesRequestConditionInContext:(id)_ctx;
+- (NSException *) matchesRequestConditionInContext:(id)_ctx;
/* acls */
Please use gnustep-base instead.
#endif
+#import <unistd.h>
+
+#import <Foundation/NSBundle.h>
#import <Foundation/NSClassDescription.h>
#import <Foundation/NSString.h>
#import <Foundation/NSUserDefaults.h>
#import <NGObjWeb/WEClientCapabilities.h>
#import <NGObjWeb/WOApplication.h>
#import <NGObjWeb/WOContext.h>
+#import <NGObjWeb/WOResourceManager.h>
#import <NGObjWeb/WOResponse.h>
#import <NGObjWeb/WORequest.h>
#import <NGObjWeb/WORequest+So.h>
#import "SOGoDAVRendererTypes.h"
#import "NSArray+Utilities.h"
+#import "NSDictionary+Utilities.h"
#import "NSString+Utilities.h"
#import "SOGoObject.h"
// asDefaultForPermission: SoPerm_WebDAVAccess];
}
++ (NSString *) globallyUniqueObjectId
+{
+ /*
+ 4C08AE1A-A808-11D8-AC5A-000393BBAFF6
+ SOGo-Web-28273-18283-288182
+ printf( "%x", *(int *) &f);
+ */
+ static int pid = 0;
+ static int sequence = 0;
+ static float rndm = 0;
+ float f;
+
+ if (pid == 0)
+ { /* break if we fork ;-) */
+ pid = getpid();
+ rndm = random();
+ }
+ sequence++;
+ f = [[NSDate date] timeIntervalSince1970];
+
+ return [NSString stringWithFormat:@"%0X-%0X-%0X-%0X",
+ pid, (int) f, sequence++, random];
+}
+
+- (NSString *) globallyUniqueObjectId
+{
+ return [[self class] globallyUniqueObjectId];
+}
+
+ (void) _fillDictionary: (NSMutableDictionary *) dictionary
withDAVMethods: (NSString *) firstMethod, ...
{
return container;
}
+- (NSArray *) pathArrayToSOGoObject
+{
+ NSMutableArray *realPathArray;
+ NSString *objectName;
+ NSArray *objectDescription;
+
+ realPathArray
+ = [NSMutableArray arrayWithArray: [self pathArrayToSoObject]];
+ if ([realPathArray count] > 2)
+ {
+ objectName = [realPathArray objectAtIndex: 2];
+ objectDescription = [objectName componentsSeparatedByString: @"_"];
+ if ([objectDescription count] > 1)
+ {
+ [realPathArray replaceObjectAtIndex: 0
+ withObject: [objectDescription objectAtIndex: 0]];
+ [realPathArray replaceObjectAtIndex: 2
+ withObject: [objectDescription objectAtIndex: 1]];
+ }
+ }
+
+ return realPathArray;
+}
+
/* ownership */
- (void) setOwner: (NSString *) newOwner
/* looking up shared objects */
-- (SOGoUserFolder *)lookupUserFolder {
+- (SOGoUserFolder *) lookupUserFolder
+{
if (![container respondsToSelector:_cmd])
return nil;
return [container lookupUserFolder];
}
-- (SOGoGroupsFolder *)lookupGroupsFolder {
+- (SOGoGroupsFolder *) lookupGroupsFolder
+{
return [[self lookupUserFolder] lookupGroupsFolder];
}
return nil;
}
+- (NSString *) labelForKey: (NSString *) key
+{
+ NSString *userLanguage, *label;
+ NSArray *paths;
+ NSBundle *bundle;
+ NSDictionary *strings;
+
+ bundle = [NSBundle bundleForClass: [self class]];
+ if (!bundle)
+ bundle = [NSBundle mainBundle];
+
+ userLanguage = [[context activeUser] language];
+ paths = [bundle pathsForResourcesOfType: @"strings"
+ inDirectory: [NSString stringWithFormat: @"%@.lproj", userLanguage]
+ forLocalization: userLanguage];
+ if ([paths count] > 0)
+ {
+ strings = [NSDictionary dictionaryFromStringsFile: [paths objectAtIndex: 0]];
+ label = [strings objectForKey: key];
+ if (!label)
+ label = key;
+ }
+ else
+ label = key;
+
+ return label;
+}
+
/* description */
- (void)appendAttributesToDescription:(NSMutableString *)_ms {
--- /dev/null
+/* SOGoParentFolder.h - this file is part of SOGo
+ *
+ * Copyright (C) 2006, 2007 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * 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 SOGOPARENTFOLDERS_H
+#define SOGOPARENTFOLDERS_H
+
+#import "SOGoObject.h"
+
+@class NSMutableDictionary;
+@class NSString;
+@class WOResponse;
+
+@interface SOGoParentFolder : SOGoObject
+{
+ NSMutableDictionary *subFolders;
+ NSString *OCSPath;
+ Class subFolderClass;
+}
+
++ (NSString *) gcsFolderType;
++ (Class) subFolderClass;
+
+- (void) setBaseOCSPath: (NSString *) newOCSPath;
+
+- (NSArray *) subFolders;
+
+- (NSException *) newFolderWithName: (NSString *) name
+ nameInContainer: (NSString **) newNameInContainer;
+
+@end
+
+#endif /* SOGOPARENTFOLDERS_H */
--- /dev/null
+/* SOGoParentFolder.m - this file is part of SOGo
+ *
+ * Copyright (C) 2006, 2007 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * 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 <Foundation/NSDictionary.h>
+#import <Foundation/NSString.h>
+#import <Foundation/NSUserDefaults.h>
+
+#import <NGObjWeb/NSException+HTTP.h>
+#import <NGObjWeb/WOContext+SoObjects.h>
+#import <GDLContentStore/GCSChannelManager.h>
+#import <GDLContentStore/GCSFolderManager.h>
+#import <GDLContentStore/NSURL+GCS.h>
+#import <GDLAccess/EOAdaptorChannel.h>
+
+#import "SOGoFolder.h"
+#import "SOGoUser.h"
+
+#import "SOGoParentFolder.h"
+
+@implementation SOGoParentFolder
+
+- (id) init
+{
+ if ((self = [super init]))
+ {
+ subFolders = nil;
+ OCSPath = nil;
+ subFolderClass = Nil;
+ }
+
+ return self;
+}
+
+- (void) dealloc
+{
+ [subFolders release];
+ [OCSPath release];
+ [super dealloc];
+}
+
++ (Class) subFolderClass
+{
+ [self subclassResponsibility: _cmd];
+
+ return Nil;
+}
+
++ (NSString *) gcsFolderType
+{
+ [self subclassResponsibility: _cmd];
+
+ return nil;
+}
+
+- (void) setBaseOCSPath: (NSString *) newOCSPath
+{
+ ASSIGN (OCSPath, newOCSPath);
+}
+
+- (NSString *) defaultFolderName
+{
+ return @"Personal";
+}
+
+- (void) _fetchPersonalFolders: (NSString *) sql
+ withChannel: (EOAdaptorChannel *) fc
+{
+ NSArray *attrs;
+ NSDictionary *row;
+ SOGoFolder *folder;
+ BOOL hasPersonal;
+ NSString *key, *path, *personalName;
+
+ if (!subFolderClass)
+ subFolderClass = [[self class] subFolderClass];
+
+ hasPersonal = NO;
+ [fc evaluateExpressionX: sql];
+ attrs = [fc describeResults: NO];
+ row = [fc fetchAttributes: attrs withZone: NULL];
+ while (row)
+ {
+ folder
+ = [subFolderClass objectWithName: [row objectForKey: @"c_path4"]
+ inContainer: self];
+ key = [row objectForKey: @"c_path4"];
+ hasPersonal = (hasPersonal || [key isEqualToString: @"personal"]);
+ [folder setOCSPath: [NSString stringWithFormat: @"%@/%@",
+ OCSPath, key]];
+ [subFolders setObject: folder forKey: key];
+ row = [fc fetchAttributes: attrs withZone: NULL];
+ }
+
+ if (!hasPersonal)
+ {
+ folder = [subFolderClass objectWithName: @"personal" inContainer: self];
+ personalName = [self labelForKey: [self defaultFolderName]];
+ [folder setDisplayName: personalName];
+ path = [NSString stringWithFormat: @"/Users/%@/%@/personal",
+ [self ownerInContext: context],
+ nameInContainer];
+ [folder setOCSPath: path];
+ [subFolders setObject: folder forKey: @"personal"];
+ }
+}
+
+- (void) appendPersonalSources
+{
+ GCSChannelManager *cm;
+ EOAdaptorChannel *fc;
+ NSURL *folderLocation;
+ NSString *sql, *gcsFolderType;
+
+ cm = [GCSChannelManager defaultChannelManager];
+ folderLocation
+ = [[GCSFolderManager defaultFolderManager] folderInfoLocation];
+ fc = [cm acquireOpenChannelForURL: folderLocation];
+ if (fc)
+ {
+ gcsFolderType = [[self class] gcsFolderType];
+
+ sql
+ = [NSString stringWithFormat: (@"SELECT c_path4 FROM %@"
+ @" WHERE c_path2 = '%@'"
+ @" AND c_folder_type = '%@'"),
+ [folderLocation gcsTableName],
+ [self ownerInContext: context],
+ gcsFolderType];
+ [self _fetchPersonalFolders: sql withChannel: fc];
+ [cm releaseChannel: fc];
+// sql = [sql stringByAppendingFormat:@" WHERE %@ = '%@'",
+// uidColumnName, [self uid]];
+ }
+}
+
+- (void) appendSystemSources
+{
+}
+
+- (void) appendSubscribedSources
+{
+ NSArray *subscribedReferences;
+ NSUserDefaults *settings;
+ NSEnumerator *allKeys;
+ NSString *currentKey;
+ SOGoFolder *subscribedFolder;
+
+ settings = [[context activeUser] userSettings];
+ subscribedReferences = [[settings objectForKey: nameInContainer]
+ objectForKey: @"SubscribedFolders"];
+ if ([subscribedReferences isKindOfClass: [NSArray class]])
+ {
+ allKeys = [subscribedReferences objectEnumerator];
+ currentKey = [allKeys nextObject];
+ while (currentKey)
+ {
+ subscribedFolder
+ = [subFolderClass folderWithSubscriptionReference: currentKey
+ inContainer: self];
+ [subFolders setObject: subscribedFolder
+ forKey: [subscribedFolder nameInContainer]];
+ currentKey = [allKeys nextObject];
+ }
+ }
+}
+
+- (NSException *) newFolderWithName: (NSString *) name
+ nameInContainer: (NSString **) newNameInContainer
+{
+ NSString *newFolderID;
+ SOGoFolder *newFolder;
+ NSException *error;
+
+ if (!subFolderClass)
+ subFolderClass = [[self class] subFolderClass];
+
+ *newNameInContainer = nil;
+ newFolderID = [self globallyUniqueObjectId];
+ newFolder = [subFolderClass objectWithName: newFolderID inContainer: self];
+ if ([newFolder isKindOfClass: [NSException class]])
+ error = (NSException *) newFolder;
+ else
+ {
+ [newFolder setDisplayName: name];
+ [newFolder setOCSPath: [NSString stringWithFormat: @"%@/%@",
+ OCSPath, newFolderID]];
+ if ([newFolder create])
+ {
+ error = nil;
+ *newNameInContainer = newFolderID;
+ }
+ else
+ error = [NSException exceptionWithHTTPStatus: 400
+ reason: @"The new folder could not be created"];
+ }
+
+ return error;
+}
+
+- (void) initSubFolders
+{
+ NSString *login;
+
+ if (!subFolders)
+ {
+ subFolders = [NSMutableDictionary new];
+ [self appendPersonalSources];
+ [self appendSystemSources];
+ login = [[context activeUser] login];
+ if ([login isEqualToString: owner])
+ [self appendSubscribedSources];
+ }
+}
+
+- (id) lookupName: (NSString *) name
+ inContext: (WOContext *) lookupContext
+ acquire: (BOOL) acquire
+{
+ id obj;
+
+ /* first check attributes directly bound to the application */
+ obj = [super lookupName: name inContext: lookupContext acquire: NO];
+ if (!obj)
+ {
+ if (!subFolders)
+ [self initSubFolders];
+
+ obj = [subFolders objectForKey: name];
+ }
+
+ return obj;
+}
+
+- (NSArray *) toManyRelationshipKeys
+{
+ if (!subFolders)
+ [self initSubFolders];
+
+ return [subFolders allKeys];
+}
+
+- (NSArray *) subFolders
+{
+ if (!subFolders)
+ [self initSubFolders];
+
+ return [subFolders allValues];
+}
+
+/* acls */
+- (NSArray *) aclsForUser: (NSString *) uid
+{
+ return nil;
+}
+
+- (BOOL) davIsCollection
+{
+ return YES;
+}
+
+- (NSString *) davContentType
+{
+ return @"httpd/unix-directory";
+}
+
+@end
#import <NGObjWeb/SoClassSecurityInfo.h>
#import <NGExtensions/NSObject+Logs.h>
-#import <Appointments/SOGoAppointmentFolder.h>
+#import <Appointments/SOGoAppointmentFolders.h>
#import <Appointments/SOGoFreeBusyObject.h>
#import <Contacts/SOGoContactFolders.h>
#import <Mailer/SOGoMailAccounts.h>
- (NSString *) ocsPrivateCalendarPath
{
- return [[self ocsUserPath] stringByAppendingString:@"/Calendar/personal"];
+ return [[self ocsUserPath] stringByAppendingString:@"/Calendar"];
}
- (NSString *) ocsPrivateContactsPath
// : [super permissionForKey: key]);
// }
-- (SOGoAppointmentFolder *) privateCalendar: (NSString *) _key
- inContext: (WOContext *) _ctx
+- (SOGoAppointmentFolders *) privateCalendars: (NSString *) _key
+ inContext: (WOContext *) _ctx
{
- SOGoAppointmentFolder *calendar;
+ SOGoAppointmentFolders *calendars;
- calendar = [$(@"SOGoAppointmentFolder") objectWithName: _key inContainer: self];
- [calendar setOCSPath: [self ocsPrivateCalendarPath]];
+ calendars = [$(@"SOGoAppointmentFolders") objectWithName: _key inContainer: self];
+ [calendars setBaseOCSPath: [self ocsPrivateCalendarPath]];
- return calendar;
+ return calendars;
}
- (SOGoContactFolders *) privateContacts: (NSString *) _key
if (!obj)
{
if ([_key isEqualToString: @"Calendar"])
- obj = [self privateCalendar: @"Calendar" inContext: _ctx];
+ obj = [self privateCalendars: @"Calendar" inContext: _ctx];
// if (![_key isEqualToString: @"Calendar"])
// obj = [obj lookupName: [_key pathExtension]
// inContext: _ctx acquire: NO];
"You cannot subscribe to a folder that you own!" = "You cannot subscribe to a folder that you own!";
"Unable to unsubscribe from that folder!" = "Unable to unsubscribe from that folder!";
"You cannot unsubscribe from a folder that you own!" = "You cannot unsubscribe from a folder that you own!";
+"Unable to rename that folder!" = "Unable to rename that folder!";
"You cannot subscribe to a folder that you own!" = "Impossible de vous abonner à un dossier qui vous appartient.";
"Unable to unsubscribe from that folder!" = "Impossible de se désabonner de ce dossier.";
"You cannot unsubscribe from a folder that you own!" = "Impossible de vous désabonner d'un dossier qui vous appartient.";
+"Unable to rename that folder!" = "Impossible de renommer ce dossier.";
UIxAclEditor.m \
UIxObjectActions.m \
UIxFolderActions.m \
+ UIxParentFolderActions.m \
UIxElemBuilder.m \
UIxTabView.m \
UIxTabItem.m \
"You cannot subscribe to a folder that you own!" = "Unmöglich sich an einem Ordner zu abonnieren, der Ihnen selbst gehört.";
"Unable to unsubscribe from that folder!" = "Unmöglich sich von diesem Ordner zu des-abonnieren.";
"You cannot unsubscribe from a folder that you own!" = "Unmöglich sich von einem Ordner zu des-abonnieren, der Ihnen selbst gehört.";
+"Unable to rename that folder!" = "Unable to rename that folder!";
NSString *owner;
NSString *login;
NSString *baseFolder;
- NSMutableString *subscriptionPointer;
+ NSString *subscriptionPointer;
NSMutableDictionary *moduleSettings;
BOOL isMailInvitation;
}
#import <NGObjWeb/SoSecurityManager.h>
#import <SoObjects/SOGo/LDAPUserManager.h>
+#import <SoObjects/SOGo/NSArray+Utilities.h>
#import <SoObjects/SOGo/SOGoUser.h>
-#import <SoObjects/SOGo/SOGoObject.h>
+#import <SoObjects/SOGo/SOGoFolder.h>
#import <SoObjects/SOGo/SOGoPermissions.h>
+#import "WODirectAction+SOGo.h"
+
#import "UIxFolderActions.h"
@implementation UIxFolderActions
}
[ud setObject: moduleSettings forKey: baseFolder];
- subscriptionPointer = [NSMutableString stringWithFormat: @"%@:%@",
- owner, baseFolder];
- if ([baseFolder isEqualToString: @"Contacts"])
- [subscriptionPointer appendFormat: @"/%@",
- [clientObject nameInContainer]];
+ subscriptionPointer = [NSString stringWithFormat: @"%@:%@/%@",
+ owner, baseFolder,
+ [clientObject nameInContainer]];
mailInvitationParam
= [[context request] formValueForKey: @"mail-invitation"];
isMailInvitation = [mailInvitationParam boolValue];
}
-- (WOResponse *) _realActionWithFolderName: (NSDictionary *) folderDict
+- (WOResponse *) _realSubscribe: (BOOL) reallyDo
{
WOResponse *response;
- NSMutableDictionary *folderSubscription;
+ NSMutableArray *folderSubscription;
NSString *mailInvitationURL;
- response = [context response];
if ([owner isEqualToString: login])
{
- [response setStatus: 403];
+ response = [self responseWithStatus: 403];
[response appendContentString:
@"You cannot (un)subscribe to a folder that you own!"];
}
{
folderSubscription
= [moduleSettings objectForKey: @"SubscribedFolders"];
- if (!folderSubscription)
+ if (!(folderSubscription
+ && [folderSubscription isKindOfClass: [NSMutableArray class]]))
{
- folderSubscription = [NSMutableDictionary dictionary];
+ folderSubscription = [NSMutableArray array];
[moduleSettings setObject: folderSubscription
forKey: @"SubscribedFolders"];
}
- if (folderDict)
- [folderSubscription setObject: folderDict
- forKey: subscriptionPointer];
+ if (reallyDo)
+ [folderSubscription addObjectUniquely: subscriptionPointer];
else
- [folderSubscription removeObjectForKey: subscriptionPointer];
+ [folderSubscription removeObject: subscriptionPointer];
[ud synchronize];
mailInvitationURL
= [[clientObject soURLToBaseContainerForCurrentUser]
absoluteString];
- [response setStatus: 302];
+ response = [self responseWithStatus: 302];
[response setHeader: mailInvitationURL
forKey: @"location"];
}
else
- [response setStatus: 204];
+ response = [self responseWith204];
}
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 dictionary];
- [folderDict setObject: folderName forKey: @"displayName"];
- [folderDict setObject: [NSNumber numberWithBool: NO] forKey: @"active"];
- return [self _realActionWithFolderName: folderDict];
+ return [self _realSubscribe: YES];
}
- (WOResponse *) unsubscribeAction
{
[self _setupContext];
- return [self _realActionWithFolderName: nil];
+ return [self _realSubscribe: NO];
}
- (WOResponse *) canAccessContentAction
{
- WOResponse *response;
-
- response = [context response];
- [response setStatus: 204];
-
- return response;
+ return [self responseWith204];
}
- (WOResponse *) _realFolderActivation: (BOOL) makeActive
{
- WOResponse *response;
- NSMutableDictionary *folderSubscription, *folderDict;
- NSNumber *active;
-
- response = [context response];
+ NSMutableArray *folderSubscription;
+ NSString *folderName;
[self _setupContext];
- active = [NSNumber numberWithBool: makeActive];
- if ([owner isEqualToString: login])
- [moduleSettings setObject: active forKey: @"activateUserFolder"];
- else
+ folderSubscription
+ = [moduleSettings objectForKey: @"ActiveFolders"];
+ if (!folderSubscription)
{
- folderSubscription
- = [moduleSettings objectForKey: @"SubscribedFolders"];
- if (folderSubscription)
- {
- folderDict = [folderSubscription objectForKey: subscriptionPointer];
- if (folderDict)
- [folderDict setObject: active
- forKey: @"active"];
- }
+ folderSubscription = [NSMutableArray array];
+ [moduleSettings setObject: folderSubscription forKey: @"ActiveFolders"];
}
+ folderName = [clientObject nameInContainer];
+ if (makeActive)
+ [folderSubscription addObjectUniquely: folderName];
+ else
+ [folderSubscription removeObject: folderName];
+
[ud synchronize];
- [response setStatus: 204];
- return response;
+ return [self responseWith204];
}
- (WOResponse *) activateFolderAction
return [self _realFolderActivation: NO];
}
+- (WOResponse *) deleteFolderAction
+{
+ WOResponse *response;
+
+ response = (WOResponse *) [[self clientObject] delete];
+ if (!response)
+ response = [self responseWith204];
+
+ return response;
+}
+
+- (WOResponse *) renameFolderAction
+{
+ WOResponse *response;
+ NSString *folderName;
+
+ folderName = [[context request] formValueForKey: @"name"];
+ if ([folderName length] > 0)
+ {
+ clientObject = [self clientObject];
+ [clientObject renameTo: folderName];
+ response = [self responseWith204];
+ }
+ else
+ {
+ response = [self responseWithStatus: 500];
+ [response appendContentString: @"Missing 'name' parameter."];
+ }
+
+ return response;
+}
+
@end
@interface WODirectAction (SOGoExtension)
+- (WOResponse *) responseWithStatus: (unsigned int) status;
+- (WOResponse *) responseWith204;
- (WOResponse *) redirectToLocation: (NSString *) newLocation;
@end
@implementation WODirectAction (SOGoExtension)
-- (WOResponse *) redirectToLocation: (NSString *) newLocation
+- (WOResponse *) responseWithStatus: (unsigned int) status
{
WOResponse *response;
response = [context response];
- [response setStatus: 302 /* moved */];
+ [response setStatus: status];
+
+ return response;
+}
+
+- (WOResponse *) responseWith204
+{
+ return [self responseWithStatus: 204];
+}
+
+- (WOResponse *) redirectToLocation: (NSString *) newLocation
+{
+ WOResponse *response;
+
+ response = [self responseWithStatus: 302];
[response setHeader: newLocation forKey: @"location"];
return response;
}
+
@end
-{ /* -*-javascript-*- */
- requires = ( MAIN, Mailer );
+{ /* -*-java-*- */
+ 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 = {
- SOGoObject = {
- methods = {
- addUserInAcls = {
- protectedBy = "SaveAcls";
- actionClass = "UIxObjectActions";
- actionName = "addUserInAcls";
- };
- removeUserFromAcls = {
- protectedBy = "SaveAcls";
- actionClass = "UIxObjectActions";
- actionName = "removeUserFromAcls";
- };
- acls = {
- protectedBy = "ReadAcls";
- pageName = "UIxAclEditor";
- };
- saveAcls = {
- protectedBy = "SaveAcls";
- pageName = "UIxAclEditor";
- actionName = "saveAcls";
- };
- userRights = {
- protectedBy = "ReadAcls";
- pageName = "UIxUserRightsEditor";
- };
- saveUserRights = {
- protectedBy = "ReadAcls";
- pageName = "UIxUserRightsEditor";
- actionName = "saveUserRights";
- };
- };
+ categories = {
+ SOGoObject = {
+ methods = {
+ addUserInAcls = {
+ protectedBy = "SaveAcls";
+ actionClass = "UIxObjectActions";
+ actionName = "addUserInAcls";
+ };
+ removeUserFromAcls = {
+ protectedBy = "SaveAcls";
+ actionClass = "UIxObjectActions";
+ actionName = "removeUserFromAcls";
+ };
+ acls = {
+ protectedBy = "ReadAcls";
+ pageName = "UIxAclEditor";
+ };
+ saveAcls = {
+ protectedBy = "SaveAcls";
+ pageName = "UIxAclEditor";
+ actionName = "saveAcls";
+ };
+ userRights = {
+ protectedBy = "ReadAcls";
+ pageName = "UIxUserRightsEditor";
+ };
+ saveUserRights = {
+ protectedBy = "ReadAcls";
+ pageName = "UIxUserRightsEditor";
+ actionName = "saveUserRights";
+ };
+ };
+ };
+ SOGoParentFolder = {
+ methods = {
+ createFolder = {
+ protectedBy = "View";
+ actionClass = "UIxParentFolderActions";
+ actionName = "createFolder";
+ };
};
- SOGoFolder = {
- methods = {
- subscribe = {
- protectedBy = "<public>";
- actionClass = "UIxFolderActions";
- actionName = "subscribe";
- };
- unsubscribe = {
- protectedBy = "<public>";
- actionClass = "UIxFolderActions";
- actionName = "unsubscribe";
- };
- canAccessContent = {
- protectedBy = "<public>";
- actionClass = "UIxFolderActions";
- actionName = "canAccessContent";
- };
- activateFolder = {
- protectedBy = "<public>";
- actionClass = "UIxFolderActions";
- actionName = "activateFolder";
- };
- deactivateFolder = {
- protectedBy = "<public>";
- actionClass = "UIxFolderActions";
- actionName = "deactivateFolder";
- };
- };
+ };
+ SOGoFolder = {
+ methods = {
+ subscribe = {
+ protectedBy = "<public>";
+ actionClass = "UIxFolderActions";
+ actionName = "subscribe";
+ };
+ unsubscribe = {
+ protectedBy = "<public>";
+ actionClass = "UIxFolderActions";
+ actionName = "unsubscribe";
+ };
+ canAccessContent = {
+ protectedBy = "<public>";
+ actionClass = "UIxFolderActions";
+ actionName = "canAccessContent";
+ };
+ activateFolder = {
+ protectedBy = "<public>";
+ actionClass = "UIxFolderActions";
+ actionName = "activateFolder";
+ };
+ deactivateFolder = {
+ protectedBy = "<public>";
+ actionClass = "UIxFolderActions";
+ actionName = "deactivateFolder";
+ };
+ deleteFolder = {
+ protectedBy = "SaveAcls"; /* a hack to force "owner" */
+ actionClass = "UIxFolderActions";
+ actionName = "deleteFolder";
+ };
+ renameFolder = {
+ protectedBy = "SaveAcls";
+ actionClass = "UIxFolderActions";
+ actionName = "renameFolder";
+ };
};
- };
+ };
+ };
}
"Are you sure you want to delete the selected address book?"
= "Are you sure you want to delete the selected address book?";
+"Address Book Name" = "Address Book Name";
+
"You cannot subscribe to a folder that you own!"
= "You cannot subscribe to a folder that you own!";
"Unable to subscribe to that folder!"
"Are you sure you want to delete the selected address book?"
= "Voulez-vous vraiment supprimer le carnet d'adresses sélectionné ?";
+"Address Book Name" = "Nom du carnet d'adresses";
+
"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!"
"Are you sure you want to delete the selected address book?"
= "Voulez-vous vraiment supprimer le carnet d'adresses sélectionné ?";
+"Address Book Name" = "Address Book Name";
+
"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!"
jsLink="js_card";
label="New Card";
image="new-card.png";
- onclick = "newContact(this); return false;"; },
+ onclick = "newContact(this); return false;";
+ tooltip = "Create a new address book card"; },
{ link = "new_list";
enabled = "NO";
label="New List";
- image="new-list.png"; }
+ image="new-list.png";
+ tooltip = "Create a new list"; }
),
(
{ link = "edit";
label = "Modify";
onclick = "return onToolbarEditSelectedContacts(this);";
- image = "properties.png"; },
+ image = "properties.png";
+ tooltip = "Edit the selected card"; },
{ link = "write";
label="Write";
onclick = "return onToolbarWriteToSelectedContacts(this);";
- image="write.png"; }
+ image="write.png";
+ tooltip = "Send a mail message"; }
),
(
{ link = "delete";
label="Delete";
onclick = "return uixDeleteSelectedContacts(this);";
- image="delete.png"; }
+ image="delete.png";
+ tooltip = "Delete selected card or address book"; }
)
)
id <SOGoContactFolder> co;
co = [self clientObject];
- if ([[co class] respondsToSelector: @selector (globallyUniqueObjectId)])
- objectId = [[[self clientObject] class] globallyUniqueObjectId];
+ if ([co respondsToSelector: @selector (globallyUniqueObjectId)])
+ objectId = [co globallyUniqueObjectId];
else
objectId = nil;
WORequest *request;
folders = [self clientObject];
- action = [NSString stringWithFormat: @"../%@/%@",
- [folders defaultSourceName],
- actionName];
+ action = [NSString stringWithFormat: @"../personal/%@", actionName];
request = [[self context] request];
return [self _selectActionForApplication: @"new"];
}
-- (id <WOActionResults>) newAbAction
-{
- id <WOActionResults> response;
- NSString *name;
-
- name = [self queryParameterForKey: @"name"];
- if ([name length] > 0)
- response = [[self clientObject] newFolderWithName: name];
- else
- response = [NSException exceptionWithHTTPStatus: 400
- reason: @"The name is missing"];
-
- return response;
-}
-
- (id) selectForMailerAction
{
return [self _selectActionForApplication: @"mailer-contacts"];
{
uid = [currentContact objectForKey: @"c_uid"];
if (uid && ![results objectForKey: uid])
- [results setObject: currentContact
- forKey: uid];
+ [results setObject: currentContact forKey: uid];
currentContact = [folderResults nextObject];
}
}
return result;
}
-- (NSArray *) _gcsFoldersFromFolder: (SOGoContactFolders *) contactFolders
+- (NSArray *) _subFoldersFromFolder: (SOGoParentFolder *) parentFolder
{
- NSMutableArray *gcsFolders;
- NSEnumerator *contactSubfolders;
- SOGoContactGCSFolder *currentContactFolder;
- NSString *folderName, *displayName;
+ NSMutableArray *folders;
+ NSEnumerator *subfolders;
+ SOGoFolder *currentFolder;
+ NSString *folderName;
NSMutableDictionary *currentDictionary;
+ SoSecurityManager *securityManager;
- gcsFolders = [NSMutableArray new];
- [gcsFolders autorelease];
+ securityManager = [SoSecurityManager sharedSecurityManager];
+
+// return (([securityManager validatePermission: SoPerm_AccessContentsInformation
+// onObject: contactFolder
+// inContext: context] == nil)
- contactSubfolders = [[contactFolders contactFolders] objectEnumerator];
- currentContactFolder = [contactSubfolders nextObject];
- while (currentContactFolder)
+ folders = [NSMutableArray new];
+ [folders autorelease];
+
+ subfolders = [[parentFolder subFolders] objectEnumerator];
+ currentFolder = [subfolders nextObject];
+ while (currentFolder)
{
- if ([currentContactFolder
- isKindOfClass: [SOGoContactGCSFolder class]])
+ if (![securityManager validatePermission: SOGoPerm_AccessObject
+ onObject: currentFolder inContext: context])
{
- displayName = [[currentContactFolder ocsFolder] folderName];
- if (displayName)
- {
- folderName = [NSString stringWithFormat: @"/Contacts/%@",
- [currentContactFolder nameInContainer]];
- currentDictionary
- = [NSMutableDictionary dictionaryWithCapacity: 3];
- [currentDictionary setObject: displayName forKey: @"displayName"];
- [currentDictionary setObject: folderName forKey: @"name"];
- [currentDictionary setObject: @"contact" forKey: @"type"];
- [gcsFolders addObject: currentDictionary];
- }
+ folderName = [NSString stringWithFormat: @"/%@/%@",
+ [parentFolder nameInContainer],
+ [currentFolder nameInContainer]];
+ currentDictionary
+ = [NSMutableDictionary dictionaryWithCapacity: 3];
+ [currentDictionary setObject: [currentFolder displayName]
+ forKey: @"displayName"];
+ [currentDictionary setObject: folderName forKey: @"name"];
+ [currentDictionary setObject: [currentFolder folderType]
+ forKey: @"type"];
+ [folders addObject: currentDictionary];
}
- currentContactFolder = [contactSubfolders nextObject];
+ currentFolder = [subfolders nextObject];
}
- return gcsFolders;
+ return folders;
}
- (NSArray *) _foldersForUID: (NSString *) uid
ofType: (NSString *) folderType
{
NSObject *topFolder, *userFolder;
- SOGoContactFolders *contactFolders;
+ SOGoParentFolder *parentFolder;
NSMutableArray *folders;
- NSMutableDictionary *currentDictionary;
folders = [NSMutableArray new];
[folders autorelease];
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];
+ parentFolder = [userFolder lookupName: @"Calendar"
+ inContext: context acquire: NO];
+ [folders
+ addObjectsFromArray: [self _subFoldersFromFolder: parentFolder]];
}
if ([folderType length] == 0 || [folderType isEqualToString: @"contact"])
{
- contactFolders = [userFolder lookupName: @"Contacts"
- inContext: context acquire: NO];
+ parentFolder = [userFolder lookupName: @"Contacts"
+ inContext: context acquire: NO];
[folders
- addObjectsFromArray: [self _gcsFoldersFromFolder: contactFolders]];
+ addObjectsFromArray: [self _subFoldersFromFolder: parentFolder]];
}
return folders;
return result;
}
-- (SOGoContactGCSFolder *) contactFolderForUID: (NSString *) uid
-{
- SOGoFolder *upperContainer;
- SOGoUserFolder *userFolder;
- SOGoContactFolders *contactFolders;
- SOGoContactGCSFolder *contactFolder;
- SoSecurityManager *securityManager;
-
- upperContainer = [[[self clientObject] container] container];
- userFolder = [SOGoUserFolder objectWithName: uid
- inContainer: upperContainer];
- contactFolders = [SOGoContactFolders objectWithName: @"Contacts"
- inContainer: userFolder];
- contactFolder = [SOGoContactGCSFolder objectWithName: @"personal"
- inContainer: contactFolders];
- [contactFolder
- setOCSPath: [NSString stringWithFormat: @"/Users/%@/Contacts/personal", uid]];
- [contactFolder setOwner: uid];
-
- securityManager = [SoSecurityManager sharedSecurityManager];
-
- return (([securityManager validatePermission: SoPerm_AccessContentsInformation
- onObject: contactFolder
- inContext: context] == nil)
- ? contactFolder : nil);
-}
+// - (SOGoContactGCSFolder *) contactFolderForUID: (NSString *) uid
+// {
+// SOGoFolder *upperContainer;
+// SOGoUserFolder *userFolder;
+// SOGoContactFolders *contactFolders;
+// SOGoContactGCSFolder *contactFolder;
+// SoSecurityManager *securityManager;
+
+// upperContainer = [[[self clientObject] container] container];
+// userFolder = [SOGoUserFolder objectWithName: uid
+// inContainer: upperContainer];
+// contactFolders = [SOGoUserFolder lookupName: @"Contacts"
+// inContext: context
+// acquire: NO];
+// contactFolder = [contactFolders lookupName: @"personal"
+// inContext: context
+// acquire: NO];
+
+// securityManager = [SoSecurityManager sharedSecurityManager];
+
+// return (([securityManager validatePermission: SoPerm_AccessContentsInformation
+// onObject: contactFolder
+// inContext: context] == nil)
+// ? contactFolder : nil);
+// }
@end
return selectorComponentClass;
}
-- (id <WOActionResults>) deleteAction
-{
- id <WOActionResults> result;
- NSException <WOActionResults> *ex;
- WOResponse *response;
-
- ex = [[self clientObject] delete];
- if (ex)
- result = ex;
- else
- {
- response = [context response];
- [response setStatus: 200];
- result = response;
- }
-
- return result;
-}
-
- (NSString *) defaultSortKey
{
return @"displayName";
@interface UIxContactsListViewContainer : UIxComponent
{
- NSString *foldersPrefix;
NSString *selectorComponentClass;
- NSString *currentAdditionalFolder;
- NSDictionary *additionalFolders;
id currentFolder;
}
- (void) setCurrentFolder: (id) folder;
-- (NSString *) foldersPrefix;
-
- (NSArray *) contactFolders;
- (NSString *) currentContactFolderId;
+- (NSString *) currentContactFolderOwner;
- (NSString *) currentContactFolderName;
-- (NSArray *) additionalFolders;
-
-- (void) setCurrentAdditionalFolder: (NSString *) newCurrentAdditionalFolder;
-- (NSString *) currentAdditionalFolder;
-- (NSString *) currentAdditionalFolderName;
-
@end
#endif /* UIXCONTACTSLISTVIEWCONTAINERBASE_H */
#import <SoObjects/SOGo/SOGoUser.h>
#import <SoObjects/Contacts/SOGoContactFolder.h>
+#import <SoObjects/Contacts/SOGoContactFolders.h>
#import "UIxContactsListViewContainer.h"
{
if ((self = [super init]))
{
- foldersPrefix = nil;
selectorComponentClass = nil;
- additionalFolders = nil;
}
return self;
}
-- (void) dealloc
-{
- [additionalFolders release];
- [super dealloc];
-}
-
- (void) setSelectorComponentClass: (NSString *) aComponentClass
{
selectorComponentClass = aComponentClass;
currentFolder = folder;
}
-- (NSString *) foldersPrefix
-{
- NSMutableArray *folders;
- SOGoObject *currentObject;
-
- if (!foldersPrefix)
- {
- folders = [NSMutableArray new];
- [folders autorelease];
-
- currentObject = [[self clientObject] container];
- while (![currentObject isKindOfClass: [SOGoContactFolders class]])
- {
- [folders insertObject: [currentObject nameInContainer] atIndex: 0];
- currentObject = [currentObject container];
- }
-
- foldersPrefix = [folders componentsJoinedByString: @"/"];
- [foldersPrefix retain];
- }
-
- return foldersPrefix;
-}
-
- (NSArray *) contactFolders
{
SOGoContactFolders *folderContainer;
folderContainer = [[self clientObject] container];
- return [folderContainer contactFolders];
+ return [folderContainer subFolders];
}
- (NSString *) currentContactFolderId
{
- return [NSString stringWithFormat: @"%@/%@",
- [self foldersPrefix],
+ return [NSString stringWithFormat: @"/%@",
[currentFolder nameInContainer]];
}
return [currentFolder displayName];
}
-- (NSArray *) additionalFolders
-{
- NSUserDefaults *ud;
-
- if (!additionalFolders)
- {
- ud = [[context activeUser] userSettings];
- additionalFolders
- = [[ud objectForKey: @"Contacts"] objectForKey: @"SubscribedFolders"];
- [additionalFolders retain];
- }
-
- return [additionalFolders allKeys];
-}
-
-- (void) setCurrentAdditionalFolder: (NSString *) newCurrentAdditionalFolder
-{
- currentAdditionalFolder = newCurrentAdditionalFolder;
-}
-
-- (NSString *) currentAdditionalFolder
-{
- return currentAdditionalFolder;
-}
-
-- (NSString *) currentAdditionalFolderName
+- (NSString *) currentContactFolderOwner
{
- return [[additionalFolders objectForKey: currentAdditionalFolder]
- objectForKey: @"displayName"];
+ return [currentFolder ownerInContext: context];
}
- (BOOL) hasContactSelectionButtons
pageName = "UIxContactFoldersView";
actionName = "new";
};
- newAb = {
- protectedBy = "View";
- pageName = "UIxContactFoldersView";
- actionName = "newAb";
- };
mailer-contacts = {
protectedBy = "View";
pageName = "UIxContactFoldersView";
pageName = "UIxContactsListView";
actionName = "mailerContacts";
};
- delete = {
- protectedBy = "SaveAcls"; /* a hack to force "owner" */
- pageName = "UIxContactsListView";
- actionName = "delete";
- };
userRights = {
protectedBy = "ReadAcls";
pageName = "UIxContactsUserRightsEditor";
"Home" = "Home";
"Calendar" = "Calendar";
-"Addressbook" = "Addressbook";
+"Addressbook" = "Address Book";
"Mail" = "Mail";
"Right Administration" = "Right Administration";
"cc" = "Cc";
"bcc" = "Bcc";
-"Addressbook" = "Addressbook";
+"Addressbook" = "Address Book";
"Anais" = "Anais";
"Edit Draft..." = "Edit Draft...";
onclick = "return clickedEditorSend(this);";
image = "tb-compose-send-flat-24x24.png";
cssClass = "tbicon_send";
- label = "Send"; },
+ label = "Send";
+ tooltip = "Send this message now"; },
{ link = "#";
onclick = "return onContactAdd(null);";
image = "tb-compose-contacts-flat-24x24.png";
cssClass = "tbicon_addressbook";
- label = "Contacts"; },
+ label = "Contacts";
+ tooltip = "Select a recipient from an Address Book"; },
{ link = "#";
isSafe = NO;
onclick = "return clickedEditorAttach(this)";
image = "tb-compose-attach-flat-24x24.png";
cssClass = "tbicon_attach";
- label = "Attach"; },
+ label = "Attach";
+ tooltip = "Include an attachment"; },
{ link = "#";
isSafe = NO;
onclick = "return clickedEditorSave(this);";
image = "tb-mail-file-flat-24x24.png";
cssClass = "tbicon_save";
- label = "Save"; },
+ label = "Save";
+ tooltip = "Save this message"; },
)
)
cssClass = "tbicon_getmail";
label = "Get Mail";
onclick = "return refreshMailbox(this);";
- },
+ tooltip = "Get new messages"; },
{ link = "#";
isSafe = NO;
image = "tb-mail-write-flat-24x24.png";
onclick = "return onComposeMessage();";
- cssClass = "tbicon_compose"; label = "Write"; },
- { link = "#"; target = "addressbook";
+ cssClass = "tbicon_compose";
+ label = "Write";
+ tooltip = "Create a new message"; },
+ { link = "#";
+ target = "addressbook";
onclick = "openAddressbook(this);return false;";
image = "tb-mail-addressbook-flat-24x24.png";
- cssClass = "tbicon_addressbook"; label = "Addressbook"; },
+ cssClass = "tbicon_addressbook";
+ label = "Addressbook";
+ tooltip = "Go to address book"; },
),
( // second group
onclick = "return openMessageWindowsForSelection('reply');";
isSafe = NO;
image = "tb-mail-reply-flat-24x24.png";
- cssClass = "tbicon_reply"; label = "Reply"; },
-
+ cssClass = "tbicon_reply";
+ label = "Reply";
+ tooltip = "Reply to the message"; },
{ link = "replyall";
onclick = "return openMessageWindowsForSelection('replyall');";
isSafe = NO;
image = "tb-mail-replyall-flat-24x24.png";
- cssClass = "tbicon_replyall"; label = "Reply All"; },
-
+ cssClass = "tbicon_replyall";
+ label = "Reply All";
+ tooltip = "Reply to sender and all recipients"; },
{ link = "forward";
onclick = "return openMessageWindowsForSelection('forward');";
isSafe = NO;
image = "tb-mail-forward-flat-24x24.png";
- cssClass = "tbicon_forward"; label = "Forward"; },
+ cssClass = "tbicon_forward";
+ label = "Forward";
+ tooltip = "Forward selected message"; },
),
( // third group
onclick = "onMenuDeleteMessage(event);";
// enabled = showMarkDeletedButton;
image = "tb-mail-delete-flat-24x24.png";
- cssClass = "tbicon_delete"; label = "Delete"; },
+ cssClass = "tbicon_delete";
+ label = "Delete";
+ tooltip = "Delete selected message or folder"; },
{ link = "#";
isSafe = NO;
image = "tb-mail-junk-flat-24x24.png";
- cssClass = "tbicon_junk"; label = "Junk";
- },
+ cssClass = "tbicon_junk";
+ label = "Junk";
+ tooltip = "Mark the selected messages as junk"; },
),
(
{ link = "#";
onclick = "return onPrintCurrentMessage(event);";
cssClass = "tbicon_print";
image = "tb-mail-print-flat-24x24.png";
- label = "Print"; },
+ label = "Print";
+ tooltip = "Print this message"; },
{ link = "#";
image = "tb-mail-stop-flat-24x24.png";
cssClass = "tbicon_stop";
- label = "Stop"; },
+ label = "Stop";
+ tooltip = "Stop the current transfer"; },
),
)
rawFolders = [co allFolderPaths];
folders = [self _jsonFolders: [rawFolders objectEnumerator]];
- response = [context response];
- [response setStatus: 200];
+ response = [self responseWithStatus: 200];
[response setHeader: @"text/plain; charset=utf-8"
forKey: @"content-type"];
[response appendContentString: [folders jsonRepresentation]];
response = [[self clientObject] trashInContext: context];
if (!response)
- {
- response = [context response];
- [response setStatus: 204];
- }
+ response = [self responseWith204];
return response;
}
response = [[self clientObject] moveToFolderNamed: destinationFolder
inContext: context];
if (!response)
- {
- response = [context response];
- [response setStatus: 204];
- }
+ response = [self responseWith204];
}
else
response = [NSException exceptionWithHTTPStatus: 500 /* Server Error */
return response;
}
+/* active message */
+
+- (id) markMessageUnreadAction
+{
+ id response;
+
+ response = [[self clientObject] removeFlags: @"seen"];
+ if (!response)
+ response = [self responseWith204];
+
+ return response;
+}
+
+- (id) markMessageReadAction
+{
+ id response;
+
+ response = [[self clientObject] addFlags: @"seen"];
+ if (!response)
+ response = [self responseWith204];
+
+ return response;
+}
+
/* SOGoDraftObject */
- (WOResponse *) editAction
{
if (error)
response = error;
else
- {
- response = [context response];
- [response setStatus: 204];
- }
+ response = [self responseWith204];
return response;
}
WOResponse *response;
NSString *filename;
- response = [context response];
-
filename = [[context request] formValueForKey: @"filename"];
if ([filename length] > 0)
{
+ response = [self responseWith204];
[[self clientObject] deleteAttachmentWithName: filename];
- [response setStatus: 204];
}
else
{
- [response setStatus: 500];
+ response = [self responseWithStatus: 500];
[response appendContentString: @"How did you end up here?"];
}
{
result = [[self clientObject] save];
if (!result)
- {
- result = [context response];
- [result setStatus: 204];
- }
+ result = [self responseWith204];
}
else
result = [self failedToSaveFormResponse];
#import <SoObjects/Mailer/SOGoMailAccount.h>
#import <SoObjects/SOGo/NSObject+Utilities.h>
+#import <UI/Common/WODirectAction+SOGo.h>
+
#import "UIxMailFolderActions.h"
@implementation UIxMailFolderActions
NSString *folderName;
co = [self clientObject];
- response = [context response];
folderName = [[context request] formValueForKey: @"name"];
if ([folderName length] > 0)
error = [connection createMailbox: folderName atURL: [co imap4URL]];
if (error)
{
- [response setStatus: 500];
+ response = [self responseWithStatus: 500];
[response appendContentString: @"Unable to create folder."];
}
else
- [response setStatus: 204];
+ response = [self responseWith204];
}
else
{
- [response setStatus: 500];
+ response = [self responseWithStatus: 500];
[response appendContentString: @"Missing 'name' parameter."];
}
NSURL *srcURL, *destURL;
co = [self clientObject];
- response = [context response];
folderName = [[context request] formValueForKey: @"name"];
if ([folderName length] > 0)
toURL: destURL];
if (error)
{
- [response setStatus: 500];
+ response = [self responseWithStatus: 500];
[response appendContentString: @"Unable to rename folder."];
}
else
- [response setStatus: 204];
+ response = [self responseWith204];
}
else
{
- [response setStatus: 500];
+ response = [self responseWithStatus: 500];
[response appendContentString: @"Missing 'name' parameter."];
}
NSURL *srcURL, *destURL;
co = [self clientObject];
- response = [context response];
connection = [co imap4Connection];
srcURL = [co imap4URL];
destURL = [self _trashedURLOfFolder: srcURL
toURL: destURL];
if (error)
{
- [response setStatus: 500];
+ response = [self responseWithStatus: 500];
[response appendContentString: @"Unable to move folder."];
}
else
- [response setStatus: 204];
+ response = [self responseWith204];
return response;
}
WOResponse *response;
co = [self clientObject];
- response = [context response];
error = [co expunge];
if (error)
{
- [response setStatus: 500];
+ response = [self responseWithStatus: 500];
[response appendContentString: @"Unable to expunge folder."];
}
else
{
[co flushMailCaches];
- [response setStatus: 204];
+ response = [self responseWith204];
}
return response;
NSURL *currentURL;
co = [self clientObject];
- response = [context response];
error = [co addFlagsToAllMessages: @"deleted"];
if (!error)
}
if (error)
{
- [response setStatus: 500];
+ response = [self responseWithStatus: 500];
[response appendContentString: @"Unable to empty the trash folder."];
}
else
- [response setStatus: 204];
+ response = [self responseWith204];
return response;
}
WOResponse *response;
SOGoMailFolder *clientObject;
- response = [context response];
mailInvitationParam
= [[context request] formValueForKey: @"mail-invitation"];
if ([mailInvitationParam boolValue])
}
else
{
- [response setStatus: 500];
+ response = [self responseWithStatus: 500];
[response appendContentString: @"How did you end up here?"];
}
NGImap4Client *client;
NSString *responseString;
- response = [context response];
- [response setStatus: 200];
+ response = [self responseWithStatus: 200];
[response setHeader: @"text/plain; charset=UTF-8"
forKey: @"content-type"];
- (NSArray *) sortedUIDs
{
+ EOQualifier *fetchQualifier, *notDeleted;
if (!sortedUIDs)
{
+ notDeleted = [EOQualifier qualifierWithQualifierFormat:
+ @"(not (flags = %@))",
+ @"deleted"];
+ if (qualifier)
+ {
+ fetchQualifier = [[EOAndQualifier alloc] initWithQualifiers:
+ notDeleted, qualifier,
+ nil];
+ [fetchQualifier autorelease];
+ }
+ else
+ fetchQualifier = notDeleted;
+
sortedUIDs
- = [[self clientObject] fetchUIDsMatchingQualifier: qualifier
+ = [[self clientObject] fetchUIDsMatchingQualifier: fetchQualifier
sortOrdering: [self imap4SortOrdering]];
[sortedUIDs retain];
}
return [self redirectToLocation:url];
}
-/* active message */
-
-- (SOGoMailObject *) lookupActiveMessage
-{
- NSString *uid;
-
- if ((uid = [[context request] formValueForKey: @"uid"]) == nil)
- return nil;
-
- return [[self clientObject] lookupName: uid
- inContext: context
- acquire: NO];
-}
-
/* actions */
-- (BOOL) isJavaScriptRequest
-{
- return [[[context request] formValueForKey:@"jsonly"] boolValue];
-}
-
-- (id) javaScriptOK
-{
- WOResponse *r;
-
- r = [context response];
- [r setStatus:200 /* OK */];
- return r;
-}
-
- (int) firstMessageOfPageFor: (int) messageNbr
{
NSArray *messageNbrs;
if ([criteria isEqualToString: @"subject"])
qualifier = [EOQualifier qualifierWithQualifierFormat:
- @"(subject doesContain: %@)",
- value];
+ @"(subject doesContain: %@)", value];
else if ([criteria isEqualToString: @"sender"])
qualifier = [EOQualifier qualifierWithQualifierFormat:
- @"(sender doesContain: %@)", value];
+ @"(from doesContain: %@)", value];
else if ([criteria isEqualToString: @"subject_or_sender"])
qualifier = [EOQualifier qualifierWithQualifierFormat:
- @"((sender doesContain: %@)"
+ @"((subject doesContain: %@)"
@" OR (from doesContain: %@))",
value, value];
else if ([criteria isEqualToString: @"to_or_cc"])
= ((specificMessage)
? [self firstMessageOfPageFor: [specificMessage intValue]]
: [[request formValueForKey:@"idx"] intValue]);
-
return self;
}
-- (id) viewAction
-{
- return [self defaultAction];
-}
-
-- (id) markMessageUnreadAction
-{
- NSException *error;
-
- if ((error = [[self lookupActiveMessage] removeFlags:@"seen"]) != nil)
- // TODO: improve error handling
- return error;
-
- if ([self isJavaScriptRequest])
- return [self javaScriptOK];
-
- return [self redirectToLocation:@"view"];
-}
-
-- (id) markMessageReadAction
-{
- NSException *error;
-
- if ((error = [[self lookupActiveMessage] addFlags:@"seen"]) != nil)
- // TODO: improve error handling
- return error;
-
- if ([self isJavaScriptRequest])
- return [self javaScriptOK];
-
- return [self redirectToLocation:@"view"];
-}
-
- (id) getMailAction
{
// TODO: we might want to flush the caches?
#import <Foundation/NSString.h>
#import <SoObjects/Mailer/SOGoMailObject.h>
+#import <UI/Common/WODirectAction+SOGo.h>
+
#import "UIxMailSourceView.h"
@implementation UIxMailSourceView
source = [[self clientObject] contentAsString];
- response = [context response];
- [response setStatus: 200];
+ response = [self responseWithStatus: 200];
[response setHeader: @"text/plain; charset=utf-8"
forKey: @"content-type"];
[response appendContentString: source];
- (id) defaultAction
{
+ WOResponse *response;
+ NSString *s;
+
/* check etag to see whether we really must rerender */
- if (mailETag != nil ) {
- /*
- Note: There is one thing which *can* change for an existing message,
- those are the IMAP4 flags (and annotations, which we do not use).
- Since we don't render the flags, it should be OK, if this changes
- we must embed the flagging into the etag.
- */
- NSString *s;
-
- if ((s = [[context request] headerForKey:@"if-none-match"])) {
- if ([s rangeOfString:mailETag].length > 0) { /* not perfectly correct */
- /* client already has the proper entity */
- // [self logWithFormat:@"MATCH: %@ (tag %@)", s, mailETag];
-
- if (![[self clientObject] doesMailExist]) {
- return [NSException exceptionWithHTTPStatus:404 /* Not Found */
- reason:@"message got deleted"];
+ if (mailETag)
+ {
+ /*
+ Note: There is one thing which *can* change for an existing message,
+ those are the IMAP4 flags (and annotations, which we do not use).
+ Since we don't render the flags, it should be OK, if this changes
+ we must embed the flagging into the etag.
+ */
+ s = [[context request] headerForKey: @"if-none-match"];
+ if (s)
+ {
+ if ([s rangeOfString:mailETag].length > 0) /* not perfectly correct */
+ {
+ /* client already has the proper entity */
+ // [self logWithFormat:@"MATCH: %@ (tag %@)", s, mailETag];
+
+ if (![[self clientObject] doesMailExist]) {
+ return [NSException exceptionWithHTTPStatus:404 /* Not Found */
+ reason:@"message got deleted"];
+ }
+
+ response = [context response];
+ [response setStatus: 304 /* Not Modified */];
+
+ return response;
+ }
}
-
- [[context response] setStatus:304 /* Not Modified */];
- return [context response];
- }
}
- }
- if ([self message] == nil) {
- // TODO: redirect to proper error
+ if (![self message]) // TODO: redirect to proper error
return [NSException exceptionWithHTTPStatus:404 /* Not Found */
reason:@"did not find specified message!"];
- }
return self;
}
protectedBy = "View";
pageName = "UIxMailListView";
};
- markMessageUnread = {
- protectedBy = "View";
- pageName = "UIxMailListView";
- actionName = "markMessageUnread";
- };
- markMessageRead = {
- protectedBy = "View";
- pageName = "UIxMailListView";
- actionName = "markMessageRead";
- };
getMail = {
protectedBy = "View";
pageName = "UIxMailListView";
actionClass = "UIxMailActions";
actionName = "forward";
};
+ markMessageUnread = {
+ protectedBy = "View";
+ actionClass = "UIxMailActions";
+ actionName = "markMessageUnread";
+ };
+ markMessageRead = {
+ protectedBy = "View";
+ actionClass = "UIxMailActions";
+ actionName = "markMessageRead";
+ };
};
};
auth = [[WOApplication application]
authenticatorInContext: context];
- response = [context response];
+ response = [self responseWith204];
cookieString = [NSString stringWithFormat: @"%@:%@",
[self queryParameterForKey: @"userName"],
[self queryParameterForKey: @"password"]];
- cookieValue = [NSString stringWithFormat: @"basic%@",
+ cookieValue = [NSString stringWithFormat: @"basic %@",
[cookieString stringByEncodingBase64]];
authCookie = [WOCookie cookieWithName: [auth cookieNameInContext: context]
value: cookieValue];
[authCookie setPath: @"/"];
- [response setStatus: 204];
[response addCookie: authCookie];
return response;
}
-// - (id <WOActionResults>) defaultAction
-// {
-// WOResponse *r;
-// NSString *login, *rhk;
-// SOGoWebAuthenticator *auth;
-// SOGoUser *user;
-// SOGoUserFolder *home;
-// WOApplication *base;
-
-// /*
-// Note: ctx.activeUser is NOT set here. Don't know why, so we retrieve
-// the user from the authenticator.
-// */
-
-// auth = [[self clientObject] authenticatorInContext: context];
-// user = [auth userInContext: context];
-// login = [user login];
-
-// if ([login isEqualToString:@"anonymous"]) {
-// /* use root page for unauthenticated users */
-// return self;
-// }
-
-// /* check base */
-
-// base = [self application];
-// rhk = [[context request] requestHandlerKey];
-// if (([rhk length] == 0) || ([base requestHandlerForKey:rhk] == nil)) {
-// base = [base lookupName: @"so" inContext: context acquire: NO];
-
-// if (![base isNotNull] || [base isKindOfClass:[NSException class]]) {
-// /* use root page if home could not be found */
-// [self errorWithFormat:@"Did not find 'so' request handler!"];
-// return self;
-// }
-// }
-
-// /* lookup home-page */
-
-// home = [base lookupName: login inContext: context acquire: NO];
-// if (![home isNotNull] || [home isKindOfClass:[NSException class]]) {
-// /* use root page if home could not be found */
-// return self;
-// }
-
-// /* redirect to home-page */
-
-// r = [context response];
-// [r setStatus: 302 /* moved */];
-// [r setHeader: [home baseURLInContext: context]
-// forKey: @"location"];
-
-// return r;
-// }
-
-/* response generation */
-
-// - (void) appendToResponse: (WOResponse *) response
-// inContext: (WOContext *) ctx
-// {
-// NSString *rhk;
-
-// // TODO: we might also want to look into the HTTP basic-auth to redirect to
-// // the login URL!
-
-// rhk = [[ctx request] requestHandlerKey];
-// if ([rhk length] == 0
-// || [[self application] requestHandlerForKey: rhk] == nil)
-// {
-// /* a small hack to redirect to a valid URL */
-// NSString *url;
-
-// url = [ctx urlWithRequestHandlerKey: @"so" path: @"/" queryString: nil];
-// [response setStatus: 302 /* moved */];
-// [response setHeader: url forKey: @"location"];
-// [self logWithFormat: @"URL: %@", url];
-// return;
-// }
-
-// [response setHeader: @"text/html" forKey: @"content-type"];
-// [super appendToResponse: response inContext: ctx];
-// }
+- (id <WOActionResults>) defaultAction
+{
+ id <WOActionResults> response;
+ NSString *login, *oldLocation;
+
+ login = [[context activeUser] login];
+ if ([login isEqualToString: @"anonymous"])
+ response = self;
+ else
+ {
+ oldLocation = [[self clientObject] baseURLInContext: context];
+ response
+ = [self redirectToLocation: [NSString stringWithFormat: @"%@/%@",
+ oldLocation, login]];
+ }
+
+ return response;
+}
- (BOOL) isPublicInContext: (WOContext *) localContext
{
"Access Contents Information" = ( "Owner", "ObjectViewer" );
};
};
+ SOGoParentFolder = {
+ superclass = "SOGoObject";
+ protectedBy = "Access Contents Information";
+ defaultRoles = {
+ "Access Contents Information" = ( "Authenticated" );
+ "WebDAV Access" = ( "Authenticated" );
+ };
+ };
SOGoUserFolder = {
superclass = "SOGoFolder";
protectedBy = "Access Contents Information";
- (NSArray *) timeZonesList
{
- return [NSTimeZone knownTimeZoneNames];
+ return [[NSTimeZone knownTimeZoneNames]
+ sortedArrayUsingSelector: @selector (localizedCaseInsensitiveCompare:)];
}
- (NSString *) userTimeZone
/* date selection */
- (NSCalendarDate *) selectedDate;
-- (NSString *)dateStringForDate:(NSCalendarDate *)_date;
+- (NSString *) dateStringForDate: (NSCalendarDate *)_date;
- (BOOL) hideFrame;
- (UIxComponent *) jsCloseWithRefreshMethod: (NSString *) methodName;
/* SoUser */
-- (NSString *)shortUserNameForDisplay;
+- (NSString *) shortUserNameForDisplay;
/* labels */
-- (NSString *)labelForKey:(NSString *)_key;
+- (NSString *) labelForKey:(NSString *)_key;
-- (NSString *)localizedNameForDayOfWeek:(unsigned)_dayOfWeek;
-- (NSString *)localizedAbbreviatedNameForDayOfWeek:(unsigned)_dayOfWeek;
-- (NSString *)localizedNameForMonthOfYear:(unsigned)_monthOfYear;
-- (NSString *)localizedAbbreviatedNameForMonthOfYear:(unsigned)_monthOfYear;
+- (NSString *) localizedNameForDayOfWeek:(unsigned)_dayOfWeek;
+- (NSString *) localizedAbbreviatedNameForDayOfWeek:(unsigned)_dayOfWeek;
+- (NSString *) localizedNameForMonthOfYear:(unsigned)_monthOfYear;
+- (NSString *) localizedAbbreviatedNameForMonthOfYear:(unsigned)_monthOfYear;
/* HTTP method safety */
-- (BOOL)isInvokedBySafeMethod;
+- (BOOL) isInvokedBySafeMethod;
/* locale */
- (NSDictionary *)locale;
- (WOResourceManager *) pageResourceManager;
- (NSString *) urlForResourceFilename: (NSString *) filename;
+- (WOResponse *) responseWith204;
+
/* Debugging */
- (BOOL)isUIxDebugEnabled;
userTimeZone = [[context activeUser] timeZone];
[_date setTimeZone: userTimeZone];
- return [_date descriptionWithCalendarFormat:@"%Y%m%d"];
+ return [_date descriptionWithCalendarFormat: @"%Y%m%d"];
}
- (BOOL) hideFrame
return url;
}
+- (WOResponse *) responseWith204
+{
+ WOResponse *response;
+
+ response = [context response];
+ [response setStatus: 204];
+
+ return response;
+}
+
/* debugging */
- (BOOL)isUIxDebugEnabled {
/* Button Titles */
-"Add..." = "Add...";
-"Remove" = "Remove";
+"New Calendar..." = "New Calendar...";
+"Subscribe to a Calendar..." = "Subscribe to a Calendar...";
+"Remove the selected Calendar" = "Remove the selected Calendar";
+
+"Name of the Calendar" = "Name of the Calendar";
"new" = "New";
"printview" = "Print View";
/* Button Titles */
-"Add..." = "Ajouter...";
-"Remove" = "Enlever";
+"New Calendar..." = "Nouvel agenda...";
+"Subscribe to a Calendar..." = "S'inscrire à un agenda...";
+"Remove the selected Calendar" = "Enlever l'agenda sélectionné";
+
+"Name of the Calendar" = "Nom de l'agenda";
"new" = "Nouveau";
"printview" = "Version imprimable";
product.plist
SchedulerUI_RESOURCE_FILES += \
- Toolbars/SOGoAppointmentFolder.toolbar \
+ Toolbars/SOGoAppointmentFolders.toolbar \
Toolbars/SOGoAppointmentObject.toolbar \
Toolbars/SOGoAppointmentObjectAccept.toolbar \
Toolbars/SOGoAppointmentObjectDecline.toolbar \
/* Button Titles */
-"Add..." = "Hinzufügen...";
-"Remove" = "Löschen";
+"New Calendar..." = "New Calendar...";
+"Subscribe to a Calendar..." = "Subscribe to a Calendar...";
+"Remove the selected Calendar" = "Remove the selected Calendar";
+
+"Name of the Calendar" = "Name of the Calendar";
"new" = "Neu";
"printview" = "Version imprimable";
isSafe = NO;
label = "New Event";
onclick = "return newEvent(this, 'event');";
- image = "new-event.png"; },
+ image = "new-event.png";
+ tooltip = "Create a new event"; },
{ link = "new_task";
label="New Task";
image = "new-task.png";
onclick = "return newEvent(this, 'task');";
- image = "new-task.png"; },
+ image = "new-task.png";
+ tooltip = "Create a new task"; },
{ link = "edit";
label="Edit";
onclick = "return editEvent(this);";
- image = "edit.png"; },
+ image = "edit.png";
+ tooltip = "Edit this event or task"; },
{ link = "delete";
label="Delete";
onclick = "return deleteEvent(this);";
- image = "delete.png"; } ),
+ image = "delete.png";
+ tooltip = "Delete this event or task"; } ),
( { link = "today";
label="Go to Today";
onclick = "return gotoToday();";
- image = "goto-today.png" } ),
+ image = "goto-today.png";
+ tooltip = "Go to today"; } ),
( { link = "dayoverview";
label="Day View";
onclick = "return onDayOverview();";
- image = "day-view.png"; },
+ image = "day-view.png";
+ tooltip = "Switch to day view"; },
/* disabled until we fix the view */
/* { link = "dayoverview";
label="Multicolumn Day View";
onclick = "return onMulticolumnDayOverview();";
- image = "day-view-multicolumn.png"; }, */
+ image = "day-view-multicolumn.png";
+ tooltip = ""; }, */
{ link = "weekoverview";
label="Week View";
onclick = "return onWeekOverview();";
- image = "week-view.png"; },
+ image = "week-view.png";
+ tooltip = "Switch to week view"; },
{ link = "monthoverview";
label="Month View";
onclick = "return onMonthOverview();";
- image = "month-view.png"; } )
+ image = "month-view.png";
+ tooltip = "Switch to month view"; } )
)
{
NSString *objectId, *method, *uri;
id <WOActionResults> result;
- Class clientKlazz;
+ SOGoAppointmentFolder *co;
- clientKlazz = [[self clientObject] class];
- objectId = [clientKlazz globallyUniqueObjectId];
+ co = [self clientObject];
+ objectId = [co globallyUniqueObjectId];
if ([objectId length] > 0)
{
- method = [NSString stringWithFormat:@"%@/Calendar/%@/editAsAppointment",
- [self userFolderPath], objectId];
+ method = [NSString stringWithFormat:@"%@/%@/editAsAppointment",
+ [co soURL], objectId];
uri = [self completeHrefForMethod: method];
result = [self redirectToLocation: uri];
}
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSNull.h>
#import <Foundation/NSString.h>
+#import <Foundation/NSValue.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <SoObjects/SOGo/NSArray+Utilities.h>
#import <SoObjects/SOGo/NSObject+Utilities.h>
#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
+#import <SoObjects/Appointments/SOGoAppointmentFolders.h>
+
+#import <UI/Common/WODirectAction+SOGo.h>
#import "NSArray+Scheduler.h"
return aptFolder;
}
-- (NSArray *) _activeCalendarFolders
-{
- NSMutableArray *activeFolders;
- NSEnumerator *folders;
- NSDictionary *currentFolderDict;
- SOGoAppointmentFolder *currentFolder, *clientObject;
-
- activeFolders = [NSMutableArray new];
- [activeFolders autorelease];
-
- clientObject = [self clientObject];
-
- folders = [[clientObject 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 activeFolders;
-}
-
- (NSArray *) _fetchFields: (NSArray *) fields
forComponentOfType: (NSString *) component
{
NSMutableDictionary *infos, *currentInfo, *newInfo;
NSString *owner, *uid;
NSNull *marker;
+ SOGoAppointmentFolders *clientObject;
marker = [NSNull null];
infos = [NSMutableDictionary dictionary];
- folders = [[self _activeCalendarFolders] objectEnumerator];
+ clientObject = [self clientObject];
+
+ folders = [[clientObject subFolders] objectEnumerator];
currentFolder = [folders nextObject];
while (currentFolder)
{
- owner = [currentFolder ownerInContext: context];
- currentInfos = [[currentFolder fetchCoreInfosFrom: startDate
- to: endDate
- component: component] objectEnumerator];
- newInfo = [currentInfos nextObject];
- while (newInfo)
+ if ([currentFolder isActive])
{
- uid = [newInfo objectForKey: @"c_uid"];
- currentInfo = [infos objectForKey: uid];
- if (!currentInfo
- || [owner isEqualToString: userLogin])
+ owner = [currentFolder ownerInContext: context];
+ currentInfos = [[currentFolder fetchCoreInfosFrom: startDate
+ to: endDate
+ component: component] objectEnumerator];
+ newInfo = [currentInfos nextObject];
+ while (newInfo)
{
- [self _updatePrivacyInComponent: newInfo
- fromFolder: currentFolder];
- [newInfo setObject: owner forKey: @"c_owner"];
- [infos setObject: [newInfo objectsForKeys: fields
- notFoundMarker: marker]
- forKey: uid];
+ uid = [newInfo objectForKey: @"c_uid"];
+ currentInfo = [infos objectForKey: uid];
+ if (!currentInfo
+ || [owner isEqualToString: userLogin])
+ {
+ [self _updatePrivacyInComponent: newInfo
+ fromFolder: currentFolder];
+ [newInfo setObject: [currentFolder nameInContainer]
+ forKey: @"c_folder"];
+ // [newInfo setObject: owner forKey: @"c_owner"];
+ [infos setObject: [newInfo objectsForKeys: fields
+ notFoundMarker: marker]
+ forKey: uid];
+ }
+ newInfo = [currentInfos nextObject];
}
- newInfo = [currentInfos nextObject];
}
currentFolder = [folders nextObject];
}
{
WOResponse *response;
- response = [context response];
+ response = [self responseWithStatus: 200];
[response setHeader: @"text/plain; charset=utf-8"
forKey: @"content-type"];
- [response setStatus: 200];
[response appendContentString: [data jsonRepresentation]];
return response;
[self _setupContext];
newEvents = [NSMutableArray array];
- fields = [NSArray arrayWithObjects: @"c_name", @"c_owner", @"c_status",
+ fields = [NSArray arrayWithObjects: @"c_name", @"c_folder", @"c_status",
@"c_title", @"c_startdate", @"c_enddate", @"c_location",
@"c_isallday", nil];
events = [[self _fetchFields: fields
[self _setupContext];
- fields = [NSArray arrayWithObjects: @"c_name", @"c_owner", @"c_status",
+ fields = [NSArray arrayWithObjects: @"c_name", @"c_folder", @"c_status",
@"c_title", @"c_enddate", nil];
tasks = [[self _fetchFields: fields
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSString.h>
+#import <Foundation/NSTimeZone.h>
#import <Foundation/NSUserDefaults.h>
#import <Foundation/NSValue.h>
@implementation UIxCalMainView
+- (NSString *) userUTCOffset
+{
+ NSTimeZone *userTZ;
+
+ userTZ = [[context activeUser] timeZone];
+
+ return [NSString stringWithFormat: @"%d", [userTZ secondsFromGMT]];
+}
+
- (NSArray *) monthMenuItems
{
unsigned int count;
#ifndef UIXCALENDARSELECTOR_H
#define UIXCALENDARSELECTOR_H
+#import <UI/SOGoUI/UIxComponent.h>
+
@class NSArray;
@class NSMutableArray;
@class NSDictionary;
-@class NSMutableDictionary;
@class NSString;
-@class iCalPerson;
@interface UIxCalendarSelector : UIxComponent
{
- NSMutableDictionary *colors;
-
- NSDictionary *currentCalendarFolder;
- NSString *currentCalendarLogin;
+ NSMutableArray *calendars;
+ NSDictionary *currentCalendar;
}
-- (NSArray *) calendarFolders;
-
-- (void) setCurrentCalendarFolder: (NSDictionary *) newCurrentCalendarFolder;
-- (NSDictionary *) currentCalendarFolder;
+- (NSArray *) calendars;
-- (NSString *) currentCalendarSpanBG;
-- (NSString *) currentCalendarLogin;
-- (NSString *) currentCalendarStyle;
+- (void) setCurrentCalendar: (NSDictionary *) newCalendar;
+- (NSDictionary *) currentCalendar;
@end
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
-#import <Foundation/NSString.h>
-#import <Foundation/NSUserDefaults.h>
+#import <Foundation/NSValue.h>
-#import <NGExtensions/NGExtensions.h>
-#import <NGCards/iCalPerson.h>
-
-#import <SOGo/SOGoUser.h>
-#import <SOGoUI/UIxComponent.h>
+#import <SOGo/NSDictionary+Utilities.h>
#import <Appointments/SOGoAppointmentFolder.h>
+#import <Appointments/SOGoAppointmentFolders.h>
#import "UIxCalendarSelector.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;
+// static inline char
+// darkenedColor (const char value)
+// {
+// char newValue;
- return 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;
+// }
static inline NSString *
colorForNumber (unsigned int number)
{
if ((self = [super init]))
{
- colors = nil;
- currentCalendarFolder = nil;
+ calendars = nil;
+ currentCalendar = nil;
}
return self;
- (void) dealloc
{
- [currentCalendarFolder release];
- [colors release];
+ [calendars release];
+ [currentCalendar release];
[super dealloc];
}
-- (NSArray *) calendarFolders
+- (NSArray *) calendars
{
- NSArray *calendarFolders;
- NSEnumerator *newFolders;
- NSDictionary *currentFolder;
- unsigned int count;
-
- calendarFolders = [[self clientObject] calendarFolders];
- if (!colors)
+ NSArray *folders;
+ SOGoAppointmentFolder *folder;
+ NSMutableDictionary *calendar;
+ unsigned int count, max;
+ NSString *folderId, *folderName;
+ NSNumber *isActive;
+
+ if (!calendars)
{
- colors = [NSMutableDictionary new];
- count = 0;
- newFolders = [calendarFolders objectEnumerator];
- currentFolder = [newFolders nextObject];
- while (currentFolder)
+ folders = [[self clientObject] subFolders];
+ max = [folders count];
+ calendars = [[NSMutableArray alloc] initWithCapacity: max];
+ for (count = 0; count < max; count++)
{
- [colors setObject: colorForNumber (count)
- forKey: [currentFolder objectForKey: @"folder"]];
- count++;
- currentFolder = [newFolders nextObject];
+ folder = [folders objectAtIndex: count];
+ calendar = [NSMutableDictionary dictionary];
+ folderName = [folder nameInContainer];
+ [calendar setObject:
+ [NSString stringWithFormat: @"/%@", folderName]
+ forKey: @"id"];
+ [calendar setObject: [folder displayName]
+ forKey: @"displayName"];
+ [calendar setObject: folderName forKey: @"folder"];
+ [calendar setObject: colorForNumber (count)
+ forKey: @"color"];
+ isActive = [NSNumber numberWithBool: [folder isActive]];
+ [calendar setObject: isActive forKey: @"active"];
+ [calendars addObject: calendar];
}
}
- return calendarFolders;
+ return calendars;
}
-- (void) setCurrentCalendarFolder: (NSDictionary *) newCurrentCalendarFolder
+- (void) setCurrentCalendar: (NSDictionary *) newCalendar
{
- ASSIGN (currentCalendarFolder, newCurrentCalendarFolder);
+ ASSIGN (currentCalendar, newCalendar);
}
-- (NSDictionary *) currentCalendarFolder
+- (NSDictionary *) currentCalendar
{
- return currentCalendarFolder;
-}
-
-- (NSString *) currentCalendarSpanBG
-{
- NSString *colorKey;
-
- colorKey = [currentCalendarFolder objectForKey: @"folder"];
-
- return [colors objectForKey: colorKey];
-}
-
-- (NSString *) currentCalendarLogin
-{
- NSArray *parts;
- NSMutableString *login;
-
- login = [NSMutableString string];
- parts = [[currentCalendarFolder objectForKey: @"folder"]
- componentsSeparatedByString: @":"];
- [login appendString: (([parts count] > 1)
- ? [parts objectAtIndex: 0]
- : [[context activeUser] login])];
- [login replaceString: @"." withString: @"_"];
- [login replaceString: @"#" withString: @"_"];
- [login replaceString: @"@" withString: @"_"];
-
- return login;
+ return currentCalendar;
}
- (NSString *) currentCalendarStyle
{
- NSString *color;
-
- color = [self currentCalendarSpanBG];
-
- return [NSString stringWithFormat: @"color: %@; background-color: %@;",
- color, color];
+ return [currentCalendar
+ keysWithFormat: @"color: %{color}; background-color: %{color};"];
}
@end /* UIxCalendarSelector */
#import <NGExtensions/NSString+misc.h>
#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
+#import <SoObjects/Appointments/SOGoAppointmentFolders.h>
#import <SoObjects/Appointments/SOGoAppointmentObject.h>
#import <SoObjects/Appointments/SOGoTaskObject.h>
#import <SoObjects/SOGo/NSString+Utilities.h>
- (NSArray *) calendarList
{
- SOGoAppointmentFolder *folder;
+ SOGoAppointmentFolder *calendar, *currentCalendar;
+ SOGoAppointmentFolders *calendarParent;
NSEnumerator *allCalendars;
- NSDictionary *currentCalendar;
if (!calendarList)
{
calendarList = [NSMutableArray new];
- folder = [[self clientObject] container];
- allCalendars = [[folder calendarFolders] objectEnumerator];
+ calendar = [[self clientObject] container];
+ calendarParent = [calendar container];
+ allCalendars = [[calendarParent subFolders] objectEnumerator];
currentCalendar = [allCalendars nextObject];
while (currentCalendar)
{
- if ([[currentCalendar objectForKey: @"active"] boolValue])
+ if ([currentCalendar isActive])
[calendarList addObject: currentCalendar];
currentCalendar = [allCalendars nextObject];
}
{
NSString *objectId, *method, *uri;
id <WOActionResults> result;
- Class clientKlazz;
+ SOGoAppointmentFolder *co;
- clientKlazz = [[self clientObject] class];
- objectId = [clientKlazz globallyUniqueObjectId];
+ co = [self clientObject];
+ objectId = [co globallyUniqueObjectId];
if ([objectId length] > 0)
{
- method = [NSString stringWithFormat:@"%@/Calendar/%@/editAsTask",
- [self userFolderPath], objectId];
+ method = [NSString stringWithFormat:@"%@/%@/editAsTask",
+ [co soURL], objectId];
uri = [self completeHrefForMethod: method];
result = [self redirectToLocation: uri];
}
};
categories = {
- SOGoAppointmentFolder = {
+ SOGoAppointmentFolders = {
slots = {
toolbar = {
protectedBy = "View";
- value = "SOGoAppointmentFolder.toolbar";
+ value = "SOGoAppointmentFolders.toolbar";
};
};
methods = {
protectedBy = "View";
pageName = "UIxCalMonthView";
};
- newevent = {
- protectedBy = "Add Documents, Images, and Files";
- pageName = "UIxAppointmentEditor";
- actionName = "new";
- };
- newtask = {
- protectedBy = "Add Documents, Images, and Files";
- pageName = "UIxTaskEditor";
- actionName = "new";
- };
show = {
protectedBy = "View";
pageName = "UIxCalView";
pageName = "UIxAppointmentProposal";
actionName = "proposalSearch";
};
+ userRights = {
+ protectedBy = "ReadAcls";
+ pageName = "UIxCalUserRightsEditor";
+ };
+ saveUserRights = {
+ protectedBy = "SaveAcls";
+ pageName = "UIxCalUserRightsEditor";
+ actionName = "saveUserRights";
+ };
+ };
+ };
+
+ SOGoAppointmentFolder = {
+ methods = {
+ newevent = {
+ protectedBy = "Add Documents, Images, and Files";
+ pageName = "UIxAppointmentEditor";
+ actionName = "new";
+ };
+ newtask = {
+ protectedBy = "Add Documents, Images, and Files";
+ pageName = "UIxTaskEditor";
+ actionName = "new";
+ };
batchDelete = {
protectedBy = "Delete Objects";
pageName = "UIxCalMainView";
actionName = "batchDelete";
};
- updateCalendars = {
+
+ show = {
protectedBy = "View";
+ pageName = "UIxCalView";
+ actionName = "redirectForUIDs";
+ };
+ batchDelete = {
+ protectedBy = "Delete Objects";
pageName = "UIxCalMainView";
- actionName = "updateCalendars";
+ actionName = "batchDelete";
};
editAttendees = {
protectedBy = "View";
};
};
};
+
SOGoCalendarComponent = {
};
pageName = "UIxAppointmentEditor";
actionName = "decline";
};
+ editAttendees = {
+ protectedBy = "View";
+ pageName = "UIxAttendeesEditor";
+ };
};
};
<ul id="contactFolders">
<var:foreach list="contactFolders" item="currentFolder"
><li var:id="currentContactFolderId"
- ><var:string value="currentContactFolderName" /></li
+ var:owner="currentContactFolderOwner"
+ ><var:string value="currentContactFolderName" /></li
></var:foreach
- ><var:foreach list="additionalFolders"
- item="currentAdditionalFolder"
- ><li var:id="currentAdditionalFolder" class="denied"
- ><var:string value="currentAdditionalFolderName" /></li
- ></var:foreach>
+ >
</ul>
<var:if condition="hasContactSelectionButtons">
var:class="messageSubjectCellStyleClass"
var:id="msgDivID"
><var:string value="message.envelope.subject"
- formatter="context.mailSubjectFormatter"
/></td
><td class="messageAddressColumn"
className="UIxPageFrame"
title="title"
>
+ <script type="text/javascript">
+ var UTCOffset = <var:string value="userUTCOffset"/>;
+ </script>
<div class="preload" style="visibility: hidden;">
<img rsrc:src="event-gradient.png"/>
</div>
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<style type="text/css">
- <var:foreach list="calendarFolders" item="currentCalendarFolder">
-.ownerIs<var:string value="currentCalendarLogin" />
-{ background-color: <var:string value="currentCalendarSpanBG" /> !important; }
+ <var:foreach list="calendars" item="currentCalendar">
+.calendarFolder<var:string value="currentCalendar.folder" />
+{ background-color: <var:string value="currentCalendar.color" /> !important; }
</var:foreach>
</style>
<div id="calendarSelector">
<span id="calendarSelectorButtons">
<a href="#" class="toolbarButton"
><span class="toolbarButton"><img rsrc:src="add-calendar.png"
- label:title="Add..."
+ label:title="New Calendar..."
+ /></span></a>
+ <a href="#" class="toolbarButton"
+ ><span class="toolbarButton"><img rsrc:src="add-user-calendar.png"
+ label:title="Subscribe to a Calendar..."
/></span></a>
<a href="#" class="toolbarButton"
><span class="toolbarButton"><img rsrc:src="remove-calendar.png"
- label:title="Remove"
+ label:title="Remove the selected Calendar"
/></span></a>
</span>
<ul id="calendarList" multiselect="yes">
- <var:foreach list="calendarFolders" item="currentCalendarFolder"
- ><li class="denied" var:id="currentCalendarFolder.folder">
+ <var:foreach list="calendars" item="currentCalendar"
+ ><li class="denied" var:id="currentCalendar.id">
<input type="checkbox" class="checkBox"
const:disabled="disabled"
- var:checked="currentCalendarFolder.active" />
+ var:checked="currentCalendar.active" />
<div class="colorBox" var:style="currentCalendarStyle">OO</div>
- <var:string value="currentCalendarFolder.displayName"
+ <var:string value="currentCalendar.displayName"
/></li>
</var:foreach>
</ul>
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
- xmlns:label="OGo:label"
+ xmlns:label="OGo:label"
><var:string var:value="doctype" const:escapeHTML="NO" />
<var:if condition="hideFrame" const:negate="YES"
><html>
><span class="toolbarButton"
><img class="buttonImage"
var:src="buttonImage"
- var:alt="buttonInfo.image"
+ var:alt="buttonInfo.tooltip"
/><var:if condition="hasMenu"
><img class="buttonMenuArrow"
rsrc:src="arrow-dwn-sharp.gif"
- var:alt="buttonInfo.image"
+ var:alt="buttonInfo.tooltip"
/></var:if
><br
/><span class="buttonLabel"
><span class="disabledToolbarButton"
><img class="buttonImage"
var:src="buttonImage"
- var:alt="buttonInfo.image"
+ var:alt="buttonInfo.tooltip"
/><br
/><span class="buttonLabel"
><var:string
errortext = errortext + labels.error_missingrecipients + "\n";
if (errortext.length > 0) {
- alert(labels.error_validationfailed.decodeEntities() + ":\n"
- + errortext.decodeEntities());
+ alert(labels.error_validationfailed + ":\n"
+ + errortext);
return false;
}
return true;
}
function onAddressBookNew(event) {
- var name = window.prompt(labels["Name of the Address Book"].decodeEntities());
- if (name) {
- if (document.newAbAjaxRequest) {
- document.newAbAjaxRequest.aborted = true;
- document.newAbAjaxRequest.abort();
- }
- var url = ApplicationBaseURL + "/newAb?name=" + name;
- document.newAbAjaxRequest
- = triggerAjaxRequest(url, newAbCallback, name);
- }
+ createFolder(window.prompt(labels["Name of the Address Book"]),
+ appendAddressBook);
preventDefault(event);
}
function appendAddressBook(name, folder) {
- var li = document.createElement("li");
- $("contactFolders").appendChild(li);
- li.setAttribute("id", folder);
- li.appendChild(document.createTextNode(name));
- setEventsOnContactFolder(li);
+ if (folder)
+ folder = accessToSubscribedFolder(folder);
+ else
+ folder = "/" + name;
+ var li = document.createElement("li");
+ $("contactFolders").appendChild(li);
+ li.setAttribute("id", folder);
+ li.appendChild(document.createTextNode(name));
+ setEventsOnContactFolder(li);
}
-function newAbCallback(http) {
+function newFolderCallback(http) {
if (http.readyState == 4
&& http.status == 201) {
var name = http.callbackData;
var selector = $("contactFolders");
var nodes = selector.getSelectedNodes();
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();
- }
+ 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();
+ }
}
preventDefault(event);
}
function deletePersonalAddressBook(folderId) {
- var label
- = labels["Are you sure you want to delete the selected address book?"];
- if (window.confirm(label.decodeEntities())) {
- if (document.deletePersonalABAjaxRequest) {
- document.deletePersonalABAjaxRequest.aborted = true;
- document.deletePersonalABAjaxRequest.abort();
- }
- var url = ApplicationBaseURL + "/" + folderId + "/delete";
- document.deletePersonalABAjaxRequest
- = triggerAjaxRequest(url, deletePersonalAddressBookCallback,
- folderId);
- }
+ var label
+ = labels["Are you sure you want to delete the selected address book?"];
+ if (window.confirm(label)) {
+ if (document.deletePersonalABAjaxRequest) {
+ document.deletePersonalABAjaxRequest.aborted = true;
+ document.deletePersonalABAjaxRequest.abort();
+ }
+ var url = ApplicationBaseURL + "/" + folderId + "/deleteFolder";
+ document.deletePersonalABAjaxRequest
+ = triggerAjaxRequest(url, deletePersonalAddressBookCallback,
+ folderId);
+ }
}
function deletePersonalAddressBookCallback(http) {
if (http.readyState == 4) {
- if (http.status == 200) {
- var ul = $("contactFolders");
+ if (isHttpStatus204(http.status)) {
+ var ul = $("contactFolders");
- var children = ul.childNodesWithTag("li");
- var i = 0;
- var done = false;
- while (!done && i < children.length) {
- var currentFolderId = children[i].getAttribute("id").substr(1);
- if (currentFolderId == http.callbackData) {
- ul.removeChild(children[i]);
- done = true;
- }
- else
- i++;
+ var children = ul.childNodesWithTag("li");
+ var i = 0;
+ var done = false;
+ while (!done && i < children.length) {
+ var currentFolderId = children[i].getAttribute("id").substr(1);
+ if (currentFolderId == http.callbackData) {
+ ul.removeChild(children[i]);
+ done = true;
}
- }
- document.deletePersonalABAjaxRequest = null;
+ else
+ i++;
+ }
+ }
+ document.deletePersonalABAjaxRequest = null;
}
else
- log ("ajax problem 5: " + http.status);
+ log ("ajax problem 5: " + http.status);
}
function configureDragHandles() {
onContactFoldersContextMenu.bindAsEventListener(node), false);
}
+function onMenuModify(event) {
+ var folders = $("contactFolders");
+ var selected = folders.getSelectedNodes()[0];
+
+ if (UserLogin == selected.getAttribute("owner")) {
+ var currentName = selected.innerHTML;
+ var newName = window.prompt(labels["Address Book Name"],
+ currentName);
+ if (newName && newName.length > 0
+ && newName != currentName) {
+ var url = (URLForFolderID(selected.getAttribute("id"))
+ + "/renameFolder?name=" + escape(newName.utf8encode()));
+ triggerAjaxRequest(url, folderRenameCallback,
+ {node: selected, name: newName});
+ }
+ } else
+ window.alert(clabels["Unable to rename that folder!"]);
+}
+
+function folderRenameCallback(http) {
+ if (http.readyState == 4) {
+ if (isHttpStatus204(http.status)) {
+ var dict = http.callbackData;
+ dict["node"].innerHTML = dict["name"];
+ }
+ }
+}
+
function onMenuSharing(event) {
var folders = $("contactFolders");
var selected = folders.getSelectedNodes()[0];
function getMenus() {
var menus = {};
- menus["contactFoldersMenu"] = new Array(null, "-", null,
+ menus["contactFoldersMenu"] = new Array(onMenuModify, "-", null,
null, "-", null, "-",
onMenuSharing);
menus["contactMenu"] = new Array(onMenuEditContact, "-",
function mailListMarkMessage(event) {
var http = createHTTPClient();
- var url = ApplicationBaseURL + currentMailbox + "/" + action + "?uid=" + msguid;
+ var url = ApplicationBaseURL + currentMailbox + "/" + msguid + "/" + action;
if (http) {
// TODO: add parameter to signal that we are only interested in OK
}
function ctxFolderDelete(sender) {
- if (!confirm("Delete current folder?").decodeEntities())
+ if (!confirm("Delete current folder?"))
return false;
// TODO: should use a form-POST or AJAX
function onPrintCurrentMessage(event) {
var rowIds = $("messageList").getSelectedRowsId();
if (rowIds.length == 0) {
- window.alert(labels["Please select a message to print."].decodeEntities());
+ window.alert(labels["Please select a message to print."]);
}
else if (rowIds.length > 1) {
- window.alert(labels["Please select only one message to print."].decodeEntities());
+ window.alert(labels["Please select only one message to print."]);
}
else
window.print();
var used = mbQuotas["usedSpace"];
var max = mbQuotas["maxQuota"];
var percents = (Math.round(used * 10000 / max) / 100);
- var format = labels["quotasFormat"].decodeEntities();
+ var format = labels["quotasFormat"];
var text = format.formatted(used, max, percents);
window.status = text;
}
}
function onMenuCreateFolder(event) {
- var name = window.prompt(labels["Name :"].decodeEntities(), "");
+ var name = window.prompt(labels["Name :"], "");
if (name && name.length > 0) {
var folderID = document.menuTarget.getAttribute("dataname");
var urlstr = URLForFolderID(folderID) + "/createFolder?name=" + name;
function onMenuRenameFolder(event) {
var name = window.prompt(labels["Enter the new name of your folder :"]
- .decodeEntities(),
+ ,
"");
if (name && name.length > 0) {
var folderID = document.menuTarget.getAttribute("dataname");
}
function onMenuDeleteFolder(event) {
- var answer = window.confirm(labels["Do you really want to move this folder into the trash ?"].decodeEntities());
+ var answer = window.confirm(labels["Do you really want to move this folder into the trash ?"]);
if (answer) {
var folderID = document.menuTarget.getAttribute("dataname");
var urlstr = URLForFolderID(folderID) + "/deleteFolder";
&& http.status == 204)
initMailboxTree();
else
- window.alert(labels["Operation failed"].decodeEntities());
+ window.alert(labels["Operation failed"]);
}
function folderRefreshCallback(http) {
refreshCurrentFolder();
}
else
- window.alert(labels["Operation failed"].decodeEntities());
+ window.alert(labels["Operation failed"]);
}
function getMenus() {
background-color: #d4d0c8;
margin: 0px auto;
margin-top: 5em;
- padding: 10px;
+ padding: 5px;
border: 2px solid transparent;
- width: 197px;
- height: 300px;
+ width: 200px;
+ height: 315px;
-moz-border-top-colors: #efebe7 #fff;
-moz-border-left-colors: #efebe7 #fff;
-moz-border-right-colors: #000 #9c9a94 transparent;
{ border: 0px;
margin: 0px;
padding: 0px;
- height: 192px;
- width: 192px; }
+ height: 200px;
+ width: 200px; }
DIV#loginScreen INPUT.textField
{ width: 187px; }
var contactSelectorAction = 'calendars-contacts';
var eventsToDelete = new Array();
-var ownersOfEventsToDelete = new Array();
+var calendarsOfEventsToDelete = new Array();
var usersRightsWindowHeight = 250;
var usersRightsWindowWidth = 502;
if (!day)
day = currentDay;
- var user = UserLogin;
- if (sender.parentNode.getAttribute("id") != "toolbar"
- && currentView == "multicolumndayview" && type == "event")
- user = sender.parentNode.parentNode.getAttribute("user");
-
var hour = sender.hour;
if (!hour)
hour = sender.getAttribute("hour");
- var urlstr = UserFolderURL + "../" + user + "/Calendar/new" + type;
+ var folderID = getSelectedFolder();
+ var urlstr = ApplicationBaseURL + folderID + "/new" + type;
var params = new Array();
if (day)
params.push("day=" + day);
return false; /* stop following the link */
}
+function getSelectedFolder() {
+ var folder;
+
+ var nodes = $("calendarList").getSelectedRows();
+ if (nodes.length > 0)
+ folder = nodes[0].getAttribute("id");
+ else
+ folder = "/personal";
+
+ return folder;
+}
+
function onMenuNewEventClick(event) {
newEvent(this, "event");
}
newEvent(this, "task");
}
-function _editEventId(id, owner) {
- var urlBase;
- if (owner)
- urlBase = UserFolderURL + "../" + owner + "/";
- urlBase += "Calendar/"
-
- var urlstr = urlBase + id + "/edit";
+function _editEventId(id, calendar) {
+ var urlstr = ApplicationBaseURL + "/" + calendar + "/" + id + "/edit";
var targetname = "SOGo_edit_" + id;
var win = window.open(urlstr, "_blank",
"width=490,height=470,resizable=0");
for (var i = 0; i < nodes.length; i++)
_editEventId(nodes[i].getAttribute("id"),
- nodes[i].owner);
+ nodes[i].calendar);
} else if (selectedCalendarCell) {
_editEventId(selectedCalendarCell[0].cname,
- selectedCalendarCell[0].owner);
+ selectedCalendarCell[0].calendar);
}
return false; /* stop following the link */
function _batchDeleteEvents() {
var events = eventsToDelete.shift();
- var owner = ownersOfEventsToDelete.shift();
- var urlstr = (UserFolderURL + "../" + owner + "/Calendar/batchDelete?ids="
- + events.join('/'));
+ var calendar = calendarsOfEventsToDelete.shift();
+ var urlstr = (ApplicationBaseURL + "/" + calendar
+ + "/batchDelete?ids=" + events.join('/'));
document.deleteEventAjaxRequest = triggerAjaxRequest(urlstr,
deleteEventCallback,
events);
if (nodes.length > 0) {
var label = "";
if (listOfSelection == $("tasksList"))
- label = labels["taskDeleteConfirmation"].decodeEntities();
+ label = labels["taskDeleteConfirmation"];
else
- label = labels["eventDeleteConfirmation"].decodeEntities();
+ label = labels["eventDeleteConfirmation"];
if (confirm(label)) {
if (document.deleteEventAjaxRequest) {
document.deleteEventAjaxRequest.abort();
}
var sortedNodes = new Array();
- var owners = new Array();
+ var calendars = new Array();
for (var i = 0; i < nodes.length; i++) {
- var owner = nodes[i].owner;
- if (!sortedNodes[owner]) {
- sortedNodes[owner] = new Array();
- owners.push(owner);
+ var calendar = nodes[i].calendar;
+ if (!sortedNodes[calendar]) {
+ sortedNodes[calendar] = new Array();
+ calendars.push(calendar);
}
- sortedNodes[owner].push(nodes[i].cname);
+ sortedNodes[calendar].push(nodes[i].cname);
}
- for (var i = 0; i < owners.length; i++) {
- ownersOfEventsToDelete.push(owners[i]);
- eventsToDelete.push(sortedNodes[owners[i]]);
+ for (var i = 0; i < calendars.length; i++) {
+ calendarsOfEventsToDelete.push(calendars[i]);
+ eventsToDelete.push(sortedNodes[calendars[i]]);
}
_batchDeleteEvents();
}
}
}
else if (selectedCalendarCell) {
- var label = labels["eventDeleteConfirmation"].decodeEntities();
+ var label = labels["eventDeleteConfirmation"];
if (confirm(label)) {
if (document.deleteEventAjaxRequest) {
document.deleteEventAjaxRequest.aborted = true;
document.deleteEventAjaxRequest.abort();
}
eventsToDelete.push([selectedCalendarCell[0].cname]);
- ownersOfEventsToDelete.push(selectedCalendarCell[0].owner);
+ calendarsOfEventsToDelete.push(selectedCalendarCell[0].calendar);
_batchDeleteEvents();
}
}
closePseudoWin.style.top = "0px;";
closePseudoWin.style.left = "0px;";
closePseudoWin.style.right = "0px;";
- closePseudoWin.appendChild(document.createTextNode(labels["closeThisWindowMessage"].decodeEntities()));
+ closePseudoWin.appendChild(document.createTextNode(labels["closeThisWindowMessage"]));
document.body.appendChild(closeDiv);
document.body.appendChild(closePseudoWin);
}
}
function editDoubleClickedEvent(event) {
- _editEventId(this.cname, this.owner);
+ _editEventId(this.cname, this.calendar);
preventDefault(event);
event.cancelBubble = true;
$(row).addClassName("eventRow");
row.setAttribute("id", escape(data[i][0]));
row.cname = escape(data[i][0]);
- row.owner = data[i][1];
+ row.calendar = data[i][1];
var startDate = new Date();
startDate.setTime(data[i][4] * 1000);
Event.observe(listItem, "dblclick", editDoubleClickedEvent.bindAsEventListener(listItem));
listItem.setAttribute("id", data[i][0]);
$(listItem).addClassName(data[i][5]);
- var owner = data[i][1];
- listItem.owner = owner;
- $(listItem).addClassName("ownerIs" + owner.cssSafeString());
+ listItem.calendar = data[i][1];
+ $(listItem).addClassName("calendarFolder" + data[i][1]);
listItem.cname = escape(data[i][0]);
var input = document.createElement("input");
input.setAttribute("type", "checkbox");
}
function changeDateSelectorDisplay(day, keepCurrentDay) {
- var url = ApplicationBaseURL + "dateselector";
+ var url = ApplicationBaseURL + "/dateselector";
if (day)
url += "?day=" + day;
}
function changeCalendarDisplay(time, newView) {
- var url = ApplicationBaseURL + ((newView) ? newView : currentView);
+ var url = ApplicationBaseURL + "/" + ((newView) ? newView : currentView);
selectedCalendarCell = null;
document.refreshCalendarEventsAjaxRequest.aborted = true;
document.refreshCalendarEventsAjaxRequest.abort();
}
- var url = ApplicationBaseURL + "eventslist?sd=" + sd + "&ed=" + ed;
+ var url = ApplicationBaseURL + "/eventslist?sd=" + sd + "&ed=" + ed;
document.refreshCalendarEventsAjaxRequest
= triggerAjaxRequest(url, refreshCalendarEventsCallback,
{"startDate": sd, "endDate": ed});
var viewEndDate = ed.asDate();
var startDate = new Date();
- startDate.setTime(eventData[4] * 1000);
+ startDate.setTime(eventData[4] * 1000 + (1000 * UTCOffset));
var endDate = new Date();
- endDate.setTime(eventData[5] * 1000);
+ endDate.setTime(eventData[5] * 1000 + (1000 * UTCOffset));
var days = startDate.daysUpTo(endDate);
// log("day: " + days[i]);
if (i == 0) {
- var quarters = (startDate.getHours() * 4
- + Math.floor(startDate.getMinutes() / 15));
+ var quarters = (startDate.getUTCHours() * 4
+ + Math.floor(startDate.getUTCMinutes() / 15));
starts = quarters;
startHour = startDate.getDisplayHoursString();
endHour = endDate.getDisplayHoursString();
var ends;
var lasts;
if (i == days.length - 1) {
- var quarters = (endDate.getHours() * 4
- + Math.ceil(endDate.getMinutes() / 15));
+ var quarters = (endDate.getUTCHours() * 4
+ + Math.ceil(endDate.getUTCMinutes() / 15));
ends = quarters;
}
else
}
}
-function newEventDIV(cname, owner, starts, lasts,
+function newEventDIV(cname, calendar, starts, lasts,
startHour, endHour, title) {
var eventDiv = document.createElement("div");
eventDiv.cname = escape(cname);
- eventDiv.owner = owner;
+ eventDiv.calendar = calendar;
$(eventDiv).addClassName("event");
$(eventDiv).addClassName("starts" + starts);
$(eventDiv).addClassName("lasts" + lasts);
var innerDiv = document.createElement("div");
eventDiv.appendChild(innerDiv);
$(innerDiv).addClassName("eventInside");
- $(innerDiv).addClassName("ownerIs" + owner.cssSafeString());
+ $(innerDiv).addClassName("calendarFolder" + calendar);
var gradientDiv = document.createElement("div");
innerDiv.appendChild(gradientDiv);
document.eventsListAjaxRequest.aborted = true;
document.eventsListAjaxRequest.abort();
}
- var url = ApplicationBaseURL + href;
+ var url = ApplicationBaseURL + "/" + href;
document.eventsListAjaxRequest
= triggerAjaxRequest(url, eventsListCallback, href);
document.tasksListAjaxRequest.aborted = true;
document.tasksListAjaxRequest.abort();
}
- url = ApplicationBaseURL + href;
+ url = ApplicationBaseURL + "/" + href;
var tasksList = $("tasksList");
var selectedIds;
function updateTaskStatus(event) {
var taskId = this.parentNode.getAttribute("id");
- var taskOwner = this.parentNode.owner;
var newStatus = (this.checked ? 1 : 0);
var http = createHTTPClient();
//log("update task status: " + taskId + " to " + this.checked);
event.cancelBubble = true;
- url = (UserFolderURL + "../" + taskOwner
- + "/Calendar/" + taskId
- + "/changeStatus?status=" + newStatus);
+ url = (ApplicationBaseURL + "/" + this.parentNode.calendar
+ + "/" + taskId + "/changeStatus?status=" + newStatus);
if (http) {
// log ("url: " + url);
}
}
- if (!list.length) {
- list.push(UserLogin);
- nodes[0].childNodesWithTag("input")[0].checked = true;
- }
+// if (!list.length) {
+// list.push(UserLogin);
+// nodes[0].childNodesWithTag("input")[0].checked = true;
+// }
+
// ApplicationBaseURL = (UserFolderURL + "Groups/_custom_"
// + list.join(",") + "/Calendar/");
}
function calendarEntryCallback(http) {
- if (http.readyState == 4) {
+ if (http.readyState == 4) {
var denied = !isHttpStatus204(http.status);
var entry = $(http.callbackData);
if (denied)
}
var links = $("calendarSelectorButtons").childNodesWithTag("a");
- Event.observe(links[0], "click", onCalendarAdd);
- Event.observe(links[1], "click", onCalendarRemove);
+ Event.observe(links[0], "click", onCalendarNew);
+ Event.observe(links[1], "click", onCalendarAdd);
+ Event.observe(links[2], "click", onCalendarRemove);
}
-function onCalendarAdd(event) {
- openUserFolderSelector(onFolderSubscribeCB, "calendar");
+function onCalendarNew(event) {
+ createFolder(window.prompt(labels["Name of the Calendar"]),
+ appendCalendar);
+ preventDefault(event);
+}
- preventDefault(event);
+function onCalendarAdd(event) {
+ openUserFolderSelector(onFolderSubscribeCB, "calendar");
+ preventDefault(event);
}
function appendCalendar(folderName, folder) {
- var calendarList = $("calendarList");
- var lis = calendarList.childNodesWithTag("li");
- var color = indexColor(lis.length);
- //log ("color: " + color);
-
- var li = document.createElement("li");
- calendarList.appendChild(li);
-
- var checkBox = document.createElement("input");
- checkBox.setAttribute("type", "checkbox");
- li.appendChild(checkBox);
-
- li.appendChild(document.createTextNode(" "));
-
- var colorBox = document.createElement("div");
- li.appendChild(colorBox);
- li.appendChild(document.createTextNode(" " + folderName));
- colorBox.appendChild(document.createTextNode("OO"));
+ if (folder)
+ folder = accessToSubscribedFolder(folder);
+ else
+ folder = "/" + folderName;
- li.setAttribute("id", folder);
- Event.observe(li, "mousedown", listRowMouseDownHandler);
- Event.observe(li, "click", onRowClick);
- $(checkBox).addClassName("checkBox");
+// log ("append: " + folderName + "; folder: " + folder);
- Event.observe(checkBox, "click", updateCalendarStatus.bindAsEventListener(checkBox));
+ var calendarList = $("calendarList");
+ var lis = calendarList.childNodesWithTag("li");
+ var color = indexColor(lis.length + 100);
+ //log ("color: " + color);
- $(colorBox).addClassName("colorBox");
- if (color) {
- $(colorBox).setStyle({ color: color,
- backgroundColor: color });
- }
+ var li = document.createElement("li");
+ calendarList.appendChild(li);
- var contactId = folder.split(":")[0];
- var url = URLForFolderID(folder) + "/canAccessContent";
- triggerAjaxRequest(url, calendarEntryCallback, folder);
-
- if (!document.styleSheets) return;
- var theRules = new Array();
- var lastSheet = document.styleSheets[document.styleSheets.length - 1];
- if (lastSheet.insertRule) { // Mozilla
- lastSheet.insertRule('.ownerIs' + contactId.cssSafeString() + ' {'
- + ' background-color: '
- + color
- + ' !important; }', 0);
- }
- else { // IE
- lastSheet.addRule('.ownerIs' + contactId.cssSafeString(),
- ' background-color: '
- + color
- + ' !important; }');
- }
+ var checkBox = document.createElement("input");
+ checkBox.setAttribute("type", "checkbox");
+ li.appendChild(checkBox);
+
+ li.appendChild(document.createTextNode(" "));
+
+ var colorBox = document.createElement("div");
+ li.appendChild(colorBox);
+ li.appendChild(document.createTextNode(" " + folderName));
+ colorBox.appendChild(document.createTextNode("OO"));
+
+ li.setAttribute("id", folder);
+ Event.observe(li, "mousedown", listRowMouseDownHandler);
+ Event.observe(li, "click", onRowClick);
+ $(checkBox).addClassName("checkBox");
+
+ Event.observe(checkBox, "click",
+ updateCalendarStatus.bindAsEventListener(checkBox));
+
+ $(colorBox).addClassName("colorBox");
+ if (color)
+ $(colorBox).setStyle({color: color,
+ backgroundColor: color});
+
+ var url = URLForFolderID(folder) + "/canAccessContent";
+ triggerAjaxRequest(url, calendarEntryCallback, folder);
+
+ if (!document.styleSheets) return;
+ var theRules = new Array();
+ var lastSheet = document.styleSheets[document.styleSheets.length - 1];
+ if (lastSheet.insertRule) { // Mozilla
+ lastSheet.insertRule('.calendarFolder' + folder.substr(1) + ' {'
+ + ' background-color: '
+ + color
+ + ' !important; }', 0);
+ }
+ else { // IE
+ lastSheet.addRule('.calendarFolder' + folder.substr(1),
+ ' background-color: '
+ + color
+ + ' !important; }');
+ }
}
function onFolderSubscribeCB(folderData) {
var folder = $(folderData["folder"]);
if (!folder)
- appendCalendar(folderData["folderName"], folderData["folder"]);
+ appendCalendar(folderData["folderName"], folderData["folder"]);
}
function onFolderUnsubscribeCB(folderId) {
- var node = $(folderId);
- node.parentNode.removeChild(node);
+ var node = $(folderId);
+ node.parentNode.removeChild(node);
+ refreshEvents();
+ refreshTasks();
+ changeCalendarDisplay();
}
function onCalendarRemove(event) {
if (nodes.length > 0) {
nodes[0].deselect();
var folderId = nodes[0].getAttribute("id");
- var folderIdElements = folderId.split(":");
+ var folderIdElements = folderId.split("_");
if (folderIdElements.length > 1) {
- unsubscribeFromFolder(folderId, onFolderUnsubscribeCB, folderId);
+ unsubscribeFromFolder(folderId, onFolderUnsubscribeCB, folderId);
+ }
+ else {
+ var calId = folderIdElements[0].substr(1);
+ deletePersonalCalendar(calId);
}
}
preventDefault(event);
}
+function deletePersonalCalendar(folderId) {
+ var label
+ = labels["Are you sure you want to delete the selected calendar?"];
+ if (window.confirm(label)) {
+ if (document.deletePersonalCalendarAjaxRequest) {
+ document.deletePersonalCalendarAjaxRequest.aborted = true;
+ document.deletePersonalCalendarAjaxRequest.abort();
+ }
+ var url = ApplicationBaseURL + "/" + folderId + "/deleteFolder";
+ document.deletePersonalCalendarAjaxRequest
+ = triggerAjaxRequest(url, deletePersonalCalendarCallback, folderId);
+ }
+}
+
+function deletePersonalCalendarCallback(http) {
+ if (http.readyState == 4) {
+ if (isHttpStatus204(http.status)) {
+ var ul = $("calendarList");
+ var children = ul.childNodesWithTag("li");
+ var i = 0;
+ var done = false;
+ while (!done && i < children.length) {
+ var currentFolderId = children[i].getAttribute("id").substr(1);
+ if (currentFolderId == http.callbackData) {
+ ul.removeChild(children[i]);
+ done = true;
+ }
+ else
+ i++;
+ }
+ refreshEvents();
+ refreshTasks();
+ changeCalendarDisplay();
+ }
+ document.deletePersonalCalendarAjaxRequest = null;
+ }
+ else
+ log ("ajax problem 5: " + http.status);
+}
+
function configureLists() {
var list = $("tasksList");
list.multiselect = true;
refreshCallbackData["folder"]);
}
else
- refreshCallbackData["window"].alert(clabels["You cannot subscribe to a folder that you own!"]
- .decodeEntities());
+ refreshCallbackData["window"].alert(clabels["You cannot subscribe to a folder that you own!"]);
}
function openRightsForUserID(userID) {
e = $('summary');
if (e.value.length == 0) {
- if (!confirm(labels.validate_notitle.decodeEntities()))
+ if (!confirm(labels.validate_notitle))
return false;
}
e = $('startTime_date');
if (e.value.length != 10) {
- alert(labels.validate_invalid_startdate.decodeEntities());
+ alert(labels.validate_invalid_startdate);
return false;
}
startdate = e.calendar.prs_date(e.value);
if (startdate == null) {
- alert(labels.validate_invalid_startdate.decodeEntities());
+ alert(labels.validate_invalid_startdate);
return false;
}
e = $('endTime_date');
if (e.value.length != 10) {
- alert(labels.validate_invalid_enddate.decodeEntities());
+ alert(labels.validate_invalid_enddate);
return false;
}
enddate = e.calendar.prs_date(e.value);
if (enddate == null) {
- alert(labels.validate_invalid_enddate.decodeEntities());
+ alert(labels.validate_invalid_enddate);
return false;
}
// cuicui = '';
tmpdate = uixEarlierDate(startdate, enddate);
if (tmpdate == enddate) {
// window.alert(cuicui);
- alert(labels.validate_endbeforestart.decodeEntities());
+ alert(labels.validate_endbeforestart);
return false;
}
else if (tmpdate == null /* means: same date */) {
end = parseInt(document.forms[0]['endTime_time_hour'].value);
if (start > end) {
- alert(labels.validate_endbeforestart.decodeEntities());
+ alert(labels.validate_endbeforestart);
return false;
}
else if (start == end) {
start = parseInt(document.forms[0]['startTime_time_minute'].value);
end = parseInt(document.forms[0]['endTime_time_minute'].value);
if (start > end) {
- alert(labels.validate_endbeforestart.decodeEntities());
+ alert(labels.validate_endbeforestart);
return false;
}
}
preventDefault(event);
var urlInput = document.getElementById("url");
- var newUrl = window.prompt(labels["Target:"].decodeEntities(), urlInput.value);
+ var newUrl = window.prompt(labels["Target:"], urlInput.value);
if (newUrl != null) {
var documentHref = $("documentHref");
var documentLabel = $("documentLabel");
if (e.value.length == 0)
return true;
if (uixEmailRegex.test(e.value) != true)
- return confirm(labels.invalidemailwarn.decodeEntities());
+ return confirm(labels.invalidemailwarn);
e = $('homeMail');
if (e.value.length == 0)
return true;
if (uixEmailRegex.test(e.value) != true)
- return confirm(labels.invalidemailwarn.decodeEntities());
+ return confirm(labels.invalidemailwarn);
return true;
}
for (var i = 1; i < nodes.length; i++) {
var folderInfos = nodes[i].split(":");
var icon = ResourcesURL + '/';
- if (folderInfos[2] == 'contact')
+ if (folderInfos[2] == 'Contacts')
icon += 'tb-mail-addressbook-flat-16x16.png';
else
icon += 'calendar-folder-16x16.png';
errortext = errortext + labels.error_missingrecipients + "\n";
if (errortext.length > 0) {
- alert(labels.error_validationfailed.decodeEntities() + ":\n"
- + errortext.decodeEntities());
+ alert(labels.error_validationfailed + ":\n" + errortext);
return false;
}
return true;
dateValue = date.calendar.prs_date(date.value);
if (date.value.length != 10 || !dateValue) {
- alert(label.decodeEntities());
+ alert(label);
result = false;
} else
result = dateValue;
e = document.getElementById('summary');
if (e.value.length == 0
- && !confirm(labels.validate_notitle.decodeEntities()))
+ && !confirm(labels.validate_notitle))
return false;
e = document.getElementById('startTime_date');
tmpdate = uixEarlierDate(startdate, enddate);
if (tmpdate == enddate) {
// window.alert(cuicui);
- alert(labels.validate_endbeforestart.decodeEntities());
+ alert(labels.validate_endbeforestart);
return false;
}
else if (tmpdate == null /* means: same date */) {
end = parseInt(document.forms[0]['dueTime_time_hour'].value);
if (start > end) {
- alert(labels.validate_endbeforestart.decodeEntities());
+ alert(labels.validate_endbeforestart);
return false;
}
else if (start == end) {
start = parseInt(document.forms[0]['startTime_time_minute'].value);
end = parseInt(document.forms[0]['dueTime_time_minute'].value);
if (start > end) {
- alert(labels.validate_endbeforestart.decodeEntities());
+ alert(labels.validate_endbeforestart);
return false;
}
}
document.subscriptionAjaxRequest.aborted = true;
document.subscriptionAjaxRequest.abort();
}
+
var rfCbData = { method: refreshCallback, data: refreshCallbackData };
document.subscriptionAjaxRequest = triggerAjaxRequest(url,
folderSubscriptionCallback,
}
function unsubscribeFromFolder(folder, refreshCallback, refreshCallbackData) {
- if (document.body.hasClassName("popup")) {
- window.opener.unsubscribeFromFolder(folder, refreshCallback,
- refreshCallbackData);
- }
- else {
- var folderData = folder.split(":");
- var username = folderData[0];
- var folderPath = folderData[1];
- if (username != UserLogin) {
- var url = (UserFolderURL + "../" + username
- + "/" + folderPath + "/unsubscribe");
- if (document.unsubscriptionAjaxRequest) {
- document.unsubscriptionAjaxRequest.aborted = true;
- document.unsubscriptionAjaxRequest.abort();
- }
- var rfCbData = { method: refreshCallback, data: refreshCallbackData };
- document.unsubscriptionAjaxRequest
- = triggerAjaxRequest(url, folderUnsubscriptionCallback,
- rfCbData);
+ if (document.body.hasClassName("popup")) {
+ window.opener.unsubscribeFromFolder(folder, refreshCallback,
+ refreshCallbackData);
+ }
+ else {
+ var folderData = folder.split("+");
+ var username = folderData[0];
+ var folderPath = folderData[1];
+ if (username != UserLogin) {
+ var url = (ApplicationBaseURL + folder + "/unsubscribe");
+ if (document.unsubscriptionAjaxRequest) {
+ document.unsubscriptionAjaxRequest.aborted = true;
+ document.unsubscriptionAjaxRequest.abort();
}
- else
- window.alert(clabels["You cannot unsubscribe from a folder that you own!"].decodeEntities());
- }
+ var rfCbData = { method: refreshCallback, data: refreshCallbackData };
+ document.unsubscriptionAjaxRequest
+ = triggerAjaxRequest(url, folderUnsubscriptionCallback,
+ rfCbData);
+ }
+ else
+ window.alert(clabels["You cannot unsubscribe from a folder that you own!"].decodeEntities());
+ }
+}
+
+function accessToSubscribedFolder(serverFolder) {
+ var folder;
+
+ var parts = serverFolder.split(":");
+ if (parts.length > 1) {
+ var paths = parts[1].split("/");
+ folder = "/" + parts[0] + "_" + paths[2];
+ }
+ else
+ folder = serverFolder;
+
+ return folder;
}
function listRowMouseDownHandler(event) {
configureDragHandles();
configureSortableTableHeaders();
configureLinkBanner();
+ translateLabels();
var progressImage = $("progressIndicator");
if (progressImage)
progressImage.parentNode.removeChild(progressImage);
Event.observe(document.body, "contextmenu", onBodyClickContextMenu);
}
+function translateLabels() {
+ if (typeof labels != "undefined") {
+ for (var key in labels)
+ labels[key] = labels[key].decodeEntities();
+ }
+
+ if (typeof clabels != "undefined") {
+ for (var key in clabels)
+ clabels[key] = clabels[key].decodeEntities();
+ }
+}
+
function onBodyClickContextMenu(event) {
preventDefault(event);
}
}
}
+/* folder creation */
+function createFolder(name, okCB, notOkCB) {
+ if (name) {
+ if (document.newFolderAjaxRequest) {
+ document.newFolderAjaxRequest.aborted = true;
+ document.newFolderAjaxRequest.abort();
+ }
+ var url = ApplicationBaseURL + "/createFolder?name=" + name;
+ document.newFolderAjaxRequest
+ = triggerAjaxRequest(url, createFolderCallback,
+ {name: name,
+ okCB: okCB,
+ notOkCB: notOkCB});
+ }
+}
+
+function createFolderCallback(http) {
+ if (http.readyState == 4) {
+ var data = http.callbackData;
+ if (http.status == 201) {
+ if (data.okCB)
+ data.okCB(data.name, "/" + http.responseText);
+ }
+ else {
+ if (data.notOkCB)
+ data.notOkCB(name);
+ else
+ log("ajax problem:" + http.status);
+ }
+ }
+}
+
addEvent(window, 'load', onLoadHandler);
function parent$(element) {