02111-1307, USA.
*/
-#include <SOGoUI/UIxComponent.h>
-
/*
UIxMailListView
object.
*/
-@class EOQualifier;
-
-@interface UIxMailListView : UIxComponent
-{
- NSArray *sortedUIDs; /* we always need to retrieve all anyway! */
- NSArray *messages;
- unsigned firstMessageNumber;
- id message;
- EOQualifier *qualifier;
-}
-
-- (NSString *)defaultSortKey;
-- (NSString *)imap4SortKey;
-- (NSString *)imap4SortOrdering;
+#import <Foundation/NSCalendarDate.h>
+#import <Foundation/NSDictionary.h>
+#import <Foundation/NSValue.h>
+#import <NGObjWeb/WOResponse.h>
+#import <NGObjWeb/WORequest.h>
+#import <NGObjWeb/SoObject+SoDAV.h>
+#import <NGObjWeb/NSException+HTTP.h>
+#import <NGExtensions/NSNull+misc.h>
+#import <NGExtensions/NSString+misc.h>
-- (BOOL)isSortedDescending;
+#import <SoObjects/Mailer/SOGoMailFolder.h>
+#import <SoObjects/Mailer/SOGoMailObject.h>
+#import <SoObjects/SOGo/SOGoDateFormatter.h>
+#import <SoObjects/SOGo/SOGoUser.h>
-@end
+#import "UIxMailListView.h"
-#include "common.h"
-#include <SoObjects/Mailer/SOGoMailFolder.h>
-#include <SoObjects/Mailer/SOGoMailObject.h>
-#include <NGObjWeb/SoObject+SoDAV.h>
+#define messagesPerPage 50
+static int attachmentFlagSize = 8096;
@implementation UIxMailListView
-static int attachmentFlagSize = 8096;
-
-- (void)dealloc {
+- (void) dealloc
+{
[self->qualifier release];
[self->sortedUIDs release];
[self->messages release];
[self->message release];
+ [dateFormatter release];
+ [userTimeZone release];
[super dealloc];
}
-/* frame */
-
-- (BOOL)hideFrame {
- return [[[[self context] request] formValueForKey:@"noframe"] boolValue];
-}
-
/* notifications */
-- (void)sleep {
+- (void) sleep
+{
[self->qualifier release]; self->qualifier = nil;
[self->sortedUIDs release]; self->sortedUIDs = nil;
[self->messages release]; self->messages = nil;
/* accessors */
-- (void)setMessage:(id)_msg {
+- (void)setMessage:(id)_msg
+{
ASSIGN(self->message, _msg);
}
-- (id)message {
+
+- (id) message
+{
return self->message;
}
-- (void)setQualifier:(EOQualifier *)_msg {
+- (NSString *) messageDate
+{
+ NSCalendarDate *messageDate;
+
+ messageDate = [[message objectForKey: @"envelope"] date];
+ [messageDate setTimeZone: userTimeZone];
+
+ return [dateFormatter formattedDateAndTime: messageDate];
+}
+
+- (void) setQualifier: (EOQualifier *) _msg
+{
ASSIGN(self->qualifier, _msg);
}
-- (EOQualifier *)qualifier {
+
+- (EOQualifier *) qualifier
+{
return self->qualifier;
}
-- (BOOL)showToAddress {
+- (BOOL) showToAddress
+{
NSString *ftype;
ftype = [[self clientObject] valueForKey:@"outlookFolderClass"];
/* title */
-- (NSString *)objectTitle {
+- (NSString *) objectTitle
+{
return [[self clientObject] nameInContainer];
}
-- (NSString *)panelTitle {
+
+- (NSString *) panelTitle
+{
NSString *s;
s = [self labelForKey:@"View Mail Folder"];
/* derived accessors */
-- (BOOL)isMessageDeleted {
+- (BOOL) isMessageDeleted
+{
NSArray *flags;
flags = [[self message] valueForKey:@"flags"];
return [flags containsObject:@"deleted"];
}
-- (BOOL)isMessageRead {
+- (BOOL) isMessageRead
+{
NSArray *flags;
flags = [[self message] valueForKey:@"flags"];
return [flags containsObject:@"seen"];
}
-- (NSString *)messageUidString {
+- (NSString *) messageUidString
+{
return [[[self message] valueForKey:@"uid"] stringValue];
}
-- (NSString *)messageSubjectStyleClass {
- return [self isMessageRead]
- ? @"mailer_readmailsubject"
- : @"mailer_unreadmailsubject";
-}
-- (NSString *)messageCellStyleClass {
+- (NSString *) messageRowStyleClass
+{
return [self isMessageDeleted]
? @"mailer_listcell_deleted"
: @"mailer_listcell_regular";
}
-- (BOOL)hasMessageAttachment {
+- (NSString *) messageSubjectCellStyleClass
+{
+ return ([self isMessageRead]
+ ? @"mailer_readmailsubject"
+ : @"mailer_unreadmailsubject");
+}
+
+- (BOOL) hasMessageAttachment
+{
/* we detect attachments by size ... */
unsigned size;
/* fetching messages */
-- (NSArray *)fetchKeys {
+- (NSArray *) fetchKeys
+{
/* Note: see SOGoMailManager.m for allowed IMAP4 keys */
static NSArray *keys = nil;
if (keys == nil) {
return keys;
}
-- (NSString *)defaultSortKey {
+- (NSString *) defaultSortKey
+{
return @"DATE";
}
-- (NSString *)imap4SortKey {
+
+- (NSString *) imap4SortKey
+{
NSString *sort;
sort = [[[self context] request] formValueForKey:@"sort"];
-
+
if ([sort length] == 0)
sort = [self defaultSortKey];
+
return [sort uppercaseString];
}
-- (BOOL)isSortedDescending {
+- (BOOL) isSortedDescending
+{
NSString *desc;
-
+
desc = [[[self context] request] formValueForKey:@"desc"];
- if(!desc)
- return NO;
- return [desc boolValue] ? YES : NO;
+
+ return ((desc)
+ ? [desc boolValue]
+ : YES);
}
-- (NSString *)imap4SortOrdering {
+- (NSString *) imap4SortOrdering
+{
NSString *sort;
-
+
sort = [self imap4SortKey];
- if(![self isSortedDescending])
- return sort;
- return [@"REVERSE " stringByAppendingString:sort];
+
+ if ([self isSortedDescending])
+ sort = [@"REVERSE " stringByAppendingString: sort];
+
+ return sort;
}
-- (NSRange)fetchRange {
+- (NSRange) fetchRange
+{
if (self->firstMessageNumber == 0)
- return NSMakeRange(0, 50);
- return NSMakeRange(self->firstMessageNumber - 1, 50);
+ return NSMakeRange(0, messagesPerPage);
+ return NSMakeRange(self->firstMessageNumber - 1, messagesPerPage);
}
-- (NSArray *)sortedUIDs {
- if (self->sortedUIDs != nil)
- return self->sortedUIDs;
-
- self->sortedUIDs
- = [[[self clientObject] fetchUIDsMatchingQualifier:[self qualifier]
- sortOrdering:[self imap4SortOrdering]] retain];
+- (NSArray *) sortedUIDs
+{
+ if (!sortedUIDs)
+ {
+ sortedUIDs
+ = [[self clientObject] fetchUIDsMatchingQualifier: [self qualifier]
+ sortOrdering: [self imap4SortOrdering]];
+ [sortedUIDs retain];
+ }
+
return self->sortedUIDs;
}
-- (unsigned int)totalMessageCount {
+
+- (unsigned int) totalMessageCount
+{
return [self->sortedUIDs count];
}
-- (BOOL)showsAllMessages {
+
+- (BOOL) showsAllMessages
+{
return ([[self sortedUIDs] count] <= [self fetchRange].length) ? YES : NO;
}
-- (NSRange)fetchBlock {
+- (NSRange) fetchBlock
+{
NSRange r;
unsigned len;
NSArray *uids;
r.length = len - r.location;
return r;
}
-- (unsigned int)firstMessageNumber {
+
+- (unsigned int) firstMessageNumber
+{
return [self fetchBlock].location + 1;
}
-- (unsigned int)lastMessageNumber {
+
+- (unsigned int) lastMessageNumber
+{
NSRange r;
r = [self fetchBlock];
return r.location + r.length;
}
-- (BOOL)hasPrevious {
+
+- (BOOL) hasPrevious
+{
return [self fetchBlock].location == 0 ? NO : YES;
}
-- (BOOL)hasNext {
+
+- (BOOL) hasNext
+{
NSRange r = [self fetchBlock];
return r.location + r.length >= [[self sortedUIDs] count] ? NO : YES;
}
-- (unsigned int)nextFirstMessageNumber {
+- (unsigned int) nextFirstMessageNumber
+{
return [self firstMessageNumber] + [self fetchRange].length;
}
-- (unsigned int)prevFirstMessageNumber {
+
+- (unsigned int) prevFirstMessageNumber
+{
NSRange r;
unsigned idx;
return 1;
}
-- (NSArray *)messages {
+- (NSArray *) messages
+{
NSArray *uids;
NSArray *msgs;
NSRange r;
unsigned len;
+ SOGoUser *user;
if (self->messages != nil)
return self->messages;
-
+
+ user = [context activeUser];
+ if (!dateFormatter)
+ dateFormatter = [user dateFormatterInContext: context];
+ if (!userTimeZone)
+ ASSIGN (userTimeZone, [user timeZone]);
+
r = [self fetchBlock];
uids = [self sortedUIDs];
if ((len = [uids count]) > r.length)
/* URL processing */
-- (NSString *)messageViewTarget {
- return [@"SOGo_msg_" stringByAppendingString:[self messageUidString]];
+- (NSString *) messageViewTarget
+{
+ return [NSString stringWithFormat: @"SOGo_msg_%@",
+ [self messageUidString]];
}
-- (NSString *)messageViewURL {
+
+- (NSString *) messageViewURL
+{
// TODO: noframe only when view-target is empty
// TODO: markread only if the message is unread
NSString *s;
if (![self isMessageRead]) s = [s stringByAppendingString:@"&markread=1"];
return s;
}
-- (NSString *)markReadURL {
+- (NSString *) markReadURL
+{
return [@"markMessageRead?uid=" stringByAppendingString:
[self messageUidString]];
}
-- (NSString *)markUnreadURL {
+- (NSString *) markUnreadURL
+{
return [@"markMessageUnread?uid=" stringByAppendingString:
[self messageUidString]];
}
/* JavaScript */
-- (NSString *)msgRowID {
+- (NSString *)msgRowID
+{
return [@"row_" stringByAppendingString:[self messageUidString]];
}
-- (NSString *)msgDivID {
+
+- (NSString *)msgDivID
+{
return [@"div_" stringByAppendingString:[self messageUidString]];
}
-- (NSString *)msgIconReadDivID {
+- (NSString *)msgIconReadImgID
+{
return [@"readdiv_" stringByAppendingString:[self messageUidString]];
}
-- (NSString *)msgIconUnreadDivID {
- return [@"unreaddiv_" stringByAppendingString:[self messageUidString]];
-}
-- (NSString *)msgIconReadVisibility {
- return [self isMessageRead] ? nil : @"display: none;";
-}
-- (NSString *)msgIconUnreadVisibility {
- return [self isMessageRead] ? @"display: none;" : nil;
-}
-- (NSString *)clickedMsgJS {
- /* return 'false' aborts processing */
- return [NSString stringWithFormat:@"clickedUid(this, '%@'); return false",
- [self messageUidString]];
-}
-
-// the following are unused?
-- (NSString *)dblClickedMsgJS {
- return [NSString stringWithFormat:@"doubleClickedUid(this, '%@')",
- [self messageUidString]];
-}
-
-// the following are unused?
-- (NSString *)highlightRowJS {
- return [NSString stringWithFormat:@"highlightUid(this, '%@')",
- [self messageUidString]];
-}
-- (NSString *)lowlightRowJS {
- return [NSString stringWithFormat:@"lowlightUid(this, '%@')",
- [self messageUidString]];
-}
-
-- (NSString *)markUnreadJS {
- return [NSString stringWithFormat:
- @"mailListMarkMessage(this, 'markMessageUnread', "
- @"'%@', false)",
- [self messageUidString]];
-}
-- (NSString *)markReadJS {
- return [NSString stringWithFormat:
- @"mailListMarkMessage(this, 'markMessageRead', "
- @"'%@', true)",
- [self messageUidString]];
+- (NSString *)msgIconUnreadImgID
+{
+ return [@"unreaddiv_" stringByAppendingString:[self messageUidString]];
}
/* error redirects */
-- (id)redirectToViewWithError:(id)_error {
+- (id) redirectToViewWithError: (id) _error
+{
// TODO: DUP in UIxMailAccountView
// TODO: improve, localize
// TODO: there is a bug in the treeview which preserves the current URL for
/* active message */
-- (SOGoMailObject *)lookupActiveMessage {
+- (SOGoMailObject *) lookupActiveMessage
+{
NSString *uid;
if ((uid = [[[self context] request] formValueForKey:@"uid"]) == nil)
/* actions */
-- (id)defaultAction {
- self->firstMessageNumber =
- [[[[self context] request] formValueForKey:@"idx"] intValue];
- return self;
-}
-
-- (BOOL)isJavaScriptRequest {
+- (BOOL) isJavaScriptRequest
+{
return [[[[self context] request] formValueForKey:@"jsonly"] boolValue];
}
-- (id)javaScriptOK {
+
+- (id) javaScriptOK
+{
WOResponse *r;
r = [[self context] response];
return r;
}
-- (id)markMessageUnreadAction {
+- (int) firstMessageOfPageFor: (int) messageNbr
+{
+ NSArray *messageNbrs;
+ int nbrInArray;
+ int firstMessage;
+
+ messageNbrs = [self sortedUIDs];
+ nbrInArray
+ = [messageNbrs indexOfObject: [NSNumber numberWithInt: messageNbr]];
+ if (nbrInArray > -1)
+ firstMessage = ((int) (nbrInArray / messagesPerPage)
+ * messagesPerPage) + 1;
+ else
+ firstMessage = 1;
+
+ return firstMessage;
+}
+
+- (id) defaultAction
+{
+ WORequest *request;
+ NSString *specificMessage;
+
+ request = [[self context] request];
+
+ [[self clientObject] flushMailCaches];
+
+ specificMessage = [request formValueForKey: @"pageforuid"];
+ self->firstMessageNumber
+ = ((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)
return [self redirectToLocation:@"view"];
}
-- (id)markMessageReadAction {
+
+- (id) markMessageReadAction
+{
NSException *error;
if ((error = [[self lookupActiveMessage] addFlags:@"seen"]) != nil)
return [self redirectToLocation:@"view"];
}
-- (id)getMailAction {
+- (id) getMailAction
+{
// TODO: we might want to flush the caches?
id client;
-
+
if ((client = [self clientObject]) == nil) {
return [NSException exceptionWithHTTPStatus:404 /* Not Found */
reason:@"did not find mail folder"];
}
-
- if (![client respondsToSelector:@selector(flushMailCaches)]) {
- return [NSException exceptionWithHTTPStatus:500 /* Server Error */
- reason:
- @"invalid client object (does not support flush)"];
- }
-
+
+ if (![client respondsToSelector:@selector(flushMailCaches) ])
+ {
+ return [NSException exceptionWithHTTPStatus: 500 /* Server Error */
+ reason:
+ @"invalid client object (does not support flush)"];
+ }
+
[client flushMailCaches];
+
return [self redirectToLocation:@"view"];
}
-- (id)expungeAction {
+- (id) expungeAction
+{
// TODO: we might want to flush the caches?
NSException *error;
id client;
return [self redirectToLocation:@"view"];
}
-- (id)emptyTrashAction {
- // TODO: we might want to flush the caches?
- NSException *error;
- id client;
-
- if ((client = [self clientObject]) == nil) {
- error = [NSException exceptionWithHTTPStatus:404 /* Not Found */
- reason:@"did not find mail folder"];
- return [self redirectToViewWithError:error];
- }
-
- if (![client isKindOfClass:NSClassFromString(@"SOGoTrashFolder")]) {
- /* would be better to move the method to an own class, but well .. */
- error = [NSException exceptionWithHTTPStatus:400 /* Bad Request */
- reason:@"method cannot be invoked on "
- @"the specified object"];
- return [self redirectToViewWithError:error];
- }
-
- /* mark all as deleted */
-
- [self logWithFormat:@"TODO: must mark all as deleted for empty-trash"];
-
- error = [[self clientObject] addFlagsToAllMessages:@"deleted"];
- if (error != nil)
- // TODO: improve error
- return [self redirectToViewWithError:error];
-
- /* expunge */
-
- if ((error = [[self clientObject] expunge]) != nil)
- // TODO: improve error
- return [self redirectToViewWithError:error];
-
- if ([client respondsToSelector:@selector(flushMailCaches)])
- [client flushMailCaches];
- return [self redirectToLocation:@"view"];
-}
-
-/* folder operations */
-
-- (id)createFolderAction {
- NSException *error;
- NSString *folderName;
- id client;
-
- folderName = [[[self context] request] formValueForKey:@"name"];
- if ([folderName length] == 0) {
- error = [NSException exceptionWithHTTPStatus:400 /* Bad Request */
- reason:@"missing 'name' query parameter!"];
- return [self redirectToViewWithError:error];
- }
-
- if ((client = [self clientObject]) == nil) {
- error = [NSException exceptionWithHTTPStatus:404 /* Not Found */
- reason:@"did not find mail folder"];
- return [self redirectToViewWithError:error];
- }
-
- if ((error = [[self clientObject] davCreateCollection:folderName
- inContext:[self context]]) != nil) {
- return [self redirectToViewWithError:error];
- }
-
- return [self redirectToLocation:[folderName stringByAppendingString:@"/"]];
-}
-
-- (id)deleteFolderAction {
- NSException *error;
- NSString *url;
- id client;
-
- if ((client = [self clientObject]) == nil) {
- error = [NSException exceptionWithHTTPStatus:404 /* Not Found */
- reason:@"did not find mail folder"];
- return [self redirectToViewWithError:error];
- }
-
- /* jump to parent folder afterwards */
- url = [[client container] baseURLInContext:[self context]];
- if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"];
-
- if ((error = [[self clientObject] delete]) != nil)
- return [self redirectToViewWithError:error];
-
- return [self redirectToLocation:url];
-}
+@end
-@end /* UIxMailListView */
+/* UIxMailListView */