Monotone-Revision: c5a12fa92d4b395d0d89e97ca85e5ad92a5b087f Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2007-09-11T19:42:41 Monotone-Branch: ca.inverse.sogo
455 lines
9.4 KiB
Objective-C
455 lines
9.4 KiB
Objective-C
/*
|
|
Copyright (C) 2004-2005 SKYRIX Software AG
|
|
|
|
This file is part of OpenGroupware.org.
|
|
|
|
OGo is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU Lesser General Public License as published by the
|
|
Free Software Foundation; either version 2, or (at your option) any
|
|
later version.
|
|
|
|
OGo is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with OGo; see the file COPYING. If not, write to the
|
|
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|
02111-1307, USA.
|
|
*/
|
|
|
|
#import <Foundation/NSFileManager.h>
|
|
#import <Foundation/NSKeyValueCoding.h>
|
|
#import <Foundation/NSString.h>
|
|
#import <Foundation/NSUserDefaults.h>
|
|
|
|
#import <NGObjWeb/NSException+HTTP.h>
|
|
#import <NGObjWeb/SoSubContext.h>
|
|
#import <NGObjWeb/WORequest.h>
|
|
#import <NGObjWeb/WOResponse.h>
|
|
#import <NGExtensions/NSNull+misc.h>
|
|
#import <NGExtensions/NSObject+Logs.h>
|
|
#import <NGExtensions/NSString+misc.h>
|
|
#import <NGExtensions/NSException+misc.h>
|
|
#import <NGMail/NGMimeMessage.h>
|
|
#import <NGMail/NGMimeMessageGenerator.h>
|
|
#import <NGMime/NGMimeBodyPart.h>
|
|
#import <NGMime/NGMimeHeaderFields.h>
|
|
#import <NGMime/NGMimeMultipartBody.h>
|
|
|
|
#import <SoObjects/Mailer/SOGoDraftObject.h>
|
|
#import <SoObjects/Mailer/SOGoMailFolder.h>
|
|
#import <SoObjects/Mailer/SOGoMailAccount.h>
|
|
#import <SoObjects/Mailer/SOGoMailAccounts.h>
|
|
#import <SoObjects/SOGo/SOGoUser.h>
|
|
#import <SoObjects/SOGo/NSArray+Utilities.h>
|
|
#import <SoObjects/SOGo/NSDictionary+Utilities.h>
|
|
#import <SOGoUI/UIxComponent.h>
|
|
|
|
/*
|
|
UIxMailEditor
|
|
|
|
An mail editor component which works on SOGoDraftObject's.
|
|
*/
|
|
|
|
@interface UIxMailEditor : UIxComponent
|
|
{
|
|
NSArray *to;
|
|
NSArray *cc;
|
|
NSArray *bcc;
|
|
NSString *subject;
|
|
NSString *text;
|
|
NSArray *fromEMails;
|
|
NSString *from;
|
|
SOGoMailFolder *sentFolder;
|
|
|
|
/* these are for the inline attachment list */
|
|
NSString *attachmentName;
|
|
NSArray *attachmentNames;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation UIxMailEditor
|
|
|
|
static BOOL showInternetMarker = NO;
|
|
static BOOL useLocationBasedSentFolder = NO;
|
|
static NSDictionary *internetMailHeaders = nil;
|
|
static NSArray *infoKeys = nil;
|
|
|
|
+ (void) initialize
|
|
{
|
|
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
|
|
|
infoKeys = [[NSArray alloc] initWithObjects:
|
|
@"subject", @"to", @"cc", @"bcc",
|
|
@"from", @"replyTo", @"inReplyTo",
|
|
nil];
|
|
|
|
useLocationBasedSentFolder =
|
|
[ud boolForKey:@"SOGoUseLocationBasedSentFolder"];
|
|
|
|
/* Internet mail settings */
|
|
|
|
showInternetMarker = [ud boolForKey:@"SOGoShowInternetMarker"];
|
|
if (!showInternetMarker)
|
|
NSLog(@"Note: visual Internet marker on mail editor disabled "
|
|
@"(SOGoShowInternetMarker)");
|
|
|
|
internetMailHeaders =
|
|
[[ud dictionaryForKey:@"SOGoInternetMailHeaders"] copy];
|
|
NSLog (@"Note: specified %d headers for mails send via the Internet.",
|
|
[internetMailHeaders count]);
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
[sentFolder release];
|
|
[fromEMails release];
|
|
[from release];
|
|
[text release];
|
|
[subject release];
|
|
[to release];
|
|
[cc release];
|
|
[bcc release];
|
|
[attachmentName release];
|
|
[attachmentNames release];
|
|
[super dealloc];
|
|
}
|
|
|
|
/* accessors */
|
|
|
|
- (void) setFrom: (NSString *) newFrom
|
|
{
|
|
ASSIGN (from, newFrom);
|
|
}
|
|
|
|
- (NSString *) from
|
|
{
|
|
NSDictionary *identity;
|
|
|
|
if (!from)
|
|
{
|
|
identity = [[context activeUser] primaryIdentity];
|
|
from = [identity keysWithFormat: @"%{fullName} <%{email}>"];
|
|
}
|
|
|
|
return from;
|
|
}
|
|
|
|
// - (void) setReplyTo: (NSString *) ignore
|
|
// {
|
|
// }
|
|
|
|
// - (NSString *) replyTo
|
|
// {
|
|
// /* we are here for future extensibility */
|
|
// return @"";
|
|
// }
|
|
|
|
- (void) setSubject: (NSString *) newSubject
|
|
{
|
|
ASSIGN (subject, newSubject);
|
|
}
|
|
|
|
- (NSString *) subject
|
|
{
|
|
return subject;
|
|
}
|
|
|
|
- (void) setText: (NSString *) newText
|
|
{
|
|
ASSIGN (text, newText);
|
|
}
|
|
|
|
- (NSString *) text
|
|
{
|
|
return text;
|
|
}
|
|
|
|
- (void) setTo: (NSArray *) newTo
|
|
{
|
|
if ([newTo isKindOfClass: [NSNull class]])
|
|
newTo = nil;
|
|
|
|
ASSIGN (to, newTo);
|
|
}
|
|
|
|
- (NSArray *) to
|
|
{
|
|
return to;
|
|
}
|
|
|
|
- (void) setCc: (NSArray *) newCc
|
|
{
|
|
if ([newCc isKindOfClass: [NSNull class]])
|
|
newCc = nil;
|
|
|
|
ASSIGN (cc, newCc);
|
|
}
|
|
|
|
- (NSArray *) cc
|
|
{
|
|
return cc;
|
|
}
|
|
|
|
- (void) setBcc: (NSArray *) newBcc
|
|
{
|
|
if ([newBcc isKindOfClass: [NSNull class]])
|
|
newBcc = nil;
|
|
|
|
ASSIGN (bcc, newBcc);
|
|
}
|
|
|
|
- (NSArray *) bcc
|
|
{
|
|
return bcc;
|
|
}
|
|
|
|
- (BOOL) hasOneOrMoreRecipients
|
|
{
|
|
return (([to count] + [cc count] + [bcc count]) > 0);
|
|
}
|
|
|
|
- (void) setAttachmentName: (NSString *) newAttachmentName
|
|
{
|
|
ASSIGN (attachmentName, newAttachmentName);
|
|
}
|
|
|
|
- (NSString *) attachmentName
|
|
{
|
|
return attachmentName;
|
|
}
|
|
|
|
/* from addresses */
|
|
|
|
- (NSArray *) fromEMails
|
|
{
|
|
NSArray *allIdentities;
|
|
|
|
if (!fromEMails)
|
|
{
|
|
allIdentities = [[context activeUser] allIdentities];
|
|
fromEMails = [allIdentities keysWithFormat: @"%{fullName} <%{email}>"];
|
|
[fromEMails retain];
|
|
}
|
|
|
|
return fromEMails;
|
|
}
|
|
|
|
/* info loading */
|
|
|
|
- (void) loadInfo: (NSDictionary *) _info
|
|
{
|
|
if (![_info isNotNull]) return;
|
|
[self debugWithFormat:@"loading info ..."];
|
|
[self takeValuesFromDictionary:_info];
|
|
}
|
|
|
|
- (NSDictionary *) storeInfo
|
|
{
|
|
[self debugWithFormat:@"storing info ..."];
|
|
return [self valuesForKeys:infoKeys];
|
|
}
|
|
|
|
/* requests */
|
|
|
|
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
|
|
inContext: (WOContext*) localContext
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
/* actions */
|
|
|
|
- (NSDictionary *) _scanAttachmentFilenamesInRequest: (id) httpBody
|
|
{
|
|
NSMutableDictionary *filenames;
|
|
NSDictionary *attachment;
|
|
NSArray *parts;
|
|
unsigned int count, max;
|
|
NGMimeBodyPart *part;
|
|
NGMimeContentDispositionHeaderField *header;
|
|
NSString *mimeType;
|
|
|
|
parts = [httpBody parts];
|
|
max = [parts count];
|
|
filenames = [NSMutableDictionary dictionaryWithCapacity: max];
|
|
|
|
for (count = 0; count < max; count++)
|
|
{
|
|
part = [parts objectAtIndex: count];
|
|
header = (NGMimeContentDispositionHeaderField *) [part headerForKey: @"content-disposition"];
|
|
mimeType = [(NGMimeType *) [part headerForKey: @"content-type"] stringValue];
|
|
attachment = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
[header filename], @"filename",
|
|
mimeType, @"mime-type", nil];
|
|
[filenames setObject: attachment
|
|
forKey: [header name]];
|
|
}
|
|
|
|
return filenames;
|
|
}
|
|
|
|
- (BOOL) _saveAttachments
|
|
{
|
|
WORequest *request;
|
|
NSEnumerator *allKeys;
|
|
NSString *key;
|
|
BOOL success;
|
|
NSDictionary *filenames;
|
|
id httpBody;
|
|
SOGoDraftObject *co;
|
|
|
|
success = YES;
|
|
request = [context request];
|
|
|
|
httpBody = [[request httpRequest] body];
|
|
filenames = [self _scanAttachmentFilenamesInRequest: httpBody];
|
|
|
|
co = [self clientObject];
|
|
allKeys = [[request formValueKeys] objectEnumerator];
|
|
key = [allKeys nextObject];
|
|
while (key && success)
|
|
{
|
|
if ([key hasPrefix: @"attachment"])
|
|
success
|
|
= (![co saveAttachment: (NSData *) [request formValueForKey: key]
|
|
withMetadata: [filenames objectForKey: key]]);
|
|
key = [allKeys nextObject];
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
- (BOOL) _saveFormInfo
|
|
{
|
|
NSDictionary *info;
|
|
NSException *error;
|
|
BOOL success;
|
|
SOGoDraftObject *co;
|
|
|
|
co = [self clientObject];
|
|
[co fetchInfo];
|
|
|
|
success = YES;
|
|
|
|
if ([self _saveAttachments])
|
|
{
|
|
info = [self storeInfo];
|
|
[co setHeaders: info];
|
|
[co setText: text];
|
|
error = [co storeInfo];
|
|
if (error)
|
|
{
|
|
[self errorWithFormat: @"failed to store draft: %@", error];
|
|
// TODO: improve error handling
|
|
success = NO;
|
|
}
|
|
}
|
|
else
|
|
success = NO;
|
|
|
|
// TODO: wrap content
|
|
|
|
return success;
|
|
}
|
|
|
|
- (id) failedToSaveFormResponse
|
|
{
|
|
// TODO: improve error handling
|
|
return [NSException exceptionWithHTTPStatus:500 /* server error */
|
|
reason:@"failed to store draft object on server!"];
|
|
}
|
|
|
|
/* attachment helper */
|
|
|
|
- (NSArray *) attachmentNames
|
|
{
|
|
NSArray *a;
|
|
|
|
if (attachmentNames != nil)
|
|
return attachmentNames;
|
|
|
|
a = [[self clientObject] fetchAttachmentNames];
|
|
a = [a sortedArrayUsingSelector: @selector (compare:)];
|
|
attachmentNames = [a copy];
|
|
|
|
return attachmentNames;
|
|
}
|
|
|
|
- (BOOL) hasAttachments
|
|
{
|
|
return [[self attachmentNames] count] > 0 ? YES : NO;
|
|
}
|
|
|
|
- (id) defaultAction
|
|
{
|
|
SOGoDraftObject *co;
|
|
|
|
co = [self clientObject];
|
|
[co fetchInfo];
|
|
[self loadInfo: [co headers]];
|
|
[self setText: [co text]];
|
|
|
|
return self;
|
|
}
|
|
|
|
- (id <WOActionResults>) saveAction
|
|
{
|
|
id result;
|
|
|
|
if ([self _saveFormInfo])
|
|
{
|
|
result = [[self clientObject] save];
|
|
if (!result)
|
|
result = [self responseWith204];
|
|
}
|
|
else
|
|
result = [self failedToSaveFormResponse];
|
|
|
|
return result;
|
|
}
|
|
|
|
- (NSException *) validateForSend
|
|
{
|
|
NSException *error;
|
|
|
|
if (![self hasOneOrMoreRecipients])
|
|
error = [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
|
|
reason: @"Please select a recipient!"];
|
|
else if ([[self subject] length] == 0)
|
|
error = [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
|
|
reason: @"Please set a subject!"];
|
|
else
|
|
error = nil;
|
|
|
|
return error;
|
|
}
|
|
|
|
- (id <WOActionResults>) sendAction
|
|
{
|
|
id <WOActionResults> result;
|
|
|
|
// TODO: need to validate whether we have a To etc
|
|
|
|
/* first, save form data */
|
|
result = [self validateForSend];
|
|
if (!result)
|
|
{
|
|
if ([self _saveFormInfo])
|
|
{
|
|
result = [[self clientObject] sendMail];
|
|
if (!result)
|
|
result = [self jsCloseWithRefreshMethod: nil];
|
|
}
|
|
else
|
|
result = [self failedToSaveFormResponse];
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
@end /* UIxMailEditor */
|