2 Copyright (C) 2004-2005 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
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
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.
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
22 #import <Foundation/NSUserDefaults.h>
24 #import <NGObjWeb/NSException+HTTP.h>
25 #import <NGExtensions/NSNull+misc.h>
26 #import <NGExtensions/NSURL+misc.h>
27 #import <NGExtensions/NSObject+Logs.h>
28 #import <NGExtensions/NSString+misc.h>
30 #import <NGImap4/NGImap4Connection.h>
31 #import <NGImap4/NGImap4Client.h>
33 #import <SoObjects/SOGo/SOGoPermissions.h>
34 #import <SoObjects/SOGo/SOGoUser.h>
35 #import <SoObjects/SOGo/NSArray+Utilities.h>
37 #import "SOGoMailObject.h"
38 #import "SOGoMailAccount.h"
39 #import "SOGoMailManager.h"
40 #import "SOGoMailFolder.h"
42 static NSString *defaultUserID = @"anyone";
44 @implementation SOGoMailFolder
46 static BOOL useAltNamespace = NO;
50 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
52 useAltNamespace = [ud boolForKey:@"SOGoSpecialFoldersInRoot"];
57 SOGoMailAccount *mailAccount;
58 NSString *path, *folder;
61 mailAccount = [self mailAccountFolder];
62 path = [[self imap4Connection] imap4FolderNameForURL: [self imap4URL]];
64 folder = [mailAccount sharedFolderName];
65 if (folder && [path hasPrefix: folder])
66 [self setOwner: @"nobody"];
69 folder = [mailAccount otherUsersFolderName];
70 if (folder && [path hasPrefix: folder])
72 names = [path componentsSeparatedByString: @"/"];
73 if ([names count] > 1)
74 [self setOwner: [names objectAtIndex: 1]];
76 [self setOwner: @"nobody"];
81 - (id) initWithName: (NSString *) newName
82 inContainer: (id) newContainer
84 if ((self = [super initWithName: newName
85 inContainer: newContainer]))
104 - (NSString *) relativeImap4Name
106 return [nameInContainer substringFromIndex: 6];
110 - (NSMutableString *) imap4URLString
112 NSMutableString *urlString;
114 urlString = [super imap4URLString];
115 [urlString appendString: @"/"];
120 /* listing the available folders */
122 - (NSArray *) toManyRelationshipKeys
124 return [self subfolders];
127 - (NSArray *) subfolders
129 return [[self imap4Connection] subfoldersForURL: [self imap4URL]];
132 - (NSArray *) subfoldersURL
134 NSURL *selfURL, *currentURL;
135 NSMutableArray *subfoldersURL;
136 NSEnumerator *subfolders;
137 NSString *selfPath, *currentFolder;
139 subfoldersURL = [NSMutableArray array];
140 selfURL = [self imap4URL];
141 selfPath = [selfURL path];
142 subfolders = [[self subfolders] objectEnumerator];
143 currentFolder = [subfolders nextObject];
144 while (currentFolder)
146 currentURL = [[NSURL alloc]
147 initWithScheme: [selfURL scheme]
149 path: [selfPath stringByAppendingPathComponent:
151 [currentURL autorelease];
152 [subfoldersURL addObject: currentURL];
153 currentFolder = [subfolders nextObject];
156 return subfoldersURL;
159 - (NSString *) davContentType
161 return @"httpd/unix-directory";
164 - (NSArray *) toOneRelationshipKeys
167 unsigned int count, max;
172 filenames = [NSMutableArray new];
173 uids = [self fetchUIDsMatchingQualifier: nil sortOrdering: @"DATE"];
174 if (![uids isKindOfClass: [NSException class]])
177 for (count = 0; count < max; count++)
179 filename = [NSString stringWithFormat: @"%@.mail",
180 [uids objectAtIndex: count]];
181 [filenames addObject: filename];
191 - (NSArray *) fetchUIDsMatchingQualifier: (id) _q
192 sortOrdering: (id) _so
194 /* seems to return an NSArray of NSNumber's */
195 return [[self imap4Connection] fetchUIDsInURL: [self imap4URL]
196 qualifier: _q sortOrdering: _so];
199 - (NSArray *) fetchUIDs: (NSArray *) _uids
200 parts: (NSArray *) _parts
202 return [[self imap4Connection] fetchUIDs: _uids inURL: [self imap4URL]
206 - (NSException *) postData: (NSData *) _data
209 return [[self imap4Connection] postData: _data flags: _flags
210 toFolderURL: [self imap4URL]];
213 - (NSException *) expunge
215 return [[self imap4Connection] expungeAtURL: [self imap4URL]];
220 - (NSException *) addFlagsToAllMessages: (id) _f
222 return [[self imap4Connection] addFlags:_f
223 toAllMessagesInURL: [self imap4URL]];
228 - (id) lookupName: (NSString *) _key
230 acquire: (BOOL) _acquire
234 if ([_key hasPrefix: @"folder"])
235 obj = [SOGoMailFolder objectWithName: _key inContainer: self];
238 if ([[self imap4Connection] doesMailboxExistAtURL: [self imap4URL]])
240 if (isdigit ([_key characterAtIndex: 0]))
241 obj = [SOGoMailObject objectWithName: _key inContainer: self];
243 obj = [super lookupName: _key inContext: _ctx acquire: NO];
249 if (!obj && _acquire)
250 obj = [NSException exceptionWithHTTPStatus: 404 /* Not Found */];
257 - (BOOL) davIsCollection
262 - (NSException *) davCreateCollection: (NSString *) _name
265 return [[self imap4Connection] createMailbox:_name atURL:[self imap4URL]];
268 - (NSException *) delete
270 /* Note: overrides SOGoObject -delete */
271 return [[self imap4Connection] deleteMailboxAtURL:[self imap4URL]];
274 - (NSException *) davMoveToTargetObject: (id) _target
275 newName: (NSString *) _name
280 if ([_name length] == 0) { /* target already exists! */
281 // TODO: check the overwrite request field (should be done by dispatcher)
282 return [NSException exceptionWithHTTPStatus:412 /* Precondition Failed */
283 reason:@"target already exists"];
285 if (![_target respondsToSelector:@selector(imap4URL)]) {
286 return [NSException exceptionWithHTTPStatus:502 /* Bad Gateway */
287 reason:@"target is not an IMAP4 folder"];
290 /* build IMAP4 URL for target */
292 destImapURL = [_target imap4URL];
293 // - destImapURL = [NSURL URLWithString:[[destImapURL path]
294 // - stringByAppendingPathComponent:_name]
295 // - relativeToURL:destImapURL];
296 destImapURL = [NSURL URLWithString: _name
297 relativeToURL: destImapURL];
299 [self logWithFormat:@"TODO: should move collection as '%@' to: %@",
300 [[self imap4URL] absoluteString],
301 [destImapURL absoluteString]];
303 return [[self imap4Connection] moveMailboxAtURL:[self imap4URL]
307 - (NSException *) davCopyToTargetObject: (id) _target
308 newName: (NSString *) _name
311 [self logWithFormat:@"TODO: should copy collection as '%@' to: %@",
313 return [NSException exceptionWithHTTPStatus:501 /* Not Implemented */
314 reason:@"not implemented"];
318 - (NSString *) folderType
323 - (NSString *) outlookFolderClass
325 // TODO: detect Trash/Sent/Drafts folders
326 SOGoMailAccount *account;
329 if (folderType != nil)
332 account = [self mailAccountFolder];
335 if ([n isEqualToString:[account trashFolderNameInContext:nil]])
336 folderType = @"IPF.Trash";
337 else if ([n isEqualToString:[account inboxFolderNameInContext:nil]])
338 folderType = @"IPF.Inbox";
339 else if ([n isEqualToString:[account sentFolderNameInContext:nil]])
340 folderType = @"IPF.Sent";
342 folderType = @"IPF.Folder";
349 - (NSArray *) _imapAclsToSOGoAcls: (NSString *) imapAcls
351 unsigned int count, max;
352 NSMutableArray *SOGoAcls;
354 SOGoAcls = [NSMutableArray array];
355 max = [imapAcls length];
356 for (count = 0; count < max; count++)
358 switch ([imapAcls characterAtIndex: count])
361 [SOGoAcls addObjectUniquely: SOGoRole_ObjectViewer];
364 [SOGoAcls addObjectUniquely: SOGoRole_ObjectReader];
367 [SOGoAcls addObjectUniquely: SOGoMailRole_SeenKeeper];
370 [SOGoAcls addObjectUniquely: SOGoMailRole_Writer];
373 [SOGoAcls addObjectUniquely: SOGoRole_ObjectCreator];
376 [SOGoAcls addObjectUniquely: SOGoMailRole_Poster];
379 [SOGoAcls addObjectUniquely: SOGoRole_FolderCreator];
382 [SOGoAcls addObjectUniquely: SOGoRole_FolderEraser];
385 [SOGoAcls addObjectUniquely: SOGoRole_ObjectEraser];
388 [SOGoAcls addObjectUniquely: SOGoMailRole_Expunger];
391 [SOGoAcls addObjectUniquely: SOGoMailRole_Administrator];
399 - (NSString *) _sogoAclsToImapAcls: (NSArray *) sogoAcls
401 NSMutableString *imapAcls;
403 NSString *currentAcl;
406 imapAcls = [NSMutableString string];
407 acls = [sogoAcls objectEnumerator];
408 currentAcl = [acls nextObject];
411 if ([currentAcl isEqualToString: SOGoRole_ObjectViewer])
413 else if ([currentAcl isEqualToString: SOGoRole_ObjectReader])
415 else if ([currentAcl isEqualToString: SOGoMailRole_SeenKeeper])
417 else if ([currentAcl isEqualToString: SOGoMailRole_Writer])
419 else if ([currentAcl isEqualToString: SOGoRole_ObjectCreator])
421 else if ([currentAcl isEqualToString: SOGoMailRole_Poster])
423 else if ([currentAcl isEqualToString: SOGoRole_FolderCreator])
425 else if ([currentAcl isEqualToString: SOGoRole_FolderEraser])
427 else if ([currentAcl isEqualToString: SOGoRole_ObjectEraser])
429 else if ([currentAcl isEqualToString: SOGoMailRole_Expunger])
431 else if ([currentAcl isEqualToString: SOGoMailRole_Administrator])
437 [imapAcls appendFormat: @"%c", character];
439 currentAcl = [acls nextObject];
445 - (void) _readMailboxACL
448 = [[self imap4Connection] aclForMailboxAtURL: [self imap4URL]];
452 - (NSArray *) aclUsers
457 [self _readMailboxACL];
459 if ([mailboxACL isKindOfClass: [NSDictionary class]])
460 users = [mailboxACL allKeys];
467 - (NSMutableArray *) _sharesACLs
469 NSMutableArray *acls;
470 SOGoMailAccount *mailAccount;
471 NSString *path, *folder;
473 // unsigned int count;
475 acls = [NSMutableArray array];
477 mailAccount = [self mailAccountFolder];
478 path = [[self imap4Connection] imap4FolderNameForURL: [self imap4URL]];
479 // names = [path componentsSeparatedByString: @"/"];
480 // count = [names count];
482 folder = [mailAccount sharedFolderName];
483 if (folder && [path hasPrefix: folder])
484 [acls addObject: SOGoRole_ObjectViewer];
487 folder = [mailAccount otherUsersFolderName];
488 if (folder && [path hasPrefix: folder])
489 [acls addObject: SOGoRole_ObjectViewer];
491 [acls addObject: SoRole_Owner];
497 - (NSArray *) aclsForUser: (NSString *) uid
499 NSMutableArray *acls;
502 acls = [self _sharesACLs];
505 [self _readMailboxACL];
507 if ([mailboxACL isKindOfClass: [NSDictionary class]])
509 userAcls = [mailboxACL objectForKey: uid];
510 if (!([userAcls length] || [uid isEqualToString: defaultUserID]))
511 userAcls = [mailboxACL objectForKey: defaultUserID];
512 if ([userAcls length])
513 [acls addObjectsFromArray: [self _imapAclsToSOGoAcls: userAcls]];
519 - (void) removeAclsForUsers: (NSArray *) users
522 NSString *currentUID;
523 NSString *folderName;
524 NGImap4Client *client;
526 folderName = [[self imap4Connection] imap4FolderNameForURL: [self imap4URL]];
527 client = [imap4 client];
529 uids = [users objectEnumerator];
530 currentUID = [uids nextObject];
533 [client deleteACL: folderName uid: currentUID];
534 currentUID = [uids nextObject];
536 [mailboxACL release];
540 - (void) setRoles: (NSArray *) roles
541 forUser: (NSString *) uid
543 NSString *acls, *folderName;
545 acls = [self _sogoAclsToImapAcls: roles];
546 folderName = [[self imap4Connection] imap4FolderNameForURL: [self imap4URL]];
547 [[imap4 client] setACL: folderName rights: acls uid: uid];
549 [mailboxACL release];
553 - (NSString *) defaultUserID
555 return defaultUserID;
558 - (NSString *) otherUsersPathToFolder
560 NSString *userPath, *selfPath, *otherUsers, *sharedFolders;
561 SOGoMailAccount *account;
563 account = [self mailAccountFolder];
564 otherUsers = [account otherUsersFolderName];
565 sharedFolders = [account sharedFolderName];
567 selfPath = [[self imap4URL] path];
569 && [selfPath hasPrefix:
570 [NSString stringWithFormat: @"/%@", otherUsers]])
572 && [selfPath hasPrefix:
573 [NSString stringWithFormat: @"/%@", sharedFolders]]))
578 userPath = [NSString stringWithFormat: @"/%@/%@%@",
579 [otherUsers stringByEscapingURL],
588 - (NSString *) httpURLForAdvisoryToUser: (NSString *) uid
591 NSString *otherUsersPath, *url;
592 SOGoMailAccount *thisAccount;
593 NSDictionary *mailAccount;
595 user = [SOGoUser userWithLogin: uid roles: nil];
596 otherUsersPath = [self otherUsersPathToFolder];
599 thisAccount = [self mailAccountFolder];
600 mailAccount = [[user mailAccounts] objectAtIndex: 0];
601 url = [NSString stringWithFormat: @"%@/%@%@",
602 [self soURLToBaseContainerForUser: uid],
603 [mailAccount objectForKey: @"name"],
612 - (NSString *) resourceURLForAdvisoryToUser: (NSString *) uid
614 NSURL *selfURL, *userURL;
616 selfURL = [self imap4URL];
617 userURL = [[NSURL alloc] initWithScheme: [selfURL scheme]
619 path: [self otherUsersPathToFolder]];
620 [userURL autorelease];
622 return [userURL absoluteString];
625 @end /* SOGoMailFolder */