2 Copyright (C) 2004-2005 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #import <Foundation/NSFileManager.h>
23 #import <Foundation/NSKeyValueCoding.h>
24 #import <Foundation/NSString.h>
25 #import <Foundation/NSUserDefaults.h>
27 #import <NGObjWeb/NSException+HTTP.h>
28 #import <NGObjWeb/SoSubContext.h>
29 #import <NGObjWeb/WORequest.h>
30 #import <NGObjWeb/WOResponse.h>
31 #import <NGExtensions/NSNull+misc.h>
32 #import <NGExtensions/NSObject+Logs.h>
33 #import <NGExtensions/NSString+misc.h>
34 #import <NGExtensions/NSException+misc.h>
35 #import <NGMail/NGMimeMessage.h>
36 #import <NGMail/NGMimeMessageGenerator.h>
37 #import <NGMime/NGMimeBodyPart.h>
38 #import <NGMime/NGMimeHeaderFields.h>
39 #import <NGMime/NGMimeMultipartBody.h>
41 #import <SoObjects/Mailer/SOGoDraftObject.h>
42 #import <SoObjects/Mailer/SOGoMailFolder.h>
43 #import <SoObjects/Mailer/SOGoMailAccount.h>
44 #import <SoObjects/Mailer/SOGoMailAccounts.h>
45 #import <SoObjects/SOGo/SOGoUser.h>
46 #import <SoObjects/SOGo/NSArray+Utilities.h>
47 #import <SoObjects/SOGo/NSDictionary+Utilities.h>
48 #import <SOGoUI/UIxComponent.h>
53 An mail editor component which works on SOGoDraftObject's.
56 @interface UIxMailEditor : UIxComponent
65 SOGoMailFolder *sentFolder;
67 /* these are for the inline attachment list */
68 NSString *attachmentName;
69 NSArray *attachmentNames;
74 @implementation UIxMailEditor
76 static BOOL showInternetMarker = NO;
77 static BOOL useLocationBasedSentFolder = NO;
78 static NSDictionary *internetMailHeaders = nil;
79 static NSArray *infoKeys = nil;
83 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
85 infoKeys = [[NSArray alloc] initWithObjects:
86 @"subject", @"to", @"cc", @"bcc",
87 @"from", @"replyTo", @"inReplyTo",
90 useLocationBasedSentFolder =
91 [ud boolForKey:@"SOGoUseLocationBasedSentFolder"];
93 /* Internet mail settings */
95 showInternetMarker = [ud boolForKey:@"SOGoShowInternetMarker"];
96 if (!showInternetMarker)
97 NSLog(@"Note: visual Internet marker on mail editor disabled "
98 @"(SOGoShowInternetMarker)");
100 internetMailHeaders =
101 [[ud dictionaryForKey:@"SOGoInternetMailHeaders"] copy];
102 NSLog (@"Note: specified %d headers for mails send via the Internet.",
103 [internetMailHeaders count]);
108 [sentFolder release];
109 [fromEMails release];
116 [attachmentName release];
117 [attachmentNames release];
123 - (void) setFrom: (NSString *) newFrom
125 ASSIGN (from, newFrom);
130 NSDictionary *identity;
134 identity = [[context activeUser] primaryIdentity];
135 from = [identity keysWithFormat: @"%{fullName} <%{email}>"];
141 // - (void) setReplyTo: (NSString *) ignore
145 // - (NSString *) replyTo
147 // /* we are here for future extensibility */
151 - (void) setSubject: (NSString *) newSubject
153 ASSIGN (subject, newSubject);
156 - (NSString *) subject
161 - (void) setText: (NSString *) newText
163 ASSIGN (text, newText);
171 - (void) setTo: (NSArray *) newTo
173 if ([newTo isKindOfClass: [NSNull class]])
184 - (void) setCc: (NSArray *) newCc
186 if ([newCc isKindOfClass: [NSNull class]])
197 - (void) setBcc: (NSArray *) newBcc
199 if ([newBcc isKindOfClass: [NSNull class]])
202 ASSIGN (bcc, newBcc);
210 - (BOOL) hasOneOrMoreRecipients
212 return (([to count] + [cc count] + [bcc count]) > 0);
215 - (void) setAttachmentName: (NSString *) newAttachmentName
217 ASSIGN (attachmentName, newAttachmentName);
220 - (NSString *) attachmentName
222 return attachmentName;
227 - (NSArray *) fromEMails
229 NSArray *allIdentities;
233 allIdentities = [[context activeUser] allIdentities];
234 fromEMails = [allIdentities keysWithFormat: @"%{fullName} <%{email}>"];
243 - (void) loadInfo: (NSDictionary *) _info
245 if (![_info isNotNull]) return;
246 [self debugWithFormat:@"loading info ..."];
247 [self takeValuesFromDictionary:_info];
250 - (NSDictionary *) storeInfo
252 [self debugWithFormat:@"storing info ..."];
253 return [self valuesForKeys:infoKeys];
258 - (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
259 inContext: (WOContext*) localContext
266 - (NSDictionary *) _scanAttachmentFilenamesInRequest: (id) httpBody
268 NSMutableDictionary *filenames;
269 NSDictionary *attachment;
271 unsigned int count, max;
272 NGMimeBodyPart *part;
273 NGMimeContentDispositionHeaderField *header;
276 parts = [httpBody parts];
278 filenames = [NSMutableDictionary dictionaryWithCapacity: max];
280 for (count = 0; count < max; count++)
282 part = [parts objectAtIndex: count];
283 header = (NGMimeContentDispositionHeaderField *) [part headerForKey: @"content-disposition"];
284 mimeType = [(NGMimeType *) [part headerForKey: @"content-type"] stringValue];
285 attachment = [NSDictionary dictionaryWithObjectsAndKeys:
286 [header filename], @"filename",
287 mimeType, @"mime-type", nil];
288 [filenames setObject: attachment
289 forKey: [header name]];
295 - (BOOL) _saveAttachments
298 NSEnumerator *allKeys;
301 NSDictionary *filenames;
306 request = [context request];
308 httpBody = [[request httpRequest] body];
309 filenames = [self _scanAttachmentFilenamesInRequest: httpBody];
311 co = [self clientObject];
312 allKeys = [[request formValueKeys] objectEnumerator];
313 key = [allKeys nextObject];
314 while (key && success)
316 if ([key hasPrefix: @"attachment"])
318 = (![co saveAttachment: (NSData *) [request formValueForKey: key]
319 withMetadata: [filenames objectForKey: key]]);
320 key = [allKeys nextObject];
326 - (BOOL) _saveFormInfo
333 co = [self clientObject];
338 if ([self _saveAttachments])
340 info = [self storeInfo];
341 [co setHeaders: info];
343 error = [co storeInfo];
346 [self errorWithFormat: @"failed to store draft: %@", error];
347 // TODO: improve error handling
354 // TODO: wrap content
359 - (id) failedToSaveFormResponse
361 // TODO: improve error handling
362 return [NSException exceptionWithHTTPStatus:500 /* server error */
363 reason:@"failed to store draft object on server!"];
366 /* attachment helper */
368 - (NSArray *) attachmentNames
372 if (attachmentNames != nil)
373 return attachmentNames;
375 a = [[self clientObject] fetchAttachmentNames];
376 a = [a sortedArrayUsingSelector: @selector (compare:)];
377 attachmentNames = [a copy];
379 return attachmentNames;
382 - (BOOL) hasAttachments
384 return [[self attachmentNames] count] > 0 ? YES : NO;
391 co = [self clientObject];
393 [self loadInfo: [co headers]];
394 [self setText: [co text]];
399 - (id <WOActionResults>) saveAction
403 if ([self _saveFormInfo])
405 result = [[self clientObject] save];
407 result = [self responseWith204];
410 result = [self failedToSaveFormResponse];
415 - (NSException *) validateForSend
419 if (![self hasOneOrMoreRecipients])
420 error = [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
421 reason: @"Please select a recipient!"];
422 else if ([[self subject] length] == 0)
423 error = [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
424 reason: @"Please set a subject!"];
431 - (id <WOActionResults>) sendAction
433 id <WOActionResults> result;
435 // TODO: need to validate whether we have a To etc
437 /* first, save form data */
438 result = [self validateForSend];
441 if ([self _saveFormInfo])
443 result = [[self clientObject] sendMail];
445 result = [self jsCloseWithRefreshMethod: @"refreshFolderByType(\"sent\")"];
448 result = [self failedToSaveFormResponse];
454 @end /* UIxMailEditor */