]> err.no Git - scalable-opengroupware.org/blob - SOGo/SoObjects/Mailer/SOGoMailAccount.m
account can create subfolders (root mailboxes)
[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   return [self lookupFolder:_key ofClassNamed:@"SOGoMailFolder" inContext:_cx];
166 }
167 - (id)lookupDraftsFolder:(NSString *)_key inContext:(id)_ctx {
168   return [self lookupFolder:_key ofClassNamed:@"SOGoDraftsFolder" 
169                inContext:_ctx];
170 }
171 - (id)lookupFiltersFolder:(NSString *)_key inContext:(id)_ctx {
172   return [self lookupFolder:_key ofClassNamed:@"SOGoSieveScriptsFolder" 
173                inContext:_ctx];
174 }
175
176 - (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag {
177   id obj;
178   
179   /* first check attributes directly bound to the application */
180   if ((obj = [super lookupName:_key inContext:_ctx acquire:NO]) != nil)
181     return obj;
182   
183   // TODO: those should be product.plist bindings? (can't be class bindings
184   //       though because they are 'per-account')
185   if ([_key isEqualToString:draftsFolderName]) {
186     if ((obj = [self lookupDraftsFolder:_key inContext:_ctx]) != nil)
187       return obj;
188   }
189   if ([_key isEqualToString:sieveFolderName]) {
190     if ((obj = [self lookupFiltersFolder:_key inContext:_ctx]) != nil)
191       return obj;
192   }
193   
194   if ((obj = [self lookupImap4Folder:_key inContext:_ctx]) != nil)
195     return obj;
196   
197   /* return 404 to stop acquisition */
198   return [NSException exceptionWithHTTPStatus:404 /* Not Found */];
199 }
200
201 /* special folders */
202
203 - (NSString *)inboxFolderNameInContext:(id)_ctx {
204   return inboxFolderName; /* cannot be changed in Cyrus ? */
205 }
206 - (NSString *)draftsFolderNameInContext:(id)_ctx {
207   return draftsFolderName; /* SOGo managed folder */
208 }
209 - (NSString *)sieveFolderNameInContext:(id)_ctx {
210   return sieveFolderName;  /* SOGo managed folder */
211 }
212 - (NSString *)sentFolderNameInContext:(id)_ctx {
213   /* OGo issue #1225 */
214   static NSString *s = nil;
215   
216   if (s == nil) {
217     NSUserDefaults *ud;
218     
219     ud = [NSUserDefaults standardUserDefaults];
220     s = [[ud stringForKey:@"SOGoSentFolderName"] copy];
221     if ([s length] == 0) s = @"Sent";
222     NSLog(@"Note: using SOGoSentFolderName: '%@'", s);
223   }
224   return s;
225 }
226 - (NSString *)trashFolderNameInContext:(id)_ctx {
227   /* OGo issue #1225 */
228   static NSString *s = nil;
229   
230   if (s == nil) {
231     NSUserDefaults *ud;
232     
233     ud = [NSUserDefaults standardUserDefaults];
234     s = [[ud stringForKey:@"SOGoTrashFolderName"] copy];
235     if ([s length] == 0) s = @"Trash";
236     NSLog(@"Note: using SOGoTrashFolderName: '%@'", s);
237   }
238   return s;
239 }
240
241 - (SOGoMailFolder *)inboxFolderInContext:(id)_ctx {
242   // TODO: use some profile to determine real location, use a -traverse lookup
243   SOGoMailFolder *folder;
244   
245   if (self->inboxFolder != nil)
246     return self->inboxFolder;
247   
248   folder = [self lookupName:[self inboxFolderNameInContext:_ctx]
249                  inContext:_ctx acquire:NO];
250   if ([folder isKindOfClass:[NSException class]]) return folder;
251   
252   return ((self->inboxFolder = [folder retain]));
253 }
254
255 - (SOGoMailFolder *)sentFolderInContext:(id)_ctx {
256   // TODO: use some profile to determine real location, use a -traverse lookup
257   SOGoMailFolder *folder;
258   
259   if (self->sentFolder != nil)
260     return self->sentFolder;
261   
262   folder = useAltNamespace ? (id)self : [self inboxFolderInContext:_ctx];
263   if ([folder isKindOfClass:[NSException class]]) return folder;
264   
265   folder = [folder lookupName:[self sentFolderNameInContext:_ctx]
266                    inContext:_ctx acquire:NO];
267   if ([folder isKindOfClass:[NSException class]]) return folder;
268   
269   if (![folder isNotNull]) {
270     return [NSException exceptionWithHTTPStatus:404 /* not found */
271                         reason:@"did not find Sent folder!"];
272   }
273   
274   return ((self->sentFolder = [folder retain]));
275 }
276
277 - (SOGoMailFolder *)trashFolderInContext:(id)_ctx {
278   // TODO: use some profile to determine real location
279   SOGoMailFolder *folder;
280   
281   if (self->trashFolder != nil)
282     return self->trashFolder;
283   
284   folder = useAltNamespace ? (id)self : [self inboxFolderInContext:_ctx];
285   if ([folder isKindOfClass:[NSException class]]) return folder;
286   
287   folder = [folder lookupName:[self trashFolderNameInContext:_ctx]
288                    inContext:_ctx acquire:NO];
289   if ([folder isKindOfClass:[NSException class]]) return folder;
290   
291   if (![folder isNotNull]) {
292     return [NSException exceptionWithHTTPStatus:404 /* not found */
293                         reason:@"did not find Trash folder!"];
294   }
295   
296   return ((self->trashFolder = [folder retain]));
297 }
298
299 /* WebDAV */
300
301 - (BOOL)davIsCollection {
302   return YES;
303 }
304
305 - (NSException *)davCreateCollection:(NSString *)_name inContext:(id)_ctx {
306   return [[self mailManager] createMailbox:_name atURL:[self imap4URL]
307                              password:[self imap4Password]];
308 }
309
310 - (NSString *)shortTitle {
311   NSString *s, *login, *host;
312   NSRange r;
313
314   s = [self nameInContainer];
315   
316   r = [s rangeOfString:@"@"];
317   if (r.length > 0) {
318     login = [s substringToIndex:r.location];
319     host  = [s substringFromIndex:(r.location + r.length)];
320   }
321   else {
322     login = nil;
323     host  = s;
324   }
325   
326   r = [host rangeOfString:@"."];
327   if (r.length > 0)
328     host = [host substringToIndex:r.location];
329   
330   if ([login length] == 0)
331     return host;
332
333   r = [login rangeOfString:@"."];
334   if (r.length > 0)
335     login = [login substringToIndex:r.location];
336   
337   return [NSString stringWithFormat:@"%@@%@", login, host];
338 }
339
340 - (NSString *)davDisplayName {
341   return [self shortTitle];
342 }
343
344 @end /* SOGoMailAccount */