/* MAPIStoreMailContext.m - this file is part of SOGo * * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #import #import #import #import #import #import #import #import #import "MAPIStoreMailFolder.h" #import "MAPIStoreUserContext.h" #import "NSString+MAPIStore.h" #import #import "MAPIApplication.h" #import "MAPIStoreMailContext.h" #include #undef DEBUG #include static Class MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; @implementation MAPIStoreMailContext + (void) initialize { MAPIStoreMailFolderK = [MAPIStoreMailFolder class]; MAPIStoreOutboxFolderK = [MAPIStoreOutboxFolder class]; } + (NSString *) MAPIModuleName { return @"mail"; } + (enum mapistore_context_role) MAPIContextRole { return MAPISTORE_MAIL_ROLE; } static inline NSString * MakeDisplayFolderName (NSString *folderName) { NSArray *parts; NSString *lastFolder; NSUInteger max; parts = [folderName componentsSeparatedByString: @"/"]; max = [parts count]; if (max > 1) { lastFolder = [parts objectAtIndex: max - 1]; if ([lastFolder length] == 0) lastFolder = [parts objectAtIndex: max - 2]; } else lastFolder = folderName; return [[lastFolder substringFromIndex: 6] fromCSSIdentifier]; } + (struct mapistore_contexts_list *) listContextsForUser: (NSString *) userName withIndexing: (struct indexing_context *) indexing inMemCtx: (TALLOC_CTX *) memCtx { struct mapistore_contexts_list *firstContext = NULL, *context; NSString *urlBase, *stringData, *currentName, *realName, *inboxName, *draftsName, *sentName, *trashName; NSArray *unprefixedFolders; NSMutableArray *secondaryFolders; enum mapistore_context_role role[] = {MAPISTORE_MAIL_ROLE, MAPISTORE_DRAFTS_ROLE, MAPISTORE_SENTITEMS_ROLE}; NSString *folderName[3]; NSUInteger count, max; SOGoMailAccount *accountFolder; MAPIStoreUserContext *userContext; WOContext *woContext; userContext = [MAPIStoreUserContext userContextWithUsername: userName andTDBIndexing: indexing]; accountFolder = [[userContext rootFolders] objectForKey: @"mail"]; woContext = [userContext woContext]; inboxName = @"folderINBOX"; folderName[0] = inboxName; unprefixedFolders = [[accountFolder draftsFolderNameInContext: woContext] componentsSeparatedByString: @"/"]; draftsName = [NSString stringWithFormat: @"folder%@", [unprefixedFolders componentsJoinedByString: @"/folder"]]; folderName[1] = draftsName; unprefixedFolders = [[accountFolder sentFolderNameInContext: woContext] componentsSeparatedByString: @"/"]; sentName = [NSString stringWithFormat: @"folder%@", [unprefixedFolders componentsJoinedByString: @"/folder"]]; folderName[2] = sentName; /* Note: trash is not used as a mail folder, since "Deleted Items" makes use of the fallback context */ unprefixedFolders = [[accountFolder trashFolderNameInContext: woContext] componentsSeparatedByString: @"/"]; trashName = [NSString stringWithFormat: @"folder%@", [unprefixedFolders componentsJoinedByString: @"/folder"]]; urlBase = [NSString stringWithFormat: @"sogo://%@:%@@mail/", [userName stringByReplacingOccurrencesOfString: @"@" withString: @"%40"], [userName stringByReplacingOccurrencesOfString: @"@" withString: @"%40"]]; for (count = 0; count < 3; count++) { context = talloc_zero (memCtx, struct mapistore_contexts_list); stringData = [NSString stringWithFormat: @"%@%@", urlBase, [folderName[count] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]]; context->url = [stringData asUnicodeInMemCtx: context]; /* remove "folder" prefix */ stringData = MakeDisplayFolderName (folderName[count]); context->name = [stringData asUnicodeInMemCtx: context]; context->main_folder = true; context->role = role[count]; context->tag = "tag"; DLIST_ADD_END (firstContext, context, void); } /* FIXME: Flush any cache before retrieving the hierarchy */ [accountFolder flushMailCaches]; secondaryFolders = [[accountFolder toManyRelationshipKeysWithNamespaces: NO] mutableCopy]; [secondaryFolders autorelease]; [secondaryFolders removeObject: inboxName]; [secondaryFolders removeObject: draftsName]; [secondaryFolders removeObject: sentName]; [secondaryFolders removeObject: trashName]; max = [secondaryFolders count]; for (count = 0; count < max; count++) { context = talloc_zero (memCtx, struct mapistore_contexts_list); // secondaryFolders has the names (1) Imap4Encoded and (2) asCSSIdentifier // e.g.: Probl&AOg-mes_SP_de_SP_synchronisation currentName = [secondaryFolders objectAtIndex: count]; // To get the real name we have to revert that (applying the decode functions) // in reverse order // e.g.: Problèmes de synchronisation realName = [[currentName fromCSSIdentifier] stringByDecodingImap4FolderName]; // And finally to represent that as URI we have to (1) asCSSIdentifier, // (2) Imap4Encode and (3) AddPercentEscapes // e.g.: Probl&AOg-mes_SP_de_SP_synchronisation // In the example there are no percent escapes added because is already ok stringData = [[[realName asCSSIdentifier] stringByEncodingImap4FolderName] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; context->url = [[NSString stringWithFormat: @"%@%@", urlBase, stringData] asUnicodeInMemCtx: context]; context->name = [[realName substringFromIndex: 6] asUnicodeInMemCtx: context]; context->main_folder = false; context->role = MAPISTORE_MAIL_ROLE; context->tag = "tag"; DLIST_ADD_END (firstContext, context, void); } return firstContext; } + (NSString *) createRootSecondaryFolderWithFID: (uint64_t) fid andName: (NSString *) newFolderName forUser: (NSString *) userName { NSString *mapistoreURI, *folderName; MAPIStoreUserContext *userContext; SOGoMailAccount *accountFolder; SOGoMailFolder *newFolder; userContext = [MAPIStoreUserContext userContextWithUsername: userName andTDBIndexing: NULL]; accountFolder = [[userContext rootFolders] objectForKey: @"mail"]; folderName = [NSString stringWithFormat: @"folder%@", [newFolderName asCSSIdentifier]]; newFolder = [SOGoMailFolder objectWithName: folderName inContainer: accountFolder]; if ([newFolder create]) mapistoreURI = [NSString stringWithFormat: @"sogo://%@:%@@mail/%@/", [userName stringByReplacingOccurrencesOfString: @"@" withString: @"%40"], [userName stringByReplacingOccurrencesOfString: @"@" withString: @"%40"], [[folderName stringByEncodingImap4FolderName] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]]; else mapistoreURI = nil; return mapistoreURI; } - (Class) MAPIStoreFolderClass { return MAPIStoreMailFolderK; } - (id) rootSOGoFolder { return [[userContext rootFolders] objectForKey: @"mail"]; } - (void) updateURLWithFolderName: (NSString *) newFolderName { NSString *urlString, *escapedName; NSMutableArray *pathComponents; BOOL hasSlash; NSUInteger max, folderNameIdx; NSURL *newURL; /* we do not need to unescape the url here as it will be reassembled later in the method */ urlString = [contextUrl absoluteString]; hasSlash = [urlString hasSuffix: @"/"]; pathComponents = [[urlString componentsSeparatedByString: @"/"] mutableCopy]; [pathComponents autorelease]; max = [pathComponents count]; if (hasSlash) folderNameIdx = max - 2; else folderNameIdx = max - 1; escapedName = [newFolderName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; [pathComponents replaceObjectAtIndex: folderNameIdx withObject: escapedName]; urlString = [pathComponents componentsJoinedByString: @"/"]; newURL = [NSURL URLWithString: urlString]; ASSIGN (contextUrl, newURL); } @end @implementation MAPIStoreOutboxContext + (NSString *) MAPIModuleName { return @"outbox"; } + (struct mapistore_contexts_list *) listContextsForUser: (NSString *) userName withIndexing: (struct indexing_context *) indexing inMemCtx: (TALLOC_CTX *) memCtx { struct mapistore_contexts_list *context; NSString *url, *folderName; NSArray *unprefixedFolders; SOGoMailAccount *accountFolder; MAPIStoreUserContext *userContext; WOContext *woContext; userContext = [MAPIStoreUserContext userContextWithUsername: userName andTDBIndexing: indexing]; accountFolder = [[userContext rootFolders] objectForKey: @"mail"]; woContext = [userContext woContext]; unprefixedFolders = [[accountFolder draftsFolderNameInContext: woContext] componentsSeparatedByString: @"/"]; folderName = [NSString stringWithFormat: @"folder%@", [unprefixedFolders componentsJoinedByString: @"/folder"]]; url = [NSString stringWithFormat: @"sogo://%@:%@@outbox/%@", [userName stringByReplacingOccurrencesOfString: @"@" withString: @"%40"], [userName stringByReplacingOccurrencesOfString: @"@" withString: @"%40"], folderName]; context = talloc_zero (memCtx, struct mapistore_contexts_list); context->url = [url asUnicodeInMemCtx: context]; /* TODO: use a localized version of this display name */ context->name = [@"Outbox" asUnicodeInMemCtx: context]; context->main_folder = true; context->role = MAPISTORE_OUTBOX_ROLE; context->tag = "tag"; context->prev = context; return context; } - (Class) MAPIStoreFolderClass { return MAPIStoreOutboxFolderK; } @end