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 #include <SOGoUI/UIxComponent.h>
27 An mail editor component which works on SOGoDraftObject's.
30 @class NSArray, NSString;
31 @class SOGoMailFolder;
33 @interface UIxMailEditor : UIxComponent
40 SOGoMailFolder *sentFolder;
45 #include <SOGo/SoObjects/Mailer/SOGoDraftObject.h>
46 #include <SOGo/SoObjects/Mailer/SOGoMailFolder.h>
47 #include <SOGo/SoObjects/Mailer/SOGoMailAccount.h>
48 #include <NGMail/NGMimeMessage.h>
49 #include <NGMail/NGMimeMessageGenerator.h>
52 @interface UIxComponent (Scheduler_Privates)
53 - (NSString *)emailForUser;
56 @implementation UIxMailEditor
58 static BOOL keepMailTmpFile = NO;
59 static BOOL showInternetMarker = NO;
60 static EOQualifier *internetDetectQualifier = nil;
61 static NSDictionary *internetMailHeaders = nil;
62 static NSArray *infoKeys = nil;
65 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
68 infoKeys = [[NSArray alloc] initWithObjects:
69 @"subject", @"text", @"to", @"cc", @"bcc",
73 keepMailTmpFile = [ud boolForKey:@"SOGoMailEditorKeepTmpFile"];
75 NSLog(@"WARNING: keeping mail files.");
77 /* Internet mail settings */
79 showInternetMarker = [ud boolForKey:@"SOGoShowInternetMarker"];
80 if (!showInternetMarker) {
81 NSLog(@"Note: visual Internet marker on mail editor disabled "
82 @"(SOGoShowInternetMarker)");
85 if ((s = [ud stringForKey:@"SOGoInternetDetectQualifier"]) != nil) {
86 internetDetectQualifier =
87 [[EOQualifier qualifierWithQualifierFormat:s] retain];
88 if (internetDetectQualifier == nil)
89 NSLog(@"ERROR: could not parse qualifier: '%@'", s);
91 if (internetDetectQualifier == nil)
92 NSLog(@"Note: no 'SOGoInternetDetectQualifier' configured.");
94 NSLog(@"Note: detect Internet access using: %@", internetDetectQualifier);
97 [[ud dictionaryForKey:@"SOGoInternetMailHeaders"] copy];
98 NSLog(@"Note: specified %d headers for mails send via the Internet.",
99 [internetMailHeaders count]);
103 [self->sentFolder release];
104 [self->text release];
105 [self->subject release];
114 - (void)setFrom:(NSString *)_ignore {
117 return [self emailForUser];
119 - (void)setReplyTo:(NSString *)_ignore {
121 - (NSString *)replyTo {
122 /* we are here for future extensibility */
126 - (void)setSubject:(NSString *)_value {
127 ASSIGNCOPY(self->subject, _value);
129 - (NSString *)subject {
130 return self->subject ? self->subject : @"";
133 - (void)setText:(NSString *)_value {
134 ASSIGNCOPY(self->text, _value);
137 return [self->text isNotNull] ? self->text : @"";
140 - (void)setTo:(NSArray *)_value {
141 ASSIGNCOPY(self->to, _value);
144 return [self->to isNotNull] ? self->to : [NSArray array];
147 - (void)setCc:(NSArray *)_value {
148 ASSIGNCOPY(self->cc, _value);
151 return [self->cc isNotNull] ? self->cc : [NSArray array];
154 - (void)setBcc:(NSArray *)_value {
155 ASSIGNCOPY(self->bcc, _value);
158 return [self->bcc isNotNull] ? self->bcc : [NSArray array];
163 - (NSString *)panelTitle {
164 return [self labelForKey:@"Compose Mail"];
167 /* detect webmail being accessed from the outside */
169 - (BOOL)isInternetRequest {
170 // TODO: make configurable! (eg allow specification of a qualifier)
173 rq = [[self context] request];
174 return [(id<EOQualifierEvaluation>)internetDetectQualifier
175 evaluateWithObject:[rq headers]];
178 - (BOOL)showInternetMarker {
179 if (!showInternetMarker)
181 return [self isInternetRequest];
186 - (void)loadInfo:(NSDictionary *)_info {
187 if (![_info isNotNull]) return;
188 [self debugWithFormat:@"loading info ..."];
189 [self takeValuesFromDictionary:_info];
191 - (NSDictionary *)storeInfo {
192 [self debugWithFormat:@"storing info ..."];
193 return [self valuesForKeys:infoKeys];
198 - (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c{
204 - (NSException *)patchFlagsInStore {
207 if the draft is a reply => [message markAnswered]
208 if the draft is a forward => [message addFlag:@"forwarded"]
210 This is hard, we would need to find the original message in Cyrus.
215 - (id)lookupSentFolder {
216 SOGoMailAccount *account;
217 SOGoMailFolder *folder;
219 if (self->sentFolder != nil)
222 account = [[self clientObject] mailAccountFolder];
223 if ([account isKindOfClass:[NSException class]]) return account;
225 folder = [account sentFolderInContext:[self context]];
226 if ([folder isKindOfClass:[NSException class]]) return folder;
227 return ((self->sentFolder = [folder retain]));
230 - (NSException *)storeMailInSentFolder:(NSString *)_path {
231 SOGoMailFolder *folder;
235 folder = [self lookupSentFolder];
236 if ([folder isKindOfClass:[NSException class]]) return (id)folder;
238 if ((data = [[NSData alloc] initWithContentsOfMappedFile:_path]) == nil) {
239 return [NSException exceptionWithHTTPStatus:500 /* server error */
240 reason:@"could not temporary draft file!"];
243 result = [folder postData:data flags:@"seen"];
244 [data release]; data = nil;
250 - (BOOL)_saveFormInfo {
253 if ((info = [self storeInfo]) != nil) {
256 if ((error = [[self clientObject] storeInfo:info]) != nil) {
257 [self errorWithFormat:@"failed to store draft: %@", error];
258 // TODO: improve error handling
263 // TODO: wrap content
267 - (id)failedToSaveFormResponse {
268 // TODO: improve error handling
269 return [NSException exceptionWithHTTPStatus:500 /* server error */
270 reason:@"failed to store draft object on server!"];
273 - (id)defaultAction {
274 return [self redirectToLocation:@"edit"];
278 [self logWithFormat:@"edit action, load content from: %@",
279 [self clientObject]];
281 [self loadInfo:[[self clientObject] fetchInfo]];
286 return [self _saveFormInfo] ? self : [self failedToSaveFormResponse];
294 // TODO: need to validate whether we have a To etc
296 /* first, save form data */
298 if (![self _saveFormInfo])
299 return [self failedToSaveFormResponse];
301 /* setup some extra headers if required */
303 h = [self isInternetRequest] ? internetMailHeaders : nil;
305 /* save mail to file (so that we can upload the mail to Cyrus) */
306 // TODO: all this could be handled by the SOGoDraftObject?
308 mailPath = [[self clientObject] saveMimeMessageToTemporaryFileWithHeaders:h];
310 /* then, send mail */
312 if ((error = [[self clientObject] sendMimeMessageAtPath:mailPath]) != nil) {
313 // TODO: improve error handling
314 [[NSFileManager defaultManager] removeFileAtPath:mailPath handler:nil];
318 /* patch flags in store for replies etc */
320 if ((error = [self patchFlagsInStore]) != nil)
323 /* finally store in Sent */
325 if ((error = [self storeMailInSentFolder:mailPath]) != nil)
328 /* delete temporary mail file */
331 [self warnWithFormat:@"keeping mail file: '%@'", mailPath];
333 [[NSFileManager defaultManager] removeFileAtPath:mailPath handler:nil];
338 if ((error = [[self clientObject] delete]) != nil)
341 // if everything is ok, close the window (send a JS closing the Window)
342 return [self pageWithName:@"UIxMailWindowCloser"];
348 if ((error = [[self clientObject] delete]) != nil)
354 @end /* UIxMailEditor */