]> err.no Git - scalable-opengroupware.org/blob - UI/MailerUI/UIxMailView.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1132 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / UI / MailerUI / UIxMailView.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 #import <Foundation/NSException.h>
23 #import <Foundation/NSUserDefaults.h>
24 #import <NGObjWeb/NSException+HTTP.h>
25 #import <NGObjWeb/WORequest.h>
26 #import <NGObjWeb/WOResponse.h>
27 #import <NGExtensions/NSException+misc.h>
28 #import <NGExtensions/NSString+misc.h>
29 #import <NGImap4/NGImap4Envelope.h>
30 #import <NGImap4/NGImap4EnvelopeAddress.h>
31 #import <SoObjects/Mailer/SOGoMailObject.h>
32 #import <SoObjects/Mailer/SOGoMailAccount.h>
33 #import <SoObjects/Mailer/SOGoMailFolder.h>
34 #import <SOGoUI/UIxComponent.h>
35 #import <MailPartViewers/UIxMailRenderingContext.h> // cyclic
36
37 #import "WOContext+UIxMailer.h"
38
39 @interface UIxMailView : UIxComponent
40 {
41   id currentAddress;
42 }
43
44 - (BOOL)isDeletableClientObject;
45
46 @end
47
48 @implementation UIxMailView
49
50 static NSString *mailETag = nil;
51
52 + (int)version {
53   return [super version] + 0 /* v2 */;
54 }
55
56 + (void)initialize {
57   NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
58   
59   NSAssert2([super version] == 2,
60             @"invalid superclass (%@) version %i !",
61             NSStringFromClass([self superclass]), [super version]);
62   
63   if ([ud boolForKey:@"SOGoDontUseETagsForMailViewer"]) {
64     NSLog(@"Note: usage of constant etag for mailer viewer is disabled.");
65   }
66   else {
67     mailETag = [[NSString alloc] initWithFormat:@"\"imap4url_%d_%d_%03d\"",
68                                  UIX_MAILER_MAJOR_VERSION,
69                                  UIX_MAILER_MINOR_VERSION,
70                                  UIX_MAILER_SUBMINOR_VERSION];
71     NSLog(@"Note: using constant etag for mail viewer: '%@'", mailETag);
72   }
73 }
74
75 - (void)dealloc {
76   [super dealloc];
77 }
78
79 /* accessors */
80
81 - (void) setCurrentAddress: (id) _addr
82 {
83   currentAddress = _addr;
84 }
85
86 - (id) currentAddress
87 {
88   return currentAddress;
89 }
90
91 - (NSString *) objectTitle
92 {
93   return [[self clientObject] subject];
94 }
95
96 - (NSString *) panelTitle
97 {
98   return [NSString stringWithFormat: @"%@: %@",
99                    [self labelForKey: @"View Mail"],
100                    [self objectTitle]];
101 }
102
103 /* links (DUP to UIxMailPartViewer!) */
104
105 - (NSString *) linkToEnvelopeAddress: (NGImap4EnvelopeAddress *) _address
106 {
107   // TODO: make some web-link, eg open a new compose panel?
108   return [NSString stringWithFormat: @"mailto: %@", [_address baseEMail]];
109 }
110
111 - (NSString *) currentAddressLink
112 {
113   return [self linkToEnvelopeAddress:[self currentAddress]];
114 }
115
116 /* fetching */
117
118 - (id) message
119 {
120   return [[self clientObject] fetchCoreInfos];
121 }
122
123 - (BOOL) hasCC
124 {
125   return [[[self clientObject] ccEnvelopeAddresses] count] > 0 ? YES : NO;
126 }
127
128 /* viewers */
129
130 - (id) contentViewerComponent
131 {
132   // TODO: I would prefer to flatten the body structure prior rendering,
133   //       using some delegate to decide which parts to select for alternative.
134   id info;
135   
136   info = [[self clientObject] bodyStructure];
137
138   return [[context mailRenderingContext] viewerForBodyInfo:info];
139 }
140
141 /* actions */
142
143 - (id) defaultAction
144 {
145   /* check etag to see whether we really must rerender */
146   if (mailETag != nil ) {
147     /*
148       Note: There is one thing which *can* change for an existing message,
149             those are the IMAP4 flags (and annotations, which we do not use).
150             Since we don't render the flags, it should be OK, if this changes
151             we must embed the flagging into the etag.
152     */
153     NSString *s;
154     
155     if ((s = [[context request] headerForKey:@"if-none-match"])) {
156       if ([s rangeOfString:mailETag].length > 0) { /* not perfectly correct */
157         /* client already has the proper entity */
158         // [self logWithFormat:@"MATCH: %@ (tag %@)", s, mailETag];
159         
160         if (![[self clientObject] doesMailExist]) {
161           return [NSException exceptionWithHTTPStatus:404 /* Not Found */
162                               reason:@"message got deleted"];
163         }
164         
165         [[context response] setStatus:304 /* Not Modified */];
166         return [context response];
167       }
168     }
169   }
170   
171   if ([self message] == nil) {
172     // TODO: redirect to proper error
173     return [NSException exceptionWithHTTPStatus:404 /* Not Found */
174                         reason:@"did not find specified message!"];
175   }
176   
177   return self;
178 }
179
180 - (BOOL) isDeletableClientObject
181 {
182   return [[self clientObject] respondsToSelector: @selector (delete)];
183 }
184
185 - (BOOL) isInlineViewer
186 {
187   return NO;
188 }
189
190 - (id) redirectToParentFolder
191 {
192   id url;
193   
194   url = [[[self clientObject] container] baseURLInContext: context];
195
196   return [self redirectToLocation: url];
197 }
198
199 - (id) deleteAction
200 {
201   NSException *ex;
202   
203   if (![self isDeletableClientObject]) {
204     return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
205                         reason:@"method cannot be invoked on "
206                                @"the specified object"];
207   }
208   
209   if ([self isInvokedBySafeMethod]) {
210     // TODO: fix UI to use POST for unsafe actions
211     [self logWithFormat:@"WARNING: method is invoked using safe HTTP method!"];
212   }
213   
214   if ((ex = [[self clientObject] delete]) != nil) {
215     id url;
216     
217     url = [[ex reason] stringByEscapingURL];
218     url = [@"view?error=" stringByAppendingString:url];
219     return [self redirectToLocation:url];
220     //return ex;
221   }
222   
223   if (![self isInlineViewer]) {
224     // if everything is ok, close the window (send a JS closing the Window)
225     id page;
226     
227     page = [self pageWithName:@"UIxMailWindowCloser"];
228     [page takeValue:@"YES" forKey:@"refreshOpener"];
229     return page;
230   }
231   
232   return [self redirectToParentFolder];
233 }
234
235 - (id) trashAction
236 {
237   NSException *ex;
238   
239   if ([self isInvokedBySafeMethod]) {
240     // TODO: fix UI to use POST for unsafe actions
241     [self logWithFormat:@"WARNING: method is invoked using safe HTTP method!"];
242   }
243   
244   if ((ex = [[self clientObject] trashInContext:context]) != nil) {
245     id url;
246     
247     if ([[[context request] formValueForKey:@"jsonly"] boolValue])
248       /* called using XMLHttpRequest */
249       return ex;
250     
251     url = [[ex reason] stringByEscapingURL];
252     url = [@"view?error=" stringByAppendingString:url];
253     return [self redirectToLocation:url];
254   }
255
256   if ([[[context request] formValueForKey:@"jsonly"] boolValue]) {
257     /* called using XMLHttpRequest */
258     [[context response] setStatus:200 /* OK */];
259     return [context response];
260   }
261   
262   if (![self isInlineViewer]) {
263     // if everything is ok, close the window (send a JS closing the Window)
264     id page;
265     
266     page = [self pageWithName:@"UIxMailWindowCloser"];
267     [page takeValue:@"YES" forKey:@"refreshOpener"];
268     return page;
269   }
270   
271   return [self redirectToParentFolder];
272 }
273
274 - (id <WOActionResults>) moveAction
275 {
276   id <WOActionResults> result;
277   NSString *destinationFolder;
278   id url;
279
280   if ([self isInvokedBySafeMethod]) {
281     // TODO: fix UI to use POST for unsafe actions
282     [self logWithFormat:@"WARNING: method is invoked using safe HTTP method!"];
283   }
284
285   destinationFolder = [self queryParameterForKey: @"tofolder"];
286   if ([destinationFolder length] > 0)
287     {
288       result = [[self clientObject] moveToFolderNamed: destinationFolder
289                                     inContext: context];
290       if (result)
291         {
292           if (![[[context request] formValueForKey:@"jsonly"] boolValue])
293             {
294               url = [NSString stringWithFormat: @"view?error=%@",
295                               [[result reason] stringByEscapingURL]];
296               result = [self redirectToLocation: url];
297             }
298         }
299       else
300         {
301           result = [context response];
302           [result setStatus: 200];
303         }
304     }
305   else
306     result = [NSException exceptionWithHTTPStatus:500 /* Server Error */
307                           reason: @"No destination folder given"];
308
309   return result;
310 }
311
312 /* generating response */
313
314 - (void) appendToResponse: (WOResponse *) _response
315                 inContext: (WOContext *) _ctx
316 {
317   UIxMailRenderingContext *mctx;
318
319   if (mailETag != nil)
320     [[_ctx response] setHeader:mailETag forKey:@"etag"];
321
322   mctx = [[UIxMailRenderingContext alloc] initWithViewer: self
323                                           context: _ctx];
324
325   [_ctx pushMailRenderingContext: mctx];
326   [mctx release];
327
328   [super appendToResponse: _response inContext: _ctx];
329   
330   [[_ctx popMailRenderingContext] reset];
331 }
332
333 @end /* UIxMailView */