2010-05-27 16:41:59 +02:00
|
|
|
/*
|
2015-05-05 15:49:40 +02:00
|
|
|
Copyright (C) 2006-2015 Inverse inc.
|
2010-05-27 16:41:59 +02:00
|
|
|
|
|
|
|
This file is part of SOGo
|
|
|
|
|
|
|
|
SOGo is free software; you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU Lesser General Public License as published by the
|
|
|
|
Free Software Foundation; either version 2, or (at your option) any
|
|
|
|
later version.
|
|
|
|
|
|
|
|
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
|
|
License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
2014-11-21 21:44:19 +01:00
|
|
|
License along with SOGo; see the file COPYING. If not, write to the
|
2010-05-27 16:41:59 +02:00
|
|
|
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
UIxMailListActions
|
|
|
|
|
|
|
|
This component represent a list of mails and is attached to an SOGoMailFolder
|
|
|
|
object.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#import <Foundation/NSCalendarDate.h>
|
|
|
|
#import <Foundation/NSCharacterSet.h>
|
|
|
|
#import <Foundation/NSTimeZone.h>
|
2014-11-27 14:58:33 +01:00
|
|
|
#import <Foundation/NSUserDefaults.h> /* for locale string constants */
|
2010-05-27 16:41:59 +02:00
|
|
|
#import <Foundation/NSValue.h>
|
|
|
|
|
2014-11-27 14:58:33 +01:00
|
|
|
#import <NGObjWeb/WOApplication.h>
|
2010-05-27 19:09:02 +02:00
|
|
|
#import <NGObjWeb/WOContext+SoObjects.h>
|
2010-05-27 16:41:59 +02:00
|
|
|
#import <NGObjWeb/WORequest.h>
|
|
|
|
#import <NGObjWeb/SoObject+SoDAV.h>
|
|
|
|
#import <NGObjWeb/NSException+HTTP.h>
|
|
|
|
#import <NGExtensions/NSNull+misc.h>
|
|
|
|
#import <NGExtensions/NSString+misc.h>
|
|
|
|
#import <NGExtensions/NSObject+Logs.h>
|
|
|
|
#import <NGImap4/NGImap4Envelope.h>
|
|
|
|
|
|
|
|
#import <EOControl/EOQualifier.h>
|
|
|
|
|
|
|
|
#import <Mailer/NSString+Mail.h>
|
|
|
|
#import <Mailer/SOGoDraftsFolder.h>
|
2011-07-07 15:58:50 +02:00
|
|
|
#import <Mailer/SOGoMailAccount.h>
|
2010-05-27 16:41:59 +02:00
|
|
|
#import <Mailer/SOGoSentFolder.h>
|
|
|
|
#import <SOGo/NSArray+Utilities.h>
|
|
|
|
#import <SOGo/NSDictionary+Utilities.h>
|
2015-08-19 16:39:10 +02:00
|
|
|
#import <SOGo/NSObject+Utilities.h>
|
2014-08-11 15:25:09 +02:00
|
|
|
#import <SOGo/NSString+Utilities.h>
|
2010-05-27 16:41:59 +02:00
|
|
|
#import <SOGo/SOGoDateFormatter.h>
|
|
|
|
#import <SOGo/SOGoUser.h>
|
|
|
|
#import <SOGo/SOGoUserDefaults.h>
|
2012-10-22 16:09:13 +02:00
|
|
|
#import <SOGo/SOGoUserSettings.h>
|
2014-11-27 14:58:33 +01:00
|
|
|
#import <SOGo/WOResourceManager+SOGo.h>
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2010-05-27 19:09:02 +02:00
|
|
|
#import <UI/Common/WODirectAction+SOGo.h>
|
2013-12-18 14:38:03 +01:00
|
|
|
#import <UI/MailPartViewers/UIxMailSizeFormatter.h>
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2010-05-27 19:09:02 +02:00
|
|
|
#import "WOContext+UIxMailer.h"
|
2010-05-27 23:56:04 +02:00
|
|
|
#import "UIxMailFormatter.h"
|
|
|
|
|
2010-05-27 16:41:59 +02:00
|
|
|
#import "UIxMailListActions.h"
|
|
|
|
|
2010-06-25 21:58:30 +02:00
|
|
|
// The maximum number of headers to prefetch when querying the UIDs list
|
|
|
|
#define headersPrefetchMaxSize 100
|
|
|
|
|
2010-05-27 16:41:59 +02:00
|
|
|
@implementation UIxMailListActions
|
|
|
|
|
2010-05-27 19:09:02 +02:00
|
|
|
- (id) initWithRequest: (WORequest *) newRequest
|
2010-05-27 16:41:59 +02:00
|
|
|
{
|
|
|
|
SOGoUser *user;
|
|
|
|
|
2010-05-27 19:09:02 +02:00
|
|
|
if ((self = [super initWithRequest: newRequest]))
|
2010-05-27 16:41:59 +02:00
|
|
|
{
|
2010-05-27 19:09:02 +02:00
|
|
|
user = [[self context] activeUser];
|
2014-11-25 22:35:01 +01:00
|
|
|
ASSIGN (now, [NSCalendarDate calendarDate]);
|
2010-05-27 16:41:59 +02:00
|
|
|
ASSIGN (dateFormatter, [user dateFormatterInContext: context]);
|
|
|
|
ASSIGN (userTimeZone, [[user userDefaults] timeZone]);
|
2014-11-25 22:35:01 +01:00
|
|
|
[now setTimeZone: userTimeZone];
|
2011-06-01 23:10:25 +02:00
|
|
|
sortByThread = [[user userDefaults] mailSortByThreads];
|
2010-05-27 16:41:59 +02:00
|
|
|
folderType = 0;
|
|
|
|
specificMessageNumber = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
[sortedUIDs release];
|
|
|
|
[messages release];
|
|
|
|
[message release];
|
|
|
|
[dateFormatter release];
|
|
|
|
[userTimeZone release];
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* accessors */
|
|
|
|
|
|
|
|
- (void) setMessage: (id) _msg
|
|
|
|
{
|
|
|
|
ASSIGN (message, _msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) message
|
|
|
|
{
|
|
|
|
return message;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) messageDate
|
|
|
|
{
|
|
|
|
NSCalendarDate *messageDate;
|
|
|
|
|
|
|
|
messageDate = [[message valueForKey: @"envelope"] date];
|
|
|
|
[messageDate setTimeZone: userTimeZone];
|
|
|
|
|
2014-11-25 22:35:01 +01:00
|
|
|
if ([now dayOfCommonEra] == [messageDate dayOfCommonEra])
|
|
|
|
{
|
|
|
|
// Same day
|
|
|
|
return [dateFormatter formattedTime: messageDate];
|
|
|
|
}
|
|
|
|
else if ([now dayOfCommonEra] - [messageDate dayOfCommonEra] == 1)
|
|
|
|
{
|
2014-11-27 14:58:33 +01:00
|
|
|
// Yesterday
|
2015-08-19 16:39:10 +02:00
|
|
|
return [self labelForKey: @"Yesterday" inContext: context];
|
2014-11-25 22:35:01 +01:00
|
|
|
}
|
2014-11-27 14:58:33 +01:00
|
|
|
else if ([now dayOfCommonEra] - [messageDate dayOfCommonEra] < 7)
|
|
|
|
{
|
|
|
|
// Same week
|
|
|
|
WOResourceManager *resMgr = [[WOApplication application] resourceManager];
|
|
|
|
NSString *language = [[[context activeUser] userDefaults] language];
|
|
|
|
NSDictionary *locale = [resMgr localeForLanguageNamed: language];
|
|
|
|
return [[locale objectForKey: NSWeekDayNameArray] objectAtIndex: [messageDate dayOfWeek]];
|
|
|
|
}
|
2014-11-25 22:35:01 +01:00
|
|
|
else
|
|
|
|
{
|
2014-11-27 14:58:33 +01:00
|
|
|
return [dateFormatter shortFormattedDate: messageDate];
|
2014-11-25 22:35:01 +01:00
|
|
|
}
|
2010-05-27 16:41:59 +02:00
|
|
|
}
|
|
|
|
|
2013-12-18 14:38:03 +01:00
|
|
|
- (UIxMailSizeFormatter *) sizeFormatter
|
2010-05-27 16:41:59 +02:00
|
|
|
{
|
2013-12-18 14:38:03 +01:00
|
|
|
return [UIxMailSizeFormatter sharedMailSizeFormatter];
|
2010-05-27 16:41:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Priorities are defined like this:
|
|
|
|
//
|
|
|
|
// X-Priority: 1 (Highest)
|
|
|
|
// X-Priority: 2 (High)
|
|
|
|
// X-Priority: 3 (Normal)
|
|
|
|
// X-Priority: 4 (Low)
|
|
|
|
// X-Priority: 5 (Lowest)
|
|
|
|
//
|
|
|
|
// Sometimes, the MUAs don't send over the string in () so we ignore it.
|
|
|
|
//
|
2015-09-24 20:36:06 +02:00
|
|
|
- (NSDictionary *) messagePriority
|
2010-05-27 16:41:59 +02:00
|
|
|
{
|
2015-09-24 20:36:06 +02:00
|
|
|
NSUInteger priority;
|
|
|
|
NSString *description;
|
2010-05-27 16:41:59 +02:00
|
|
|
NSData *data;
|
|
|
|
|
|
|
|
data = [message objectForKey: @"header"];
|
2015-09-24 20:36:06 +02:00
|
|
|
priority = 3;
|
|
|
|
description = [self labelForKey: @"normal" inContext: context];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
|
|
|
if (data)
|
|
|
|
{
|
|
|
|
NSString *s;
|
|
|
|
|
|
|
|
s = [[NSString alloc] initWithData: data
|
|
|
|
encoding: NSASCIIStringEncoding];
|
|
|
|
|
|
|
|
if (s)
|
|
|
|
{
|
|
|
|
NSRange r;
|
|
|
|
|
|
|
|
[s autorelease];
|
|
|
|
r = [s rangeOfString: @":"];
|
|
|
|
|
|
|
|
if (r.length)
|
|
|
|
{
|
|
|
|
s = [[s substringFromIndex: r.location+1]
|
|
|
|
stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
|
|
|
|
2015-09-24 20:36:06 +02:00
|
|
|
if ([s hasPrefix: @"1"])
|
|
|
|
{
|
|
|
|
priority = 1;
|
|
|
|
description = [self labelForKey: @"highest" inContext: context];
|
|
|
|
}
|
|
|
|
else if ([s hasPrefix: @"2"])
|
|
|
|
{
|
|
|
|
priority = 2;
|
|
|
|
description = [self labelForKey: @"high" inContext: context];
|
|
|
|
}
|
|
|
|
else if ([s hasPrefix: @"4"])
|
|
|
|
{
|
|
|
|
priority = 4;
|
|
|
|
description = [self labelForKey: @"low" inContext: context];
|
|
|
|
}
|
|
|
|
else if ([s hasPrefix: @"5"])
|
|
|
|
{
|
|
|
|
priority = 5;
|
|
|
|
description = [self labelForKey: @"lowest" inContext: context];
|
|
|
|
}
|
2010-05-27 16:41:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-24 20:36:06 +02:00
|
|
|
return [NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
[NSNumber numberWithInt: priority], @"level",
|
|
|
|
description, @"name",
|
|
|
|
nil];
|
2010-05-27 16:41:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) messageSubject
|
|
|
|
{
|
|
|
|
id baseSubject;
|
|
|
|
NSString *subject;
|
|
|
|
|
|
|
|
baseSubject = [[message valueForKey: @"envelope"] subject];
|
|
|
|
subject = [baseSubject decodedHeader];
|
|
|
|
if (![subject length])
|
2012-05-29 16:20:06 +02:00
|
|
|
subject = @"";
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2014-11-21 21:44:19 +01:00
|
|
|
return subject;
|
2010-05-27 16:41:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) showToAddress
|
|
|
|
{
|
|
|
|
SOGoMailFolder *co;
|
|
|
|
|
|
|
|
if (!folderType)
|
|
|
|
{
|
|
|
|
co = [self clientObject];
|
|
|
|
if ([co isKindOfClass: [SOGoSentFolder class]]
|
|
|
|
|| [co isKindOfClass: [SOGoDraftsFolder class]])
|
|
|
|
folderType = 1;
|
|
|
|
else
|
|
|
|
folderType = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (folderType == 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* title */
|
|
|
|
|
|
|
|
- (NSString *) objectTitle
|
|
|
|
{
|
|
|
|
return [[self clientObject] nameInContainer];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) panelTitle
|
|
|
|
{
|
|
|
|
NSString *s;
|
|
|
|
|
2015-08-19 16:39:10 +02:00
|
|
|
s = [self labelForKey:@"View Mail Folder" inContext: context];
|
2010-05-27 16:41:59 +02:00
|
|
|
s = [s stringByAppendingString:@": "];
|
|
|
|
s = [s stringByAppendingString:[self objectTitle]];
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* derived accessors */
|
|
|
|
|
|
|
|
- (BOOL) isMessageDeleted
|
|
|
|
{
|
|
|
|
NSArray *flags;
|
|
|
|
|
2015-05-04 19:56:29 +02:00
|
|
|
flags = [[self message] valueForKey: @"flags"];
|
|
|
|
return [flags containsObject: @"deleted"];
|
2010-05-27 16:41:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) isMessageRead
|
|
|
|
{
|
|
|
|
NSArray *flags;
|
|
|
|
|
2015-05-04 19:56:29 +02:00
|
|
|
flags = [[self message] valueForKey: @"flags"];
|
|
|
|
return [flags containsObject: @"seen"];
|
2010-05-27 16:41:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) isMessageFlagged
|
|
|
|
{
|
|
|
|
NSArray *flags;
|
2015-05-05 15:49:40 +02:00
|
|
|
|
2015-05-04 19:56:29 +02:00
|
|
|
flags = [[self message] valueForKey: @"flags"];
|
|
|
|
return [flags containsObject: @"flagged"];
|
2010-05-27 16:41:59 +02:00
|
|
|
}
|
|
|
|
|
2015-05-05 15:49:40 +02:00
|
|
|
- (BOOL) isMessageAnswered
|
|
|
|
{
|
|
|
|
NSArray *flags;
|
|
|
|
|
|
|
|
flags = [[self message] valueForKey: @"flags"];
|
|
|
|
return [flags containsObject: @"answered"];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) isMessageForwarded
|
|
|
|
{
|
|
|
|
NSArray *flags;
|
|
|
|
|
|
|
|
flags = [[self message] valueForKey: @"flags"];
|
|
|
|
return [flags containsObject: @"$forwarded"];
|
|
|
|
}
|
|
|
|
|
2010-05-27 16:41:59 +02:00
|
|
|
- (NSString *) messageUidString
|
|
|
|
{
|
|
|
|
return [[[self message] valueForKey:@"uid"] stringValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) hasMessageAttachment
|
|
|
|
{
|
|
|
|
NSArray *parts;
|
|
|
|
NSEnumerator *dispositions;
|
|
|
|
NSDictionary *currentDisp;
|
|
|
|
BOOL hasAttachment;
|
|
|
|
|
|
|
|
hasAttachment = NO;
|
|
|
|
|
2012-10-06 18:19:30 +02:00
|
|
|
parts = [[message objectForKey: @"bodystructure"] objectForKey: @"parts"];
|
2010-05-27 16:41:59 +02:00
|
|
|
if ([parts count] > 1)
|
|
|
|
{
|
|
|
|
dispositions = [[parts objectsForKey: @"disposition"
|
|
|
|
notFoundMarker: nil] objectEnumerator];
|
|
|
|
while (!hasAttachment
|
|
|
|
&& (currentDisp = [dispositions nextObject]))
|
|
|
|
hasAttachment = ([[currentDisp objectForKey: @"type"] length]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return hasAttachment;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fetching messages */
|
|
|
|
|
|
|
|
- (NSArray *) fetchKeys
|
|
|
|
{
|
|
|
|
/* Note: see SOGoMailManager.m for allowed IMAP4 keys */
|
|
|
|
static NSArray *keys = nil;
|
|
|
|
|
|
|
|
if (!keys)
|
|
|
|
keys = [[NSArray alloc] initWithObjects: @"UID",
|
|
|
|
@"FLAGS", @"ENVELOPE", @"RFC822.SIZE",
|
|
|
|
@"BODYSTRUCTURE", @"BODY.PEEK[HEADER.FIELDS (X-PRIORITY)]", nil];
|
|
|
|
return keys;
|
|
|
|
}
|
|
|
|
|
2010-05-28 21:18:52 +02:00
|
|
|
- (NSString *) defaultSortKey
|
2010-05-27 16:41:59 +02:00
|
|
|
{
|
|
|
|
return @"ARRIVAL";
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) imap4SortOrdering
|
|
|
|
{
|
2014-08-13 23:41:58 +02:00
|
|
|
WORequest *request;
|
|
|
|
NSString *sort, *module;
|
2010-05-28 21:18:52 +02:00
|
|
|
NSMutableDictionary *moduleSettings;
|
2014-08-06 20:49:36 +02:00
|
|
|
NSDictionary *urlParams, *sortingAttributes;
|
2010-05-28 21:18:52 +02:00
|
|
|
SOGoUser *activeUser;
|
|
|
|
SOGoUserSettings *us;
|
2014-08-13 23:41:58 +02:00
|
|
|
BOOL asc;
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2014-08-06 20:49:36 +02:00
|
|
|
request = [context request];
|
|
|
|
urlParams = [[request contentAsString] objectFromJSONString];
|
|
|
|
sortingAttributes = [urlParams objectForKey:@"sortingAttributes"];
|
2014-08-13 23:41:58 +02:00
|
|
|
sort = [[sortingAttributes objectForKey:@"sort"] uppercaseString];
|
2014-08-06 20:49:36 +02:00
|
|
|
asc = [[sortingAttributes objectForKey:@"asc"] boolValue];
|
2010-05-28 21:18:52 +02:00
|
|
|
|
2010-06-25 21:58:30 +02:00
|
|
|
activeUser = [context activeUser];
|
2011-03-22 01:30:26 +01:00
|
|
|
module = @"Mail";
|
2010-06-25 21:58:30 +02:00
|
|
|
us = [activeUser userSettings];
|
|
|
|
moduleSettings = [us objectForKey: module];
|
|
|
|
|
2011-03-22 01:30:26 +01:00
|
|
|
if ([sort length])
|
2010-06-25 21:58:30 +02:00
|
|
|
{
|
2011-03-22 01:30:26 +01:00
|
|
|
if ([sort isEqualToString: [self defaultSortKey]] && !asc)
|
|
|
|
{
|
|
|
|
if (moduleSettings)
|
|
|
|
{
|
|
|
|
[moduleSettings removeObjectForKey: @"SortingState"];
|
|
|
|
[us synchronize];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Save the sorting state in the user settings
|
|
|
|
if (!moduleSettings)
|
|
|
|
{
|
|
|
|
moduleSettings = [NSMutableDictionary dictionary];
|
|
|
|
[us setObject: moduleSettings forKey: module];
|
|
|
|
}
|
|
|
|
[moduleSettings setObject: [NSArray arrayWithObjects: [sort lowercaseString], [NSString stringWithFormat: @"%d", (asc?1:0)], nil]
|
|
|
|
forKey: @"SortingState"];
|
|
|
|
[us synchronize];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (moduleSettings)
|
|
|
|
{
|
|
|
|
NSArray *sortState = [moduleSettings objectForKey: @"SortingState"];
|
2011-03-23 22:59:22 +01:00
|
|
|
if ([sortState count])
|
|
|
|
{
|
|
|
|
sort = [[sortState objectAtIndex: 0] uppercaseString];
|
|
|
|
asc = [[sortState objectAtIndex: 1] boolValue];
|
|
|
|
}
|
2011-03-22 01:30:26 +01:00
|
|
|
}
|
2011-03-23 22:59:22 +01:00
|
|
|
if (![sort length])
|
2011-03-22 01:30:26 +01:00
|
|
|
sort = [self defaultSortKey];
|
|
|
|
|
2010-05-28 21:18:52 +02:00
|
|
|
// Construct and return the final IMAP ordering constraint
|
|
|
|
if (!asc)
|
2010-05-27 16:41:59 +02:00
|
|
|
sort = [@"REVERSE " stringByAppendingString: sort];
|
|
|
|
|
|
|
|
return sort;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (EOQualifier *) searchQualifier
|
|
|
|
{
|
2014-08-06 20:49:36 +02:00
|
|
|
EOQualifier *qualifier, *searchQualifier;
|
|
|
|
WORequest *request;
|
2015-03-18 19:03:55 +01:00
|
|
|
NSDictionary *sortingAttributes, *content, *filter;
|
2014-08-11 15:25:09 +02:00
|
|
|
NSArray *filters;
|
2015-03-18 19:03:55 +01:00
|
|
|
NSString *searchBy, *searchInput, *searchString, *match;
|
2014-08-06 20:49:36 +02:00
|
|
|
NSMutableArray *searchArray;
|
2014-10-17 21:20:25 +02:00
|
|
|
int nbFilters, i;
|
2014-08-06 20:49:36 +02:00
|
|
|
|
2010-05-27 16:41:59 +02:00
|
|
|
request = [context request];
|
2014-08-06 20:49:36 +02:00
|
|
|
content = [[request contentAsString] objectFromJSONString];
|
2010-05-27 16:41:59 +02:00
|
|
|
qualifier = nil;
|
2014-08-06 20:49:36 +02:00
|
|
|
searchString = nil;
|
2014-10-17 21:20:25 +02:00
|
|
|
match = nil;
|
|
|
|
filters = [content objectForKey: @"filters"];
|
2014-08-06 20:49:36 +02:00
|
|
|
|
2014-10-17 21:20:25 +02:00
|
|
|
if (filters)
|
2010-05-27 16:41:59 +02:00
|
|
|
{
|
2014-08-06 20:49:36 +02:00
|
|
|
nbFilters = [filters count];
|
2014-10-17 21:20:25 +02:00
|
|
|
if (nbFilters > 0) {
|
|
|
|
searchArray = [NSMutableArray arrayWithCapacity: nbFilters];
|
|
|
|
sortingAttributes = [content objectForKey: @"sortingAttributes"];
|
|
|
|
if (sortingAttributes)
|
|
|
|
match = [sortingAttributes objectForKey :@"match"]; // AND, OR
|
|
|
|
for (i = 0; i < nbFilters; i++)
|
|
|
|
{
|
2015-03-18 19:03:55 +01:00
|
|
|
filter = [filters objectAtIndex:i];
|
|
|
|
searchBy = [filter objectForKey: @"searchBy"];
|
|
|
|
searchInput = [filter objectForKey: @"searchInput"];
|
|
|
|
if (searchBy && searchInput)
|
|
|
|
{
|
|
|
|
if ([[filter objectForKey: @"negative"] boolValue])
|
|
|
|
searchString = [NSString stringWithFormat: @"(not (%@ doesContain: '%@'))", searchBy, searchInput];
|
|
|
|
else
|
|
|
|
searchString = [NSString stringWithFormat: @"(%@ doesContain: '%@')", searchBy, searchInput];
|
|
|
|
|
|
|
|
searchQualifier = [EOQualifier qualifierWithQualifierFormat: searchString];
|
|
|
|
[searchArray addObject: searchQualifier];
|
|
|
|
}
|
2014-10-17 21:20:25 +02:00
|
|
|
else
|
2015-03-18 19:03:55 +01:00
|
|
|
{
|
|
|
|
[self errorWithFormat: @"Missing parameters in search filter: %@", filter];
|
|
|
|
}
|
2014-10-17 21:20:25 +02:00
|
|
|
}
|
|
|
|
if ([match isEqualToString: @"OR"])
|
|
|
|
qualifier = [[EOOrQualifier alloc] initWithQualifierArray: searchArray];
|
|
|
|
else
|
|
|
|
qualifier = [[EOAndQualifier alloc] initWithQualifierArray: searchArray];
|
|
|
|
}
|
2014-08-06 20:49:36 +02:00
|
|
|
}
|
2014-08-13 23:41:58 +02:00
|
|
|
|
2010-05-27 16:41:59 +02:00
|
|
|
return qualifier;
|
|
|
|
}
|
|
|
|
|
2010-06-25 21:58:30 +02:00
|
|
|
- (NSArray *) getSortedUIDsInFolder: (SOGoMailFolder *) mailFolder
|
2010-05-27 16:41:59 +02:00
|
|
|
{
|
|
|
|
EOQualifier *qualifier, *fetchQualifier, *notDeleted;
|
2014-08-13 23:41:58 +02:00
|
|
|
|
2010-05-27 16:41:59 +02:00
|
|
|
if (!sortedUIDs)
|
|
|
|
{
|
2014-08-06 20:49:36 +02:00
|
|
|
notDeleted = [EOQualifier qualifierWithQualifierFormat: @"(not (flags = %@))", @"deleted"];
|
2010-05-27 16:41:59 +02:00
|
|
|
qualifier = [self searchQualifier];
|
|
|
|
if (qualifier)
|
2014-08-06 20:49:36 +02:00
|
|
|
{
|
|
|
|
fetchQualifier = [[EOAndQualifier alloc] initWithQualifiers: notDeleted, qualifier, nil];
|
|
|
|
[fetchQualifier autorelease];
|
|
|
|
}
|
2010-05-27 16:41:59 +02:00
|
|
|
else
|
2014-08-06 20:49:36 +02:00
|
|
|
fetchQualifier = notDeleted;
|
|
|
|
|
|
|
|
sortedUIDs = [mailFolder fetchUIDsMatchingQualifier: fetchQualifier
|
|
|
|
sortOrdering: [self imap4SortOrdering]
|
|
|
|
threaded: sortByThread];
|
|
|
|
|
2010-05-27 16:41:59 +02:00
|
|
|
[sortedUIDs retain];
|
|
|
|
}
|
2014-08-13 23:41:58 +02:00
|
|
|
|
2010-05-27 16:41:59 +02:00
|
|
|
return sortedUIDs;
|
|
|
|
}
|
|
|
|
|
2011-06-01 23:10:25 +02:00
|
|
|
/**
|
2014-11-21 21:44:19 +01:00
|
|
|
* Returns the messages threads as triples of
|
2011-06-01 23:10:25 +02:00
|
|
|
* metadata, including the message UID, thread level and root position.
|
|
|
|
* @param _sortedUIDs the interleaved arrays representation of the messages UIDs
|
|
|
|
* @return an flatten array representation of the messages UIDs
|
|
|
|
*/
|
|
|
|
- (NSArray *) threadedUIDs: (NSArray *) _sortedUIDs
|
|
|
|
{
|
|
|
|
NSMutableArray *threads;
|
|
|
|
NSMutableArray *currentThreads;
|
|
|
|
NSEnumerator *rootThreads;
|
|
|
|
id thread;
|
|
|
|
int count;
|
|
|
|
int i;
|
|
|
|
BOOL first;
|
|
|
|
BOOL expected;
|
|
|
|
int previousLevel;
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
i = 0;
|
|
|
|
previousLevel = 0;
|
|
|
|
expected = YES;
|
|
|
|
threads = [NSMutableArray arrayWithObject: [NSArray arrayWithObjects: @"uid", @"level", @"first", nil]];
|
|
|
|
rootThreads = [_sortedUIDs objectEnumerator];
|
|
|
|
thread = [rootThreads nextObject];
|
|
|
|
|
|
|
|
// Make sure rootThreads starts with an NSArray
|
|
|
|
if (![thread respondsToSelector: @selector(objectEnumerator)])
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
first = [thread count] > 1;
|
|
|
|
thread = [thread objectEnumerator];
|
|
|
|
|
|
|
|
currentThreads = [NSMutableArray array];
|
|
|
|
|
|
|
|
while (thread)
|
|
|
|
{
|
|
|
|
unsigned int ecount = 0;
|
|
|
|
id t;
|
|
|
|
|
|
|
|
if ([thread isKindOfClass: [NSEnumerator class]])
|
|
|
|
{
|
|
|
|
t = [thread nextObject];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
t = thread; // never happen?
|
|
|
|
while (t && ![t isKindOfClass: [NSArray class]])
|
|
|
|
{
|
|
|
|
BOOL currentFirst;
|
|
|
|
int currentLevel;
|
|
|
|
NSArray *currentThread;
|
|
|
|
|
|
|
|
currentFirst = (first && ecount == 0) || (i == 0 && count > 0) || (count > 0 && previousLevel < 0);
|
|
|
|
currentLevel = (first && ecount == 0)? 0 : (count > 0? count : -1);
|
|
|
|
currentThread = [NSArray arrayWithObjects: t,
|
|
|
|
[NSNumber numberWithInt: currentLevel],
|
|
|
|
[NSNumber numberWithInt: currentFirst], nil];
|
|
|
|
[threads addObject: currentThread];
|
|
|
|
i++;
|
|
|
|
count++;
|
|
|
|
ecount++;
|
|
|
|
expected = NO;
|
|
|
|
previousLevel = currentLevel;
|
|
|
|
t = [thread nextObject];
|
|
|
|
}
|
|
|
|
if (t)
|
|
|
|
{
|
|
|
|
// If t is defined, it has to be an NSArray
|
|
|
|
if (expected)
|
|
|
|
{
|
|
|
|
count++;
|
|
|
|
expected = NO;
|
|
|
|
}
|
|
|
|
thread = [thread allObjects];
|
|
|
|
if ([thread count] > 0)
|
|
|
|
[currentThreads addObject: [thread objectEnumerator]];
|
|
|
|
thread = [t objectEnumerator];
|
|
|
|
}
|
|
|
|
else if ([currentThreads count] > 0)
|
|
|
|
{
|
|
|
|
thread = [currentThreads objectAtIndex: 0];
|
|
|
|
[currentThreads removeObjectAtIndex: 0];
|
|
|
|
count -= ecount;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
thread = [[rootThreads nextObject] objectEnumerator]; // assume all objects of rootThreads are NSArrays
|
|
|
|
count = 0;
|
|
|
|
expected = YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prepare next iteration
|
|
|
|
thread = [thread allObjects];
|
|
|
|
first = !first && (thread != nil) && [thread count] > 1;
|
|
|
|
thread = [thread objectEnumerator];
|
|
|
|
}
|
|
|
|
|
|
|
|
return threads;
|
|
|
|
}
|
|
|
|
|
2010-05-27 16:41:59 +02:00
|
|
|
- (int) indexOfMessageUID: (int) messageNbr
|
|
|
|
{
|
|
|
|
NSArray *messageNbrs;
|
|
|
|
int index;
|
|
|
|
|
2010-06-25 21:58:30 +02:00
|
|
|
messageNbrs = [self getSortedUIDsInFolder: [self clientObject]];
|
2010-05-27 16:41:59 +02:00
|
|
|
index
|
|
|
|
= [messageNbrs indexOfObject: [NSNumber numberWithInt: messageNbr]];
|
|
|
|
// if (index < 0)
|
|
|
|
// index = 0;
|
|
|
|
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* error redirects */
|
|
|
|
|
|
|
|
/*
|
|
|
|
- (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
|
|
|
|
// the active object (displaying the error again)
|
|
|
|
id url;
|
|
|
|
|
|
|
|
if (![_error isNotNull])
|
|
|
|
return [self redirectToLocation:@"view"];
|
|
|
|
|
|
|
|
if ([_error isKindOfClass:[NSException class]])
|
|
|
|
_error = [_error reason];
|
|
|
|
else if ([_error isKindOfClass:[NSString class]])
|
|
|
|
_error = [_error stringValue];
|
|
|
|
|
|
|
|
url = [_error stringByEscapingURL];
|
|
|
|
url = [@"view?error=" stringByAppendingString:url];
|
|
|
|
return [self redirectToLocation:url];
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2011-07-08 19:38:27 +02:00
|
|
|
- (NSDictionary *) getUIDsInFolder: (SOGoMailFolder *) folder
|
|
|
|
withHeaders: (BOOL) includeHeaders
|
2010-05-27 16:41:59 +02:00
|
|
|
{
|
2011-06-01 23:10:25 +02:00
|
|
|
NSArray *uids, *threadedUids, *headers;
|
2015-08-26 15:31:08 +02:00
|
|
|
NSMutableDictionary *data;
|
2011-07-07 15:58:50 +02:00
|
|
|
SOGoMailAccount *account;
|
|
|
|
id quota;
|
2015-08-26 15:31:08 +02:00
|
|
|
|
|
|
|
NSRange r;
|
2011-07-08 19:38:27 +02:00
|
|
|
int count;
|
|
|
|
|
|
|
|
data = [NSMutableDictionary dictionary];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2011-07-08 19:38:27 +02:00
|
|
|
// TODO: we might want to flush the caches?
|
|
|
|
//[folder flushMailCaches];
|
|
|
|
[folder expungeLastMarkedFolder];
|
|
|
|
|
|
|
|
// Retrieve messages UIDs using form parameters "sort" and "asc"
|
|
|
|
uids = [self getSortedUIDsInFolder: folder];
|
2014-08-14 20:49:44 +02:00
|
|
|
|
|
|
|
// Get rid of the extra parenthesis
|
|
|
|
// uids = [[[[uids stringValue] stringByReplacingOccurrencesOfString:@"(" withString:@""] stringByReplacingOccurrencesOfString:@")" withString:@""] componentsSeparatedByString:@","];
|
2011-07-08 19:38:27 +02:00
|
|
|
|
|
|
|
if (includeHeaders)
|
|
|
|
{
|
|
|
|
// Also retrieve the first headers, up to 'headersPrefetchMaxSize'
|
2015-08-26 15:31:08 +02:00
|
|
|
NSArray *a;
|
|
|
|
|
|
|
|
a = [uids flattenedArray];
|
|
|
|
count = [a count];
|
|
|
|
if (count > headersPrefetchMaxSize)
|
|
|
|
count = headersPrefetchMaxSize;
|
2011-07-08 19:38:27 +02:00
|
|
|
r = NSMakeRange(0, count);
|
2015-08-26 15:31:08 +02:00
|
|
|
headers = [self getHeadersForUIDs: [a subarrayWithRange: r]
|
2011-07-08 19:38:27 +02:00
|
|
|
inFolder: folder];
|
|
|
|
|
|
|
|
[data setObject: headers forKey: @"headers"];
|
|
|
|
}
|
|
|
|
|
2011-06-01 23:10:25 +02:00
|
|
|
if (sortByThread)
|
|
|
|
{
|
2011-07-08 19:38:27 +02:00
|
|
|
// Add threads information
|
2011-06-01 23:10:25 +02:00
|
|
|
threadedUids = [self threadedUIDs: uids];
|
|
|
|
if (threadedUids != nil)
|
|
|
|
uids = threadedUids;
|
|
|
|
else
|
|
|
|
sortByThread = NO;
|
|
|
|
}
|
2011-07-26 18:25:34 +02:00
|
|
|
if (uids != nil)
|
|
|
|
[data setObject: uids forKey: @"uids"];
|
2011-07-08 19:38:27 +02:00
|
|
|
[data setObject: [NSNumber numberWithBool: sortByThread] forKey: @"threaded"];
|
|
|
|
|
2015-07-31 20:31:38 +02:00
|
|
|
// We get the unseen count
|
|
|
|
[data setObject: [NSNumber numberWithUnsignedInt: [folder unseenCount]] forKey: @"unseenCount"];
|
|
|
|
|
2011-07-07 15:58:50 +02:00
|
|
|
// We also return the inbox quota
|
2011-07-08 19:38:27 +02:00
|
|
|
account = [folder mailAccountFolder];
|
2011-07-07 15:58:50 +02:00
|
|
|
quota = [account getInboxQuota];
|
2011-07-14 17:26:49 +02:00
|
|
|
if (quota != nil)
|
|
|
|
[data setObject: quota forKey: @"quotas"];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2010-06-25 21:58:30 +02:00
|
|
|
return data;
|
|
|
|
}
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2011-06-01 23:10:25 +02:00
|
|
|
/* Module actions */
|
|
|
|
|
2015-03-18 19:03:55 +01:00
|
|
|
/**
|
|
|
|
* @api {get} /so/:username/Mail/:accountId/:mailboxPath/view List messages UIDs
|
|
|
|
* @apiVersion 1.0.0
|
|
|
|
* @apiName GetMailUIDsList
|
|
|
|
* @apiGroup Mail
|
|
|
|
* @apiExample {curl} Example usage:
|
|
|
|
* curl -i http://localhost/SOGo/so/sogo1/Mail/0/folderINBOX/view
|
|
|
|
* -H 'Content-Type: application/json' \
|
|
|
|
* -d '{ "sortingAttributes": { "match": "AND", "asc": true, "sort": "subject" }, \
|
|
|
|
* "filters": [{ "searchBy": "subject", "searchInput": "foo" }] }'
|
|
|
|
*
|
|
|
|
* @apiParam {Object} [sortingAttributes] Sorting preferences
|
|
|
|
* @apiParam {Boolean} [sortingAttributes.asc] Descending sort when false. Defaults to true (ascending).
|
|
|
|
* @apiParam {String} [sortingAttributes.sort] Sort field. Either c_cn, c_mail, c_screenname, c_o, or c_telephonenumber.
|
|
|
|
* @apiParam {String} [sortingAttributes.match] Either OR or AND.
|
|
|
|
* @apiParam {String} [sortingAttributes.noHeaders] Don't send the headers if true. Defaults to false.
|
|
|
|
* @apiParam {Object[]} [filters] The filters to apply.
|
|
|
|
* @apiParam {String} filters.searchBy Field criteria. Either subject, from, to, cc, or body.
|
|
|
|
* @apiParam {String} filters.searchInput String to match.
|
|
|
|
* @apiParam {String} [filters.negative] Reverse the condition when true. Defaults to false.
|
|
|
|
*
|
|
|
|
* @apiSuccess (Success 200) {Number} threaded 1 if threading is enabled for the user.
|
2015-07-31 20:31:38 +02:00
|
|
|
* @apiSuccess (Success 200) {Number} unseenCount Number of unread messages
|
2015-03-18 19:03:55 +01:00
|
|
|
* @apiSuccess (Success 200) {Number[]} uids List of uids matching the filters, in the requested order.
|
|
|
|
* @apiSuccess (Success 200) {String[]} headers The first entry are the fields names.
|
|
|
|
* @apiSuccess (Success 200) {Object[]} headers.To Recipients
|
|
|
|
* @apiSuccess (Success 200) {String} headers.To.name Recipient's name
|
|
|
|
* @apiSuccess (Success 200) {String} headers.To.email Recipient's email address
|
|
|
|
* @apiSuccess (Success 200) {Number} headers.hasAttachment 1 when there is at least one attachment
|
|
|
|
* @apiSuccess (Success 200) {Number} headers.isFlagged 1 if the message is flagged
|
|
|
|
* @apiSuccess (Success 200) {String} headers.Subject Subject
|
|
|
|
* @apiSuccess (Success 200) {Object[]} headers.From Senders
|
|
|
|
* @apiSuccess (Success 200) {String} headers.From.name Sender's name
|
|
|
|
* @apiSuccess (Success 200) {String} headers.From.email Sender's email address
|
|
|
|
* @apiSuccess (Success 200) {Number} headers.isRead 1 if message is read
|
|
|
|
* @apiSuccess (Success 200) {String} headers.Priority Priority
|
2015-09-24 20:36:06 +02:00
|
|
|
* @apiSuccess (Success 200) {String} headers.Priority.level Priority number
|
|
|
|
* @apiSuccess (Success 200) {String} headers.Priority.name Priority description
|
2015-03-18 19:03:55 +01:00
|
|
|
* @apiSuccess (Success 200) {String} headers.RelativeDate Message date relative to now
|
|
|
|
* @apiSuccess (Success 200) {String} headers.Size Formatted message size
|
|
|
|
* @apiSuccess (Success 200) {String[]} headers.Flags Flags, such as "answered" and "seen"
|
|
|
|
* @apiSuccess (Success 200) {Number} headers.uid Message UID
|
|
|
|
* @apiSuccess (Success 200) {Object} [quotas] Quota information
|
|
|
|
* @apiSuccess (Success 200) {Number} [quotas.usedSpace] Used space
|
|
|
|
* @apiSuccess (Success 200) {Number} [quotas.maxQuota] Mailbox maximum quota
|
|
|
|
*/
|
2011-07-08 19:38:27 +02:00
|
|
|
- (id <WOActionResults>) getUIDsAction
|
2010-06-25 21:58:30 +02:00
|
|
|
{
|
2015-03-18 19:03:55 +01:00
|
|
|
BOOL noHeaders;
|
2014-08-13 23:41:58 +02:00
|
|
|
NSDictionary *data, *requestContent;
|
2010-06-25 21:58:30 +02:00
|
|
|
SOGoMailFolder *folder;
|
2010-11-05 22:32:00 +01:00
|
|
|
WORequest *request;
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2010-11-05 22:32:00 +01:00
|
|
|
request = [context request];
|
2014-08-13 23:41:58 +02:00
|
|
|
requestContent = [[request contentAsString] objectFromJSONString];
|
2014-08-06 20:49:36 +02:00
|
|
|
|
2010-11-05 22:32:00 +01:00
|
|
|
folder = [self clientObject];
|
2011-07-07 15:58:50 +02:00
|
|
|
|
2015-03-18 19:03:55 +01:00
|
|
|
noHeaders = [[[requestContent objectForKey: @"sortingAttributes"] objectForKey:@"noHeaders"] boolValue];
|
2011-07-08 19:38:27 +02:00
|
|
|
data = [self getUIDsInFolder: folder
|
2015-03-18 19:03:55 +01:00
|
|
|
withHeaders: !noHeaders];
|
2011-03-15 20:36:25 +01:00
|
|
|
|
2016-01-07 21:12:13 +01:00
|
|
|
return [self responseWithStatus: 200 andJSONRepresentation: data];
|
2010-05-27 16:41:59 +02:00
|
|
|
}
|
|
|
|
|
2010-06-25 21:58:30 +02:00
|
|
|
- (NSArray *) getHeadersForUIDs: (NSArray *) uids
|
|
|
|
inFolder: (SOGoMailFolder *) mailFolder
|
2010-05-27 16:41:59 +02:00
|
|
|
{
|
2015-05-04 19:56:29 +02:00
|
|
|
UIxEnvelopeAddressFormatter *addressFormatter;
|
|
|
|
NSMutableArray *headers, *msg, *tags;
|
|
|
|
NSEnumerator *msgsList;
|
2010-06-25 21:58:30 +02:00
|
|
|
NSArray *to, *from;
|
2010-05-27 16:41:59 +02:00
|
|
|
NSDictionary *msgs;
|
2014-11-21 21:44:19 +01:00
|
|
|
NSString *msgDate;
|
2010-05-27 16:41:59 +02:00
|
|
|
|
|
|
|
headers = [NSMutableArray arrayWithCapacity: [uids count]];
|
|
|
|
addressFormatter = [context mailEnvelopeAddressFormatter];
|
|
|
|
|
|
|
|
// Fetch headers
|
|
|
|
msgs = (NSDictionary *)[mailFolder fetchUIDs: uids
|
|
|
|
parts: [self fetchKeys]];
|
|
|
|
|
|
|
|
msgsList = [[msgs objectForKey: @"fetch"] objectEnumerator];
|
|
|
|
[self setMessage: [msgsList nextObject]];
|
2010-06-25 21:58:30 +02:00
|
|
|
|
2015-05-05 15:49:40 +02:00
|
|
|
msg = [NSMutableArray arrayWithObjects: @"To", @"hasAttachment", @"isFlagged", @"Subject", @"From", @"isRead", @"Priority", @"RelativeDate", @"Size", @"Flags", @"uid", @"isAnswered", @"isForwarded", nil];
|
2010-06-25 21:58:30 +02:00
|
|
|
[headers addObject: msg];
|
2010-05-27 16:41:59 +02:00
|
|
|
while (message)
|
|
|
|
{
|
2010-09-15 12:33:07 +02:00
|
|
|
// We must check for "umimportant" untagged responses.
|
|
|
|
//
|
|
|
|
// It's generally caused by IMAP server processes sending untagged IMAP responses to SOGo in differnent IMAP
|
|
|
|
// connections (SOGo might use 2-3 per user). Say you ask your messages:
|
|
|
|
//
|
|
|
|
// 127.000.000.001.40725-127.000.000.001.00143: 59 uid fetch 62 (UID FLAGS ENVELOPE RFC822.SIZE BODYSTRUCTURE BODY.PEEK[HEADER.FIELDS (X-PRIORITY)])
|
|
|
|
// 127.000.000.001.00143-127.000.000.001.40725: * 62 FETCH (UID 62 FLAGS (\Seen) RFC822.SIZE 854 ENVELOPE .... (
|
|
|
|
// * 61 FETCH (FLAGS (\Deleted \Seen))
|
|
|
|
// * 62 FETCH (FLAGS (\Deleted \Seen))
|
|
|
|
// * 63 FETCH (FLAGS (\Deleted \Seen))
|
|
|
|
// 59 OK Fetch completed.
|
|
|
|
//
|
|
|
|
// We must ignore the * 61 .. * 63 untagged responses.
|
|
|
|
//
|
|
|
|
if (![message objectForKey: @"uid"])
|
|
|
|
{
|
|
|
|
[self setMessage: [msgsList nextObject]];
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-06-25 21:58:30 +02:00
|
|
|
msg = [NSMutableArray arrayWithCapacity: 12];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
|
|
|
// Columns data
|
|
|
|
|
2010-06-25 21:58:30 +02:00
|
|
|
// To
|
2010-05-27 16:41:59 +02:00
|
|
|
to = [[message objectForKey: @"envelope"] to];
|
|
|
|
if ([to count] > 0)
|
2014-12-06 04:49:08 +01:00
|
|
|
[msg addObject: [addressFormatter dictionariesForArray: to]];
|
2010-06-25 21:58:30 +02:00
|
|
|
else
|
|
|
|
[msg addObject: @""];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2014-11-21 21:44:19 +01:00
|
|
|
// hasAttachment
|
|
|
|
[msg addObject: [NSNumber numberWithBool: [self hasMessageAttachment]]];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2014-11-21 21:44:19 +01:00
|
|
|
// isFlagged
|
|
|
|
[msg addObject: [NSNumber numberWithBool: [self isMessageFlagged]]];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2010-06-25 21:58:30 +02:00
|
|
|
// Subject
|
2014-11-21 21:44:19 +01:00
|
|
|
[msg addObject: [self messageSubject]];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2010-06-25 21:58:30 +02:00
|
|
|
// From
|
2010-06-07 15:34:10 +02:00
|
|
|
from = [[message objectForKey: @"envelope"] from];
|
|
|
|
if ([from count] > 0)
|
2014-12-06 04:49:08 +01:00
|
|
|
[msg addObject: [addressFormatter dictionariesForArray: from]];
|
2010-06-07 15:34:10 +02:00
|
|
|
else
|
2010-06-25 21:58:30 +02:00
|
|
|
[msg addObject: @""];
|
2010-06-07 15:34:10 +02:00
|
|
|
|
2014-11-21 21:44:19 +01:00
|
|
|
// isRead
|
|
|
|
[msg addObject: [NSNumber numberWithBool: [self isMessageRead]]];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2010-06-25 21:58:30 +02:00
|
|
|
// Priority
|
|
|
|
[msg addObject: [self messagePriority]];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2014-11-27 14:58:33 +01:00
|
|
|
// Relative Date
|
2010-06-07 15:24:17 +02:00
|
|
|
msgDate = [self messageDate];
|
|
|
|
if (msgDate == nil)
|
|
|
|
msgDate = @"";
|
2010-06-25 21:58:30 +02:00
|
|
|
[msg addObject: msgDate];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2010-06-25 21:58:30 +02:00
|
|
|
// Size
|
2013-12-18 14:38:03 +01:00
|
|
|
[msg addObject: [[self sizeFormatter] stringForObjectValue: [message objectForKey: @"size"]]];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2015-05-04 19:56:29 +02:00
|
|
|
// Mail labels / tags
|
|
|
|
tags = [NSMutableArray arrayWithArray: [message objectForKey: @"flags"]];
|
2015-05-05 15:49:40 +02:00
|
|
|
[tags removeObject: @"answered"];
|
2015-05-04 19:56:29 +02:00
|
|
|
[tags removeObject: @"deleted"];
|
2015-05-05 19:06:31 +02:00
|
|
|
[tags removeObject: @"draft"];
|
2015-05-05 15:49:40 +02:00
|
|
|
[tags removeObject: @"flagged"];
|
2015-05-04 19:56:29 +02:00
|
|
|
[tags removeObject: @"recent"];
|
|
|
|
[tags removeObject: @"seen"];
|
2015-05-05 15:49:40 +02:00
|
|
|
[tags removeObject: @"$forwarded"];
|
2015-05-04 19:56:29 +02:00
|
|
|
[msg addObject: tags];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
2015-05-04 19:56:29 +02:00
|
|
|
// UID
|
2010-09-15 12:33:07 +02:00
|
|
|
[msg addObject: [message objectForKey: @"uid"]];
|
2010-05-27 16:41:59 +02:00
|
|
|
[headers addObject: msg];
|
2015-05-05 15:49:40 +02:00
|
|
|
|
|
|
|
// isAnswered
|
|
|
|
[msg addObject: [NSNumber numberWithBool: [self isMessageAnswered]]];
|
|
|
|
|
|
|
|
// isForwarded
|
|
|
|
[msg addObject: [NSNumber numberWithBool: [self isMessageForwarded]]];
|
2010-05-27 16:41:59 +02:00
|
|
|
|
|
|
|
[self setMessage: [msgsList nextObject]];
|
|
|
|
}
|
|
|
|
|
2010-06-25 21:58:30 +02:00
|
|
|
return headers;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id <WOActionResults>) getHeadersAction
|
|
|
|
{
|
|
|
|
NSArray *uids, *headers;
|
2014-11-25 15:57:08 +01:00
|
|
|
NSDictionary *data;
|
2010-06-25 21:58:30 +02:00
|
|
|
WORequest *request;
|
|
|
|
WOResponse *response;
|
|
|
|
|
|
|
|
request = [context request];
|
2014-11-25 15:57:08 +01:00
|
|
|
data = [[request contentAsString] objectFromJSONString];
|
|
|
|
if (![[data objectForKey: @"uids"] isKindOfClass: [NSArray class]]
|
|
|
|
|| [[data objectForKey: @"uids"] count] == 0)
|
2010-06-25 21:58:30 +02:00
|
|
|
{
|
2014-11-25 15:57:08 +01:00
|
|
|
data = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
@"No UID specified", @"error", nil];
|
|
|
|
return [self responseWithStatus: 404 /* Not Found */
|
2015-08-29 02:11:21 +02:00
|
|
|
andString: [data jsonRepresentation]];
|
2010-06-25 21:58:30 +02:00
|
|
|
}
|
|
|
|
|
2014-11-25 15:57:08 +01:00
|
|
|
uids = [data objectForKey: @"uids"];
|
2010-06-25 21:58:30 +02:00
|
|
|
headers = [self getHeadersForUIDs: uids
|
|
|
|
inFolder: [self clientObject]];
|
2014-11-25 15:57:08 +01:00
|
|
|
|
2010-05-27 16:41:59 +02:00
|
|
|
response = [context response];
|
2014-11-21 21:44:19 +01:00
|
|
|
[response setHeader: @"application/json; charset=utf-8"
|
2010-05-27 16:41:59 +02:00
|
|
|
forKey: @"content-type"];
|
|
|
|
[response appendContentString: [headers jsonRepresentation]];
|
|
|
|
|
|
|
|
return response;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
/* UIxMailListActions */
|