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 <NGObjWeb/WODirectAction.h>
27 This action implements the backend for the various buttons which invoke the
28 mail editor. The mail editor itself only works on a SOGoDraftObject which
29 needs to be created in advance.
32 @class SOGoDraftObject;
34 @interface UIxMailEditorAction : WODirectAction
36 SOGoDraftObject *newDraft;
41 #include <SOGo/SoObjects/Mailer/SOGoDraftsFolder.h>
42 #include <SOGo/SoObjects/Mailer/SOGoDraftObject.h>
43 #include <SOGo/SoObjects/Mailer/SOGoMailAccount.h>
44 #include <SOGo/SoObjects/Mailer/SOGoMailObject.h>
47 @implementation UIxMailEditorAction
50 [self->newDraft release];
57 [self->newDraft release]; self->newDraft = nil;
62 - (SOGoDraftsFolder *)draftsFolder {
64 Note: we cannot use acquisition to find the nearest drafts folder, because
65 the IMAP4 server might contains an own Drafts folder.
67 SOGoDraftsFolder *drafts;
70 client = [self clientObject];
71 drafts = [[client mailAccountFolder]
72 lookupName:@"Drafts" inContext:[self context] acquire:NO];
78 - (id)didNotFindDraftsError {
79 // TODO: make a nice error page
80 return [@"did not find drafts folder in object: "
81 stringByAppendingString:[[self clientObject] description]];
83 - (id)couldNotCreateDraftError:(SOGoDraftsFolder *)_draftsFolder {
84 return [@"could not create a new draft in folder: "
85 stringByAppendingString:[_draftsFolder description]];
87 - (id)didNotFindMailError {
88 return [NSException exceptionWithHTTPStatus:404 /* Not Found */
89 reason:@"Did not find mail for operation!"];
95 SOGoDraftsFolder *drafts;
99 drafts = [self draftsFolder];
100 if (![drafts isNotNull])
101 return [self didNotFindDraftsError];
102 if ([drafts isKindOfClass:[NSException class]])
105 url = [drafts newObjectBaseURLInContext:[self context]];
106 if (![url isNotNull])
107 return [self couldNotCreateDraftError:drafts];
109 if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"];
110 url = [url stringByAppendingString:@"edit"];
113 [self logWithFormat:@"compose on %@: %@", drafts, url];
115 r = [[self context] response];
116 [r setStatus:302 /* moved */];
117 [r setHeader:url forKey:@"location"];
122 /* creating new draft object */
124 - (id)newDraftObject {
125 SOGoDraftsFolder *drafts;
127 drafts = [self draftsFolder];
128 if (![drafts isNotNull])
129 return [self didNotFindDraftsError];
130 if ([drafts isKindOfClass:[NSException class]])
133 return [drafts newObjectInContext:[self context]];
136 - (NSException *)_setupNewDraft {
137 SOGoDraftObject *tmp;
139 /* create draft object */
141 if ([(tmp = [self newDraftObject]) isKindOfClass:[NSException class]])
142 return (NSException *)tmp;
143 if (![tmp isNotNull]) { /* Note: should never happen? */
144 [self logWithFormat:@"WARNING: got no new draft object and no error!"];
145 return [self didNotFindDraftsError]; // TODO: not exact
148 ASSIGN(self->newDraft, tmp);
149 [self logWithFormat:@"NEW DRAFT: %@", self->newDraft];
154 - (WOResponse *)redirectToEditNewDraft {
158 if (![self->newDraft isNotNull]) {
159 [self logWithFormat:@"ERROR(%s): missing new draft (already -reset?)",
160 __PRETTY_FUNCTION__];
164 url = [self->newDraft baseURLInContext:[self context]];
165 if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"];
166 url = [url stringByAppendingString:@"edit"];
169 [self logWithFormat:@"compose on %@", url];
171 r = [[self context] response];
172 [r setStatus:302 /* moved */];
173 [r setHeader:url forKey:@"location"];
178 /* response actions */
180 - (id)replyToAll:(BOOL)_replyToAll {
184 /* ensure mail exists and is filled */
186 // TODO: we could transport the body structure in a hidden field of the mail
187 // viewer to avoid refetching the core-info?
188 tmp = [[self clientObject] fetchCoreInfos];
189 if ([tmp isKindOfClass:[NSException class]])
191 if (![tmp isNotNull])
192 return [self didNotFindMailError];
196 if ((error = [self _setupNewDraft]) != nil)
200 [self logWithFormat:@"CORE: %@", [[self clientObject] fetchCoreInfos]];
203 return [NSException exceptionWithHTTPStatus:501 /* Not Implemented */
204 reason:@"Sorry, reply is not yet implemented!"];
208 return [self replyToAll:NO];
210 - (id)replyallAction {
211 return [self replyToAll:YES];
214 - (NSString *)getAttachmentNameForSubject:(NSString *)_subject {
215 /* SOGoDraftObject disallows some strings - anything else required? */
216 static NSString *sescape[] = {
217 @"/", @"..", @"~", @"\"", @"'", @" ", @".", nil
219 static int maxFilenameLength = 64;
223 if (![_subject isNotNull] || [_subject length] == 0)
227 if ([s length] > maxFilenameLength)
228 s = [s substringToIndex:maxFilenameLength];
230 for (i = 0; sescape[i] != nil; i++)
231 s = [s stringByReplacingString:sescape[i] withString:@"_"];
233 return [s stringByAppendingString:@".mail"];
236 - (NSString *)forwardSubject:(NSString *)_subject {
237 if (![_subject isNotNull] || [_subject length] == 0)
240 /* Note: this is how Thunderbird 1.0 creates the subject */
241 _subject = [@"[Fwd: " stringByAppendingString:_subject];
242 _subject = [_subject stringByAppendingString:@"]"];
246 - (id)forwardAction {
254 if ((content = [[self clientObject] content]) == nil)
255 return [self didNotFindMailError];
256 if ([content isKindOfClass:[NSException class]])
261 if ((error = [self _setupNewDraft]) != nil)
264 /* set subject (do we need to set anything else?) */
266 info = [NSDictionary dictionaryWithObjectsAndKeys:
267 [self forwardSubject:[[self clientObject] subject]],
270 if ((error = [self->newDraft storeInfo:info]) != nil)
275 // TODO: use subject for filename?
276 error = [self->newDraft saveAttachment:content withName:@"forward.mail"];
280 // TODO: we might want to pass the original URL to the editor for a final
281 // redirect back to the message?
282 result = [self redirectToEditNewDraft];
287 @end /* UIxMailEditorAction */