]> err.no Git - scalable-opengroupware.org/blob - SOGo/UI/Mailer/UIxMailView.m
partially implemented mail delete #1212
[scalable-opengroupware.org] / SOGo / UI / Mailer / UIxMailView.m
1 /*
2   Copyright (C) 2004 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 // $Id$
22
23 #include <SOGoUI/UIxComponent.h>
24
25 @interface UIxMailView : UIxComponent
26 {
27   id currentAddress;
28 }
29
30 - (BOOL)isDeletableClientObject;
31
32 @end
33
34 #include "UIxMailRenderingContext.h"
35 #include "WOContext+UIxMailer.h"
36 #include <SoObjects/Mailer/SOGoMailObject.h>
37 #include <NGImap4/NGImap4Envelope.h>
38 #include "common.h"
39
40 @implementation UIxMailView
41
42 - (void)dealloc {
43   [self->currentAddress release];
44   [super dealloc];
45 }
46
47 /* notifications */
48
49 - (void)sleep {
50   [self->currentAddress release]; self->currentAddress = nil;
51   [super sleep];
52 }
53
54 /* accessors */
55
56 - (void)setCurrentAddress:(id)_addr {
57   ASSIGN(self->currentAddress, _addr);
58 }
59 - (id)currentAddress {
60   return self->currentAddress;
61 }
62
63 /* fetching */
64
65 - (id)message {
66   return [[self clientObject] fetchCoreInfos];
67 }
68
69 - (BOOL)hasCC {
70   return [[[self clientObject] ccEnvelopeAddresses] count] > 0 ? YES : NO;
71 }
72
73 /* process body structure */
74
75 - (BOOL)shouldFetchPartOfType:(NSString *)_type subtype:(NSString *)_subtype {
76   _type    = [_type    lowercaseString];
77   _subtype = [_subtype lowercaseString];
78   
79   if ([_type isEqualToString:@"text"])
80     return [_subtype isEqualToString:@"plain"];
81   return NO;
82 }
83
84 - (void)addRequiredKeysOfStructure:(id)_info path:(NSString *)_p
85   toArray:(NSMutableArray *)_keys
86 {
87   NSArray  *parts;
88   unsigned i, count;
89   BOOL fetchPart;
90   
91   fetchPart = [self shouldFetchPartOfType:[_info valueForKey:@"type"]
92                     subtype:[_info valueForKey:@"subtype"]];
93   if (fetchPart) {
94     NSString *k;
95     
96     if ([_p length] > 0) {
97       k = [[@"body[" stringByAppendingString:_p] stringByAppendingString:@"]"];
98     }
99     else {
100       /*
101         for some reason we need to add ".TEXT" for plain text stuff on root
102         entities?
103         TODO: check with HTML
104       */
105       k = @"body[text]";
106     }
107     [_keys addObject:k];
108   }
109   
110   /* recurse */
111   
112   parts = [_info objectForKey:@"parts"];
113   for (i = 0, count = [parts count]; i < count; i++) {
114     NSString *sp;
115     id childInfo;
116     
117     sp = [_p length] > 0
118       ? [_p stringByAppendingFormat:@".%d", i + 1]
119       : [NSString stringWithFormat:@"%d", i + 1];
120     
121     childInfo = [parts objectAtIndex:i];
122     
123     [self addRequiredKeysOfStructure:childInfo path:sp toArray:_keys];
124   }
125 }
126
127 - (NSArray *)contentFetchKeys {
128   NSMutableArray *ma;
129   
130   ma = [NSMutableArray arrayWithCapacity:4];
131   [self addRequiredKeysOfStructure:[[self clientObject] bodyStructure]
132         path:@"" toArray:ma];
133   return ma;
134 }
135
136 - (NSDictionary *)fetchFlatContents {
137   NSMutableDictionary *flatContents;
138   unsigned i, count;
139   NSArray  *keys;
140   id result;
141   
142   keys   = [self contentFetchKeys];
143   [self debugWithFormat:@"fetch keys: %@", keys];
144   
145   result = [[self clientObject] fetchParts:keys];
146   result = [result valueForKey:@"RawResponse"]; // hackish
147   result = [result objectForKey:@"fetch"]; // Note: -valueForKey: doesn't work!
148   
149   count        = [keys count];
150   flatContents = [NSMutableDictionary dictionaryWithCapacity:count];
151   for (i = 0; i < count; i++) {
152     NSString *key;
153     NSData   *data;
154     
155     key  = [keys objectAtIndex:i];
156     data = [[result objectForKey:key] objectForKey:@"data"];
157     
158     if (![data isNotNull]) {
159       [self debugWithFormat:@"got no data fork key: %@", key];
160       continue;
161     }
162
163     if ([key isEqualToString:@"body[text]"])
164       key = @""; // see key collector
165     else if ([key hasPrefix:@"body["]) {
166       NSRange r;
167       
168       key = [key substringFromIndex:5];
169       r   = [key rangeOfString:@"]"];
170       if (r.length > 0)
171         key = [key substringToIndex:r.location];
172     }
173     [flatContents setObject:data forKey:key];
174   }
175   return flatContents;
176 }
177
178 /* viewers */
179
180 - (id)contentViewerComponent {
181   id info;
182   
183   info = [[self clientObject] bodyStructure];
184   return [[[self context] mailRenderingContext] viewerForBodyInfo:info];
185 }
186
187 /* actions */
188
189 - (id)defaultAction {
190   if ([self message] == nil) {
191     return [NSException exceptionWithHTTPStatus:404 /* Not Found */
192                         reason:@"did not find specified message!"];
193   }
194 #if 0
195   [self logWithFormat:@"FETCH BODY PARTS: %@", [self contentFetchKeys]];
196   [self logWithFormat:@"CORE: %@", [self fetchFlatContents]];
197 #endif
198   return self;
199 }
200
201 - (BOOL)isDeletableClientObject {
202   return [[self clientObject] respondsToSelector:@selector(delete)];
203 }
204 - (BOOL)isInlineViewer {
205   return NO;
206 }
207
208 - (id)deleteAction {
209   NSException *ex;
210   
211   if (![self isDeletableClientObject]) {
212     return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
213                         reason:@"method cannot be invoked on "
214                                @"the specified object"];
215   }
216   
217   if ((ex = [[self clientObject] delete]) != nil) {
218     // TODO: improve error handling
219     [self debugWithFormat:@"failed to delete: %@", ex];
220     return ex;
221   }
222   
223   if (![self isInlineViewer]) {
224     // if everything is ok, close the window (send a JS closing the Window)
225     return [self pageWithName:@"UIxMailWindowCloser"];
226   }
227   else {
228     id url;
229
230     url = [[[self clientObject] container] baseURLInContext:[self context]];
231     return [self redirectToLocation:url];
232   }
233 }
234
235 - (id)getMailAction {
236   // TODO: we might want to flush the caches?
237   return [self redirectToLocation:@"view"];
238 }
239
240 /* generating response */
241
242 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
243   UIxMailRenderingContext *mctx;
244
245   mctx = [[UIxMailRenderingContext alloc] initWithViewer:self context:_ctx];
246   [_ctx pushMailRenderingContext:mctx];
247   [mctx release];
248   
249   [super appendToResponse:_response inContext:_ctx];
250   
251   [[_ctx popMailRenderingContext] reset];
252 }
253
254 @end /* UIxMailView */