]> err.no Git - scalable-opengroupware.org/blob - SOGo/UI/Mailer/UIxMailEditorAction.m
6a88bdd58290b4be0378e1d0be55921e47f8058d
[scalable-opengroupware.org] / SOGo / UI / Mailer / UIxMailEditorAction.m
1 /*
2   Copyright (C) 2004-2005 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21
22 #include <NGObjWeb/WODirectAction.h>
23
24 /*
25   UIxMailEditorAction
26   
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.
30 */
31
32 @class SOGoDraftObject;
33
34 @interface UIxMailEditorAction : WODirectAction
35 {
36   SOGoDraftObject *newDraft;
37 }
38
39 @end
40
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>
45 #include "common.h"
46
47 @implementation UIxMailEditorAction
48
49 - (void)dealloc {
50   [self->newDraft release];
51   [super dealloc];
52 }
53
54 /* caches */
55
56 - (void)reset {
57   [self->newDraft release]; self->newDraft = nil;
58 }
59
60 /* lookups */
61
62 - (SOGoDraftsFolder *)draftsFolder {
63   /* 
64      Note: we cannot use acquisition to find the nearest drafts folder, because
65            the IMAP4 server might contains an own Drafts folder.
66   */
67   SOGoDraftsFolder *drafts;
68   id client;
69   
70   client = [self clientObject];
71   drafts = [[client mailAccountFolder]
72                     lookupName:@"Drafts" inContext:[self context] acquire:NO];
73   return drafts;
74 }
75
76 /* errors */
77
78 - (id)didNotFindDraftsError {
79   // TODO: make a nice error page
80   return [@"did not find drafts folder in object: "
81            stringByAppendingString:[[self clientObject] description]];
82 }
83 - (id)couldNotCreateDraftError:(SOGoDraftsFolder *)_draftsFolder {
84   return [@"could not create a new draft in folder: "
85            stringByAppendingString:[_draftsFolder description]];
86 }
87 - (id)didNotFindMailError {
88   return [NSException exceptionWithHTTPStatus:404 /* Not Found */
89                       reason:@"Did not find mail for operation!"];
90 }
91
92 /* compose */
93
94 - (id)composeAction {
95   SOGoDraftsFolder *drafts;
96   WOResponse *r;
97   NSString   *url;
98   
99   drafts = [self draftsFolder];
100   if (![drafts isNotNull])
101     return [self didNotFindDraftsError];
102   if ([drafts isKindOfClass:[NSException class]])
103     return drafts;
104   
105   url = [drafts newObjectBaseURLInContext:[self context]];
106   if (![url isNotNull])
107     return [self couldNotCreateDraftError:drafts];
108   
109   if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"];
110   url = [url stringByAppendingString:@"edit"];
111   
112   // TODO: debug log
113   [self logWithFormat:@"compose on %@: %@", drafts, url];
114   
115   r = [[self context] response];
116   [r setStatus:302 /* moved */];
117   [r setHeader:url forKey:@"location"];
118   [self reset];
119   return r;
120 }
121
122 /* creating new draft object */
123
124 - (id)newDraftObject {
125   SOGoDraftsFolder *drafts;
126   
127   drafts = [self draftsFolder];
128   if (![drafts isNotNull])
129     return [self didNotFindDraftsError];
130   if ([drafts isKindOfClass:[NSException class]])
131     return drafts;
132
133   return [drafts newObjectInContext:[self context]];
134 }
135
136 - (NSException *)_setupNewDraft {
137   SOGoDraftObject *tmp;
138   
139   /* create draft object */
140   
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
146   }
147   
148   ASSIGN(self->newDraft, tmp);
149   [self logWithFormat:@"NEW DRAFT: %@", self->newDraft];
150   
151   return nil;
152 }
153
154 - (WOResponse *)redirectToEditNewDraft {
155   WOResponse *r;
156   NSString   *url;
157   
158   if (![self->newDraft isNotNull]) {
159     [self logWithFormat:@"ERROR(%s): missing new draft (already -reset?)",
160             __PRETTY_FUNCTION__];
161     return nil;
162   }
163   
164   url = [self->newDraft baseURLInContext:[self context]];
165   if (![url hasSuffix:@"/"]) url = [url stringByAppendingString:@"/"];
166   url = [url stringByAppendingString:@"edit"];
167   
168   // TODO: debug log
169   [self logWithFormat:@"compose on %@", url];
170   
171   r = [[self context] response];
172   [r setStatus:302 /* moved */];
173   [r setHeader:url forKey:@"location"];
174   [self reset];
175   return r;
176 }
177
178 /* response actions */
179
180 - (id)replyToAll:(BOOL)_replyToAll {
181   NSException *error;
182   id tmp;
183   
184   /* ensure mail exists and is filled */
185   
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]])
190     return tmp;
191   if (![tmp isNotNull])
192     return [self didNotFindMailError];
193
194   /* setup draft */
195   
196   if ((error = [self _setupNewDraft]) != nil)
197     return error;
198   
199 #if 0
200   [self logWithFormat:@"CORE: %@", [[self clientObject] fetchCoreInfos]];
201 #endif
202   [self reset];
203   return [NSException exceptionWithHTTPStatus:501 /* Not Implemented */
204                       reason:@"Sorry, reply is not yet implemented!"];
205 }
206
207 - (id)replyAction {
208   return [self replyToAll:NO];
209 }
210 - (id)replyallAction {
211   return [self replyToAll:YES];
212 }
213
214 - (NSString *)getAttachmentNameForSubject:(NSString *)_subject {
215   /* SOGoDraftObject disallows some strings - anything else required? */
216   static NSString *sescape[] = { 
217     @"/", @"..", @"~", @"\"", @"'", @" ", @".", nil 
218   };
219   static int maxFilenameLength = 64;
220   NSString *s;
221   unsigned i;
222   
223   if (![_subject isNotNull] || [_subject length] == 0)
224     return _subject;
225   s = _subject;
226   
227   if ([s length] > maxFilenameLength)
228     s = [s substringToIndex:maxFilenameLength];
229   
230   for (i = 0; sescape[i] != nil; i++)
231     s = [s stringByReplacingString:sescape[i] withString:@"_"];
232   
233   return [s stringByAppendingString:@".mail"];
234 }
235
236 - (NSString *)forwardSubject:(NSString *)_subject {
237   if (![_subject isNotNull] || [_subject length] == 0)
238     return _subject;
239   
240   /* Note: this is how Thunderbird 1.0 creates the subject */
241   _subject = [@"[Fwd: " stringByAppendingString:_subject];
242   _subject = [_subject stringByAppendingString:@"]"];
243   return _subject;
244 }
245
246 - (id)forwardAction {
247   NSException  *error;
248   NSData       *content;
249   NSDictionary *info;
250   id result;
251
252   /* fetch message */
253   
254   if ((content = [[self clientObject] content]) == nil)
255     return [self didNotFindMailError];
256   if ([content isKindOfClass:[NSException class]])
257     return content;
258   
259   /* setup draft */
260   
261   if ((error = [self _setupNewDraft]) != nil)
262     return error;
263   
264   /* set subject (do we need to set anything else?) */
265
266   info = [NSDictionary dictionaryWithObjectsAndKeys:
267                          [self forwardSubject:[[self clientObject] subject]],
268                          @"subject",
269                        nil];
270   if ((error = [self->newDraft storeInfo:info]) != nil)
271     return error;
272   
273   /* attach message */
274   
275   // TODO: use subject for filename?
276   error = [self->newDraft saveAttachment:content withName:@"forward.mail"];
277   if (error != nil)
278     return error;
279   
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];
283   [self reset];
284   return result;
285 }
286
287 @end /* UIxMailEditorAction */