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