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