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 *)
284 [part headerForKey: @"content-disposition"];
285 mimeType = [(NGMimeType *)
286 [part headerForKey: @"content-type"] stringValue];
287 attachment = [NSDictionary dictionaryWithObjectsAndKeys:
288 [header filename], @"filename",
289 mimeType, @"mimetype", nil];
290 [filenames setObject: attachment forKey: [header name]];
296 - (BOOL) _saveAttachments
299 NSEnumerator *allKeys;
302 NSDictionary *filenames;
307 request = [context request];
309 httpBody = [[request httpRequest] body];
310 filenames = [self _scanAttachmentFilenamesInRequest: httpBody];
312 co = [self clientObject];
313 allKeys = [[request formValueKeys] objectEnumerator];
314 key = [allKeys nextObject];
315 while (key && success)
317 if ([key hasPrefix: @"attachment"])
319 = (![co saveAttachment: (NSData *) [request formValueForKey: key]
320 withMetadata: [filenames objectForKey: key]]);
321 key = [allKeys nextObject];
327 - (BOOL) _saveFormInfo
334 co = [self clientObject];
339 if ([self _saveAttachments])
341 info = [self storeInfo];
342 [co setHeaders: info];
344 error = [co storeInfo];
347 [self errorWithFormat: @"failed to store draft: %@", error];
348 // TODO: improve error handling
355 // TODO: wrap content
360 - (id) failedToSaveFormResponse
362 // TODO: improve error handling
363 return [NSException exceptionWithHTTPStatus:500 /* server error */
364 reason:@"failed to store draft object on server!"];
367 /* attachment helper */
369 - (NSArray *) attachmentNames
373 if (attachmentNames != nil)
374 return attachmentNames;
376 a = [[self clientObject] fetchAttachmentNames];
377 a = [a sortedArrayUsingSelector: @selector (compare:)];
378 attachmentNames = [a copy];
380 return attachmentNames;
383 - (BOOL) hasAttachments
385 return [[self attachmentNames] count] > 0 ? YES : NO;
392 co = [self clientObject];
394 [self loadInfo: [co headers]];
395 [self setText: [co text]];
400 - (id <WOActionResults>) saveAction
404 if ([self _saveFormInfo])
406 result = [[self clientObject] save];
408 result = [self responseWith204];
411 result = [self failedToSaveFormResponse];
416 - (NSException *) validateForSend
420 if (![self hasOneOrMoreRecipients])
421 error = [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
422 reason: @"Please select a recipient!"];
423 else if ([[self subject] length] == 0)
424 error = [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
425 reason: @"Please set a subject!"];
432 - (id <WOActionResults>) sendAction
434 id <WOActionResults> result;
436 // TODO: need to validate whether we have a To etc
438 /* first, save form data */
439 result = [self validateForSend];
442 if ([self _saveFormInfo])
444 result = [[self clientObject] sendMail];
446 result = [self jsCloseWithRefreshMethod: @"refreshFolderByType(\"sent\")"];
449 result = [self failedToSaveFormResponse];
455 @end /* UIxMailEditor */