]> err.no Git - scalable-opengroupware.org/blob - SOGo/SoObjects/Mailer/SOGoMailAccount.m
05fdcb478e37a9ac9c8ba359cf53bb19a034a0b2
[scalable-opengroupware.org] / SOGo / SoObjects / Mailer / SOGoMailAccount.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 "SOGoMailAccount.h"
23 #include "SOGoMailFolder.h"
24 #include "SOGoMailManager.h"
25 #include "SOGoDraftsFolder.h"
26 #include <NGObjWeb/SoHTTPAuthenticator.h>
27 #include "common.h"
28
29 @implementation SOGoMailAccount
30
31 static NSArray  *rootFolderNames  = nil;
32 static NSString *inboxFolderName  = @"INBOX";
33 static NSString *draftsFolderName = @"Drafts";
34 static NSString *sieveFolderName  = @"Filters";
35 static BOOL     useAltNamespace   = NO;
36
37 + (void)initialize {
38   NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
39   
40   useAltNamespace = [ud boolForKey:@"SOGoSpecialFoldersInRoot"];
41   
42   if ([ud boolForKey:@"SOGoEnableSieveFolder"]) {
43     rootFolderNames = [[NSArray alloc] initWithObjects:
44                                         draftsFolderName, 
45                                         sieveFolderName, 
46                                       nil];
47   }
48   else {
49     rootFolderNames = [[NSArray alloc] initWithObjects:
50                                         draftsFolderName, 
51                                       nil];
52   }
53 }
54
55 /* listing the available folders */
56
57 - (NSArray *)toManyRelationshipKeys {
58   NSArray *a, *b;
59
60   a = rootFolderNames;
61   
62   b = [[self mailManager] subfoldersForURL:[self imap4URL] 
63                           password:[self imap4Password]];
64   return [b count] > 0 ? [b arrayByAddingObjectsFromArray:a] : a;
65 }
66
67 /* hierarchy */
68
69 - (SOGoMailAccount *)mailAccountFolder {
70   return self;
71 }
72
73 - (NSArray *)allFolderPathes {
74   NSArray *pathes;
75   
76   pathes = [[self mailManager] allFoldersForURL:[self imap4URL] 
77                                password:[self imap4Password]];
78   pathes = [pathes sortedArrayUsingSelector:@selector(compare:)];
79   return pathes;
80 }
81
82 /* IMAP4 */
83
84 - (BOOL)useSSL {
85   return NO;
86 }
87
88 - (NSString *)imap4LoginFromHTTP {
89   WORequest *rq;
90   NSString  *s;
91   NSArray   *creds;
92   
93   rq = [[(WOApplication *)[WOApplication application] context] request];
94   
95   s = [rq headerForKey:@"x-webobjects-remote-user"];
96   if ([s length] > 0)
97     return s;
98   
99   if ((s = [rq headerForKey:@"authorization"]) == nil) {
100     /* no basic auth */
101     return nil;
102   }
103   
104   creds = [SoHTTPAuthenticator parseCredentials:s];
105   if ([creds count] < 2)
106     /* somehow invalid */
107     return nil;
108   
109   return [creds objectAtIndex:0]; /* the user */
110 }
111
112 - (NSURL *)imap4URL {
113   /* imap://agenortest@mail.opengroupware.org/INBOX/withsubdirs/subdir1 */
114   NSString *s;
115   NSRange  r;
116   
117   if (self->imap4URL != nil)
118     return self->imap4URL;
119   
120   s = [self nameInContainer];
121   r = [s rangeOfString:@"@"];
122   if (r.length == 0) {
123     NSString *u;
124     
125     u = [self imap4LoginFromHTTP];
126     if ([u length] == 0) {
127       [self errorWithFormat:@"missing login in account folder name: %@", s];
128       return nil;
129     }
130     s = [[u stringByAppendingString:@"@"] stringByAppendingString:s];
131   }
132   if ([s hasSuffix:@":80"]) { // HACK
133     [self logWithFormat:@"WARNING: incorrect value for IMAP4 URL: '%@'", s];
134     s = [s substringToIndex:([s length] - 3)];
135   }
136   
137   s = [([self useSSL] ? @"imaps://" : @"imap://") stringByAppendingString:s];
138   s = [s stringByAppendingString:@"/"];
139   
140   self->imap4URL = [[NSURL alloc] initWithString:s];
141   return self->imap4URL;
142 }
143
144 - (NSString *)imap4Login {
145   return [[self imap4URL] user];
146 }
147
148 /* name lookup */
149
150 - (id)lookupFolder:(NSString *)_key ofClassNamed:(NSString *)_cn
151   inContext:(id)_cx
152 {
153   Class clazz;
154
155   if ((clazz = NSClassFromString(_cn)) == Nil) {
156     [self logWithFormat:@"ERROR: did not find class '%@' for key: '%@'", 
157             _cn, _key];
158     return [NSException exceptionWithHTTPStatus:500 /* server error */
159                         reason:@"did not find mail folder class!"];
160   }
161   return [[[clazz alloc] initWithName:_key inContainer:self] autorelease];
162 }
163
164 - (id)lookupImap4Folder:(NSString *)_key inContext:(id)_cx {
165   NSString *s;
166
167   s = [_key isEqualToString:[self trashFolderNameInContext:_cx]]
168     ? @"SOGoTrashFolder" : @"SOGoMailFolder";
169   
170   return [self lookupFolder:_key ofClassNamed:s inContext:_cx];
171 }
172
173 - (id)lookupDraftsFolder:(NSString *)_key inContext:(id)_ctx {
174   return [self lookupFolder:_key ofClassNamed:@"SOGoDraftsFolder" 
175                inContext:_ctx];
176 }
177 - (id)lookupFiltersFolder:(NSString *)_key inContext:(id)_ctx {
178   return [self lookupFolder:_key ofClassNamed:@"SOGoSieveScriptsFolder" 
179                inContext:_ctx];
180 }
181
182 - (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag {
183   id obj;
184   
185   /* first check attributes directly bound to the application */
186   if ((obj = [super lookupName:_key inContext:_ctx acquire:NO]) != nil)
187     return obj;
188   
189   // TODO: those should be product.plist bindings? (can't be class bindings
190   //       though because they are 'per-account')
191   if ([_key isEqualToString:draftsFolderName]) {
192     if ((obj = [self lookupDraftsFolder:_key inContext:_ctx]) != nil)
193       return obj;
194   }
195   if ([_key isEqualToString:sieveFolderName]) {
196     if ((obj = [self lookupFiltersFolder:_key inContext:_ctx]) != nil)
197       return obj;
198   }
199   
200   if ((obj = [self lookupImap4Folder:_key inContext:_ctx]) != nil)
201     return obj;
202   
203   /* return 404 to stop acquisition */
204   return [NSException exceptionWithHTTPStatus:404 /* Not Found */];
205 }
206
207 /* special folders */
208
209 - (NSString *)inboxFolderNameInContext:(id)_ctx {
210   return inboxFolderName; /* cannot be changed in Cyrus ? */
211 }
212 - (NSString *)draftsFolderNameInContext:(id)_ctx {
213   return draftsFolderName; /* SOGo managed folder */
214 }
215 - (NSString *)sieveFolderNameInContext:(id)_ctx {
216   return sieveFolderName;  /* SOGo managed folder */
217 }
218 - (NSString *)sentFolderNameInContext:(id)_ctx {
219   /* OGo issue #1225 */
220   static NSString *s = nil;
221   
222   if (s == nil) {
223     NSUserDefaults *ud;
224     
225     ud = [NSUserDefaults standardUserDefaults];
226     s = [[ud stringForKey:@"SOGoSentFolderName"] copy];
227     if ([s length] == 0) s = @"Sent";
228     NSLog(@"Note: using SOGoSentFolderName: '%@'", s);
229   }
230   return s;
231 }
232 - (NSString *)trashFolderNameInContext:(id)_ctx {
233   /* OGo issue #1225 */
234   static NSString *s = nil;
235   
236   if (s == nil) {
237     NSUserDefaults *ud;
238     
239     ud = [NSUserDefaults standardUserDefaults];
240     s = [[ud stringForKey:@"SOGoTrashFolderName"] copy];
241     if ([s length] == 0) s = @"Trash";
242     NSLog(@"Note: using SOGoTrashFolderName: '%@'", s);
243   }
244   return s;
245 }
246
247 - (SOGoMailFolder *)inboxFolderInContext:(id)_ctx {
248   // TODO: use some profile to determine real location, use a -traverse lookup
249   SOGoMailFolder *folder;
250   
251   if (self->inboxFolder != nil)
252     return self->inboxFolder;
253   
254   folder = [self lookupName:[self inboxFolderNameInContext:_ctx]
255                  inContext:_ctx acquire:NO];
256   if ([folder isKindOfClass:[NSException class]]) return folder;
257   
258   return ((self->inboxFolder = [folder retain]));
259 }
260
261 - (SOGoMailFolder *)sentFolderInContext:(id)_ctx {
262   // TODO: use some profile to determine real location, use a -traverse lookup
263   SOGoMailFolder *folder;
264   
265   if (self->sentFolder != nil)
266     return self->sentFolder;
267   
268   folder = useAltNamespace ? (id)self : [self inboxFolderInContext:_ctx];
269   if ([folder isKindOfClass:[NSException class]]) return folder;
270   
271   folder = [folder lookupName:[self sentFolderNameInContext:_ctx]
272                    inContext:_ctx acquire:NO];
273   if ([folder isKindOfClass:[NSException class]]) return folder;
274   
275   if (![folder isNotNull]) {
276     return [NSException exceptionWithHTTPStatus:404 /* not found */
277                         reason:@"did not find Sent folder!"];
278   }
279   
280   return ((self->sentFolder = [folder retain]));
281 }
282
283 - (SOGoMailFolder *)trashFolderInContext:(id)_ctx {
284   // TODO: use some profile to determine real location
285   SOGoMailFolder *folder;
286   
287   if (self->trashFolder != nil)
288     return self->trashFolder;
289   
290   folder = useAltNamespace ? (id)self : [self inboxFolderInContext:_ctx];
291   if ([folder isKindOfClass:[NSException class]]) return folder;
292   
293   folder = [folder lookupName:[self trashFolderNameInContext:_ctx]
294                    inContext:_ctx acquire:NO];
295   if ([folder isKindOfClass:[NSException class]]) return folder;
296   
297   if (![folder isNotNull]) {
298     return [NSException exceptionWithHTTPStatus:404 /* not found */
299                         reason:@"did not find Trash folder!"];
300   }
301   
302   return ((self->trashFolder = [folder retain]));
303 }
304
305 /* WebDAV */
306
307 - (BOOL)davIsCollection {
308   return YES;
309 }
310
311 - (NSException *)davCreateCollection:(NSString *)_name inContext:(id)_ctx {
312   return [[self mailManager] createMailbox:_name atURL:[self imap4URL]
313                              password:[self imap4Password]];
314 }
315
316 - (NSString *)shortTitle {
317   NSString *s, *login, *host;
318   NSRange r;
319
320   s = [self nameInContainer];
321   
322   r = [s rangeOfString:@"@"];
323   if (r.length > 0) {
324     login = [s substringToIndex:r.location];
325     host  = [s substringFromIndex:(r.location + r.length)];
326   }
327   else {
328     login = nil;
329     host  = s;
330   }
331   
332   r = [host rangeOfString:@"."];
333   if (r.length > 0)
334     host = [host substringToIndex:r.location];
335   
336   if ([login length] == 0)
337     return host;
338   
339   r = [login rangeOfString:@"."];
340   if (r.length > 0)
341     login = [login substringToIndex:r.location];
342   
343   return [NSString stringWithFormat:@"%@@%@", login, host];
344 }
345
346 - (NSString *)davDisplayName {
347   return [self shortTitle];
348 }
349
350 @end /* SOGoMailAccount */