merge of 'baf4c7f8461dec960162ae0da21047d576421c14'

and 'fefb3f05edb2d5e5ba63661ae145d0369e47b444'

Monotone-Parent: baf4c7f8461dec960162ae0da21047d576421c14
Monotone-Parent: fefb3f05edb2d5e5ba63661ae145d0369e47b444
Monotone-Revision: 9ef1fb2c66953b8ada0d55d0eec183621a71ebab

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2007-09-11T20:58:35
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Wolfgang Sourdeau
2007-09-11 20:58:35 +00:00
32 changed files with 611 additions and 476 deletions

View File

@@ -1,3 +1,60 @@
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

View File

@@ -43,16 +43,6 @@
@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;

View File

@@ -1,6 +1,6 @@
/* 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>
*
@@ -23,25 +23,9 @@
#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

View File

@@ -1,6 +1,6 @@
/* 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>
*
@@ -20,7 +20,6 @@
* Boston, MA 02111-1307, USA.
*/
/* exchange folder types: */
/* MailItems IPF.Note
ContactItems IPF.Contact
AppointmentItems IPF.Appointment
@@ -28,23 +27,25 @@
TaskItems IPF.Task
JournalItems IPF.Journal */
#import <Foundation/NSDictionary.h>
// #import <Foundation/NSDictionary.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import <Foundation/NSEnumerator.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 <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 <GDLContentStore/GCSFolderManager.h>
// #import <GDLContentStore/GCSChannelManager.h>
// #import <GDLAccess/EOAdaptorChannel.h>
// #import <GDLContentStore/NSURL+GCS.h>
#import <SoObjects/SOGo/LDAPUserManager.h>
#import <SoObjects/SOGo/SOGoPermissions.h>
// #import <SoObjects/SOGo/SOGoPermissions.h>
#import "SOGoContactGCSFolder.h"
#import "SOGoContactLDAPFolder.h"
@@ -52,89 +53,14 @@
@implementation SOGoContactFolders
- (id) init
+ (NSString *) gcsFolderType
{
if ((self = [super init]))
{
contactFolders = nil;
OCSPath = nil;
}
return self;
return @"Contact";
}
- (void) dealloc
+ (Class) subFolderClass
{
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"];
}
}
- (void) appendPersonalSources
{
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
@@ -150,119 +76,13 @@
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
{
return @"personal";
}
@end

View File

@@ -30,9 +30,6 @@
@class NSString;
@interface SOGoContactGCSFolder : SOGoFolder <SOGoContactFolder>
{
NSString *displayName;
}
@end

View File

@@ -41,47 +41,11 @@
@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
@@ -105,7 +69,6 @@
BOOL isPut;
isPut = NO;
/* first check attributes directly bound to the application */
obj = [super lookupName:_key inContext:_ctx acquire:NO];
if (!obj)
{
@@ -273,14 +236,6 @@
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

View File

@@ -37,9 +37,12 @@
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

View File

@@ -41,11 +41,11 @@
@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
@@ -68,9 +68,9 @@
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]))

View File

@@ -21,8 +21,9 @@ FHS_HEADER_DIRS = SOGo
libSOGo_HEADER_FILES = \
SOGoObject.h \
SOGoFolder.h \
SOGoContentObject.h \
SOGoFolder.h \
SOGoParentFolder.h \
SOGoUserFolder.h \
SOGoGroupsFolder.h \
SOGoGroupFolder.h \
@@ -50,8 +51,9 @@ libSOGo_HEADER_FILES = \
libSOGo_OBJC_FILES = \
SOGoObject.m \
SOGoFolder.m \
SOGoContentObject.m \
SOGoFolder.m \
SOGoParentFolder.m \
SOGoUserFolder.m \
SOGoGroupsFolder.m \
SOGoGroupFolder.m \

View File

@@ -43,7 +43,8 @@
@interface SOGoFolder : SOGoObject
{
NSString *ocsPath;
NSString *displayName;
NSString *ocsPath;
GCSFolder *ocsFolder;
NSMutableDictionary *aclCache;
}
@@ -52,6 +53,15 @@
/* accessors */
+ (id) folderWithName: (NSString *) aName
andDisplayName: (NSString *) aDisplayName
inContainer: (id) aContainer;
- (id) initWithName: (NSString *) aName
andDisplayName: (NSString *) aDisplayName
inContainer: (id) aContainer;
- (NSString *) displayName;
- (void) setOCSPath: (NSString *)_Path;
- (NSString *) ocsPath;

View File

@@ -29,6 +29,7 @@
#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>
@@ -85,14 +86,30 @@ static NSString *defaultUserID = @"<default>";
}
sequence++;
f = [[NSDate date] timeIntervalSince1970];
return [NSString stringWithFormat:@"%0X-%0X-%0X-%0X",
pid, *(int *)&f, sequence++, random];
pid, (int) f, sequence++, random];
}
+ (id) folderWithName: (NSString *) aName
andDisplayName: (NSString *) aDisplayName
inContainer: (id) aContainer
{
id newFolder;
newFolder = [[self alloc] initWithName: aName
andDisplayName: aDisplayName
inContainer: aContainer];
[newFolder autorelease];
return newFolder;
}
- (id) init
{
if ((self = [super init]))
{
displayName = nil;
ocsPath = nil;
ocsFolder = nil;
aclCache = [NSMutableDictionary new];
@@ -101,11 +118,23 @@ static NSString *defaultUserID = @"<default>";
return self;
}
- (id) initWithName: (NSString *) aName
andDisplayName: (NSString *) aDisplayName
inContainer: (id) aContainer
{
if ((self = [self initWithName: aName
inContainer: aContainer]))
ASSIGN (displayName, aDisplayName);
return self;
}
- (void) dealloc
{
[ocsFolder release];
[ocsPath release];
[aclCache release];
[displayName release];
[super dealloc];
}
@@ -154,6 +183,11 @@ static NSString *defaultUserID = @"<default>";
return NO;
}
- (NSString *) displayName
{
return displayName;
}
- (GCSFolder *) ocsFolder
{
GCSFolder *folder;
@@ -196,7 +230,15 @@ static NSString *defaultUserID = @"<default>";
- (NSException *) delete
{
return [[self folderManager] deleteFolderAtPath: ocsPath];
NSException *error;
if ([nameInContainer isEqualToString: @"personal"])
error = [NSException exceptionWithHTTPStatus: 403
reason: @"the 'personal' folder cannot be deleted"];
else
error = [[self folderManager] deleteFolderAtPath: ocsPath];
return error;
}
- (NSArray *) fetchContentObjectNames

View File

@@ -0,0 +1,50 @@
/* 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;
@end
#endif /* SOGOPARENTFOLDERS_H */

View File

@@ -0,0 +1,240 @@
/* 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 <NGObjWeb/NSException+HTTP.h>
#import <GDLContentStore/GCSChannelManager.h>
#import <GDLContentStore/GCSFolderManager.h>
#import <GDLContentStore/NSURL+GCS.h>
#import <GDLAccess/EOAdaptorChannel.h>
#import "SOGoFolder.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);
}
- (void) _fetchPersonalFolders: (NSString *) sql
withChannel: (EOAdaptorChannel *) fc
{
NSArray *attrs;
NSDictionary *row;
SOGoFolder *folder;
BOOL hasPersonal;
NSString *key, *path;
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 folderWithName: [row objectForKey: @"c_path4"]
andDisplayName: [row objectForKey: @"c_foldername"]
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 folderWithName: @"personal"
andDisplayName: @"personal"
inContainer: self];
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, c_foldername 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
{
}
- (NSException *) newFolderWithName: (NSString *) name
{
SOGoFolder *newFolder;
NSException *error;
if (!subFolderClass)
subFolderClass = [[self class] subFolderClass];
newFolder = [subFolderClass folderWithName: name
andDisplayName: name
inContainer: self];
if ([newFolder isKindOfClass: [NSException class]])
error = (NSException *) newFolder;
else
{
[newFolder setOCSPath: [NSString stringWithFormat: @"%@/%@",
OCSPath, name]];
if ([newFolder create])
error = nil;
else
error = [NSException exceptionWithHTTPStatus: 400
reason: @"The new folder could not be created"];
}
return error;
}
- (void) initSubFolders
{
if (!subFolders)
{
subFolders = [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 (!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

View File

@@ -37,6 +37,8 @@
#import <SoObjects/SOGo/SOGoObject.h>
#import <SoObjects/SOGo/SOGoPermissions.h>
#import "WODirectAction+SOGo.h"
#import "UIxFolderActions.h"
@implementation UIxFolderActions
@@ -89,10 +91,9 @@
NSMutableDictionary *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!"];
}
@@ -119,12 +120,12 @@
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;
@@ -162,22 +163,14 @@
- (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];
[self _setupContext];
active = [NSNumber numberWithBool: makeActive];
if ([owner isEqualToString: login])
@@ -196,9 +189,8 @@
}
[ud synchronize];
[response setStatus: 204];
return response;
return [self responseWith204];
}
- (WOResponse *) activateFolderAction

View File

@@ -30,6 +30,8 @@
@interface WODirectAction (SOGoExtension)
- (WOResponse *) responseWithStatus: (unsigned int) status;
- (WOResponse *) responseWith204;
- (WOResponse *) redirectToLocation: (NSString *) newLocation;
@end

View File

@@ -28,15 +28,30 @@
@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

View File

@@ -52,8 +52,7 @@
WORequest *request;
folders = [self clientObject];
action = [NSString stringWithFormat: @"../%@/%@",
[folders defaultSourceName],
action = [NSString stringWithFormat: @"../personal/%@",
actionName];
request = [[self context] request];
@@ -82,7 +81,11 @@
name = [self queryParameterForKey: @"name"];
if ([name length] > 0)
response = [[self clientObject] newFolderWithName: name];
{
response = [[self clientObject] newFolderWithName: name];
if (!response)
response = [self responseWith204];
}
else
response = [NSException exceptionWithHTTPStatus: 400
reason: @"The name is missing"];
@@ -111,8 +114,7 @@
{
uid = [currentContact objectForKey: @"c_uid"];
if (uid && ![results objectForKey: uid])
[results setObject: currentContact
forKey: uid];
[results setObject: currentContact forKey: uid];
currentContact = [folderResults nextObject];
}
}
@@ -202,7 +204,7 @@
gcsFolders = [NSMutableArray new];
[gcsFolders autorelease];
contactSubfolders = [[contactFolders contactFolders] objectEnumerator];
contactSubfolders = [[contactFolders subFolders] objectEnumerator];
currentContactFolder = [contactSubfolders nextObject];
while (currentContactFolder)
{

View File

@@ -29,6 +29,7 @@
#import <SoObjects/SOGo/SOGoUser.h>
#import <SoObjects/Contacts/SOGoContactFolder.h>
#import <SoObjects/Contacts/SOGoContactFolders.h>
#import "UIxContactsListViewContainer.h"
@@ -115,7 +116,7 @@
folderContainer = [[self clientObject] container];
return [folderContainer contactFolders];
return [folderContainer subFolders];
}
- (NSString *) currentContactFolderId

View File

@@ -108,8 +108,7 @@
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]];

View File

@@ -94,10 +94,7 @@
response = [[self clientObject] trashInContext: context];
if (!response)
{
response = [context response];
[response setStatus: 204];
}
response = [self responseWith204];
return response;
}
@@ -113,10 +110,7 @@
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 */
@@ -125,6 +119,30 @@
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
{
@@ -158,10 +176,7 @@
if (error)
response = error;
else
{
response = [context response];
[response setStatus: 204];
}
response = [self responseWith204];
return response;
}
@@ -171,17 +186,15 @@
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?"];
}

View File

@@ -404,10 +404,7 @@ static NSArray *infoKeys = nil;
{
result = [[self clientObject] save];
if (!result)
{
result = [context response];
[result setStatus: 204];
}
result = [self responseWith204];
}
else
result = [self failedToSaveFormResponse];

View File

@@ -36,6 +36,8 @@
#import <SoObjects/Mailer/SOGoMailAccount.h>
#import <SoObjects/SOGo/NSObject+Utilities.h>
#import <UI/Common/WODirectAction+SOGo.h>
#import "UIxMailFolderActions.h"
@implementation UIxMailFolderActions
@@ -49,7 +51,6 @@
NSString *folderName;
co = [self clientObject];
response = [context response];
folderName = [[context request] formValueForKey: @"name"];
if ([folderName length] > 0)
@@ -58,15 +59,15 @@
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."];
}
@@ -100,7 +101,6 @@
NSURL *srcURL, *destURL;
co = [self clientObject];
response = [context response];
folderName = [[context request] formValueForKey: @"name"];
if ([folderName length] > 0)
@@ -112,15 +112,15 @@
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."];
}
@@ -154,7 +154,6 @@
NSURL *srcURL, *destURL;
co = [self clientObject];
response = [context response];
connection = [co imap4Connection];
srcURL = [co imap4URL];
destURL = [self _trashedURLOfFolder: srcURL
@@ -164,11 +163,11 @@
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;
}
@@ -180,18 +179,17 @@
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;
@@ -207,7 +205,6 @@
NSURL *currentURL;
co = [self clientObject];
response = [context response];
error = [co addFlagsToAllMessages: @"deleted"];
if (!error)
@@ -226,11 +223,11 @@
}
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;
}
@@ -242,7 +239,6 @@
WOResponse *response;
SOGoMailFolder *clientObject;
response = [context response];
mailInvitationParam
= [[context request] formValueForKey: @"mail-invitation"];
if ([mailInvitationParam boolValue])
@@ -257,7 +253,7 @@
}
else
{
[response setStatus: 500];
response = [self responseWithStatus: 500];
[response appendContentString: @"How did you end up here?"];
}
@@ -283,8 +279,7 @@
NGImap4Client *client;
NSString *responseString;
response = [context response];
[response setStatus: 200];
response = [self responseWithStatus: 200];
[response setHeader: @"text/plain; charset=UTF-8"
forKey: @"content-type"];

View File

@@ -221,10 +221,24 @@ static int attachmentFlagSize = 8096;
- (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];
}
@@ -407,36 +421,8 @@ static int attachmentFlagSize = 8096;
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;
@@ -462,8 +448,7 @@ static int attachmentFlagSize = 8096;
if ([criteria isEqualToString: @"subject"])
qualifier = [EOQualifier qualifierWithQualifierFormat:
@"(subject doesContain: %@)",
value];
@"(subject doesContain: %@)", value];
else if ([criteria isEqualToString: @"sender"])
qualifier = [EOQualifier qualifierWithQualifierFormat:
@"(sender doesContain: %@)", value];
@@ -510,39 +495,6 @@ static int attachmentFlagSize = 8096;
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?

View File

@@ -25,6 +25,8 @@
#import <Foundation/NSString.h>
#import <SoObjects/Mailer/SOGoMailObject.h>
#import <UI/Common/WODirectAction+SOGo.h>
#import "UIxMailSourceView.h"
@implementation UIxMailSourceView
@@ -36,8 +38,7 @@
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];

View File

@@ -142,37 +142,42 @@ static NSString *mailETag = nil;
- (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;
}

View File

@@ -115,16 +115,6 @@
protectedBy = "View";
pageName = "UIxMailListView";
};
markMessageUnread = {
protectedBy = "View";
pageName = "UIxMailListView";
actionName = "markMessageUnread";
};
markMessageRead = {
protectedBy = "View";
pageName = "UIxMailListView";
actionName = "markMessageRead";
};
getMail = {
protectedBy = "View";
pageName = "UIxMailListView";
@@ -235,6 +225,16 @@
actionClass = "UIxMailActions";
actionName = "forward";
};
markMessageUnread = {
protectedBy = "View";
actionClass = "UIxMailActions";
actionName = "markMessageUnread";
};
markMessageRead = {
protectedBy = "View";
actionClass = "UIxMailActions";
actionName = "markMessageRead";
};
};
};

View File

@@ -69,7 +69,7 @@
auth = [[WOApplication application]
authenticatorInContext: context];
response = [context response];
response = [self responseWith204];
cookieString = [NSString stringWithFormat: @"%@:%@",
[self queryParameterForKey: @"userName"],
[self queryParameterForKey: @"password"]];
@@ -78,7 +78,6 @@
authCookie = [WOCookie cookieWithName: [auth cookieNameInContext: context]
value: cookieValue];
[authCookie setPath: @"/"];
[response setStatus: 204];
[response addCookie: authCookie];
return response;

View File

@@ -68,25 +68,25 @@
/* 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;
@@ -95,6 +95,8 @@
- (WOResourceManager *) pageResourceManager;
- (NSString *) urlForResourceFilename: (NSString *) filename;
- (WOResponse *) responseWith204;
/* Debugging */
- (BOOL)isUIxDebugEnabled;

View File

@@ -400,7 +400,7 @@ static BOOL uixDebugEnabled = NO;
userTimeZone = [[context activeUser] timeZone];
[_date setTimeZone: userTimeZone];
return [_date descriptionWithCalendarFormat:@"%Y%m%d"];
return [_date descriptionWithCalendarFormat: @"%Y%m%d"];
}
- (BOOL) hideFrame
@@ -569,6 +569,16 @@ static BOOL uixDebugEnabled = NO;
return url;
}
- (WOResponse *) responseWith204
{
WOResponse *response;
response = [context response];
[response setStatus: 204];
return response;
}
/* debugging */
- (BOOL)isUIxDebugEnabled {

View File

@@ -39,6 +39,8 @@
#import <SoObjects/SOGo/NSObject+Utilities.h>
#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
#import <UI/Common/WODirectAction+SOGo.h>
#import "NSArray+Scheduler.h"
#import "UIxCalListingActions.h"
@@ -289,10 +291,9 @@
{
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;

View File

@@ -63,7 +63,6 @@
var:class="messageSubjectCellStyleClass"
var:id="msgDivID"
><var:string value="message.envelope.subject"
formatter="context.mailSubjectFormatter"
/></td
><td class="messageAddressColumn"

View File

@@ -149,7 +149,7 @@ function openMessageWindowsForSelection(action, firstOnly) {
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