/* MAPIStoreSOGo.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. */ /* OpenChange SOGo storage backend */ #import #import #import #import #import #import #import #import #import #import #import #import "MAPIApplication.h" #import "MAPIStoreAttachment.h" #import "MAPIStoreAttachmentTable.h" #import "MAPIStoreContext.h" #import "MAPIStoreEmbeddedMessage.h" #import "MAPIStoreFolder.h" #import "MAPIStoreMessage.h" #import "MAPIStoreMailVolatileMessage.h" #import "MAPIStoreObject.h" #import "MAPIStoreTable.h" #import "NSObject+MAPIStore.h" #import "NSString+MAPIStore.h" #include #include #include static Class MAPIStoreContextK = Nil; static BOOL leakDebugging = NO; #define TRYCATCH_START @try { #define TRYCATCH_END(pool) \ } @catch (NSException * e) { \ [pool release]; \ GSUnregisterCurrentThread(); \ return sogo_backend_handle_objc_exception(e, __PRETTY_FUNCTION__, __LINE__); \ } static enum mapistore_error sogo_backend_unexpected_error() { NSLog (@" UNEXPECTED WEIRDNESS: RECEIVED NO OBJECT"); abort(); return MAPISTORE_SUCCESS; } static enum mapistore_error sogo_backend_handle_objc_exception(NSException *e, const char *fn_name, const int line_no) { NSLog(@"[SOGo: %s:%d] - EXCEPTION: %@, reason: %@, backtrace: %@", fn_name, line_no, [e name], [e reason], [e callStackSymbols]); if (![e callStackSymbols]) { void *frames[128]; int i, len = backtrace(frames, 128); char **symbols = backtrace_symbols(frames, len); NSLog(@"Backtrace using execinfo.h:"); for (i = 0; i < len; ++i) NSLog(@"\t%s", symbols[i]); free(symbols); } if ([[e name] isEqual:@"NotImplementedException"]) { return MAPISTORE_ERR_NOT_IMPLEMENTED; } return MAPISTORE_ERROR; } static void sogo_backend_atexit (void) { NSAutoreleasePool *pool; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; //NSLog (@"allocated classes:\n%s", GSDebugAllocationList (YES)); [pool release]; GSUnregisterCurrentThread (); } /** \details Initialize sogo mapistore backend \return MAPISTORE_SUCCESS on success */ static enum mapistore_error sogo_backend_init (void) { NSAutoreleasePool *pool; SOGoProductLoader *loader; Class MAPIApplicationK; NSUserDefaults *ud; SoProductRegistry *registry; char *argv[] = { SAMBA_PREFIX "/sbin/samba", NULL }; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; /* Here we work around a bug in GNUstep which decodes XML user defaults using the system encoding rather than honouring the encoding specified in the file. */ putenv ("GNUSTEP_STRING_ENCODING=NSUTF8StringEncoding"); //putenv ("NSZombieEnabled=YES"); [NSProcessInfo initializeWithArguments: argv count: 1 environment: environ]; [SOGoSystemDefaults sharedSystemDefaults]; /* We force the plugin to base its configuration on the SOGo tree. */ ud = [NSUserDefaults standardUserDefaults]; if (!leakDebugging && [ud boolForKey: @"SOGoDebugLeaks"]) { NSLog (@" leak debugging on"); GSDebugAllocationActive (YES); atexit (sogo_backend_atexit); leakDebugging = YES; } registry = [SoProductRegistry sharedProductRegistry]; [registry scanForProductsInDirectory: SOGO_BUNDLES_DIR]; loader = [SOGoProductLoader productLoader]; [loader loadProducts: [NSArray arrayWithObject: BACKEND_BUNDLE_NAME]]; MAPIApplicationK = NSClassFromString (@"MAPIApplication"); if (MAPIApplicationK) [[MAPIApplicationK new] activateApplication]; [[SOGoCache sharedCache] disableRequestsCache]; [[SOGoCache sharedCache] disableLocalCache]; MAPIStoreContextK = NSClassFromString (@"MAPIStoreContext"); [pool release]; return MAPISTORE_SUCCESS; } /** \details Create a connection context to the sogo backend \param mem_ctx pointer to the memory context \param uri pointer to the sogo path \param private_data pointer to the private backend context */ static enum mapistore_error sogo_backend_create_context(TALLOC_CTX *mem_ctx, struct mapistore_connection_info *conn_info, struct indexing_context *indexing, const char *uri, void **context_object) { NSAutoreleasePool *pool; MAPIStoreContext *context; int rc; DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; if (MAPIStoreContextK) { TRYCATCH_START rc = [MAPIStoreContextK openContext: &context withURI: uri connectionInfo: conn_info andTDBIndexing: indexing]; if (rc == MAPISTORE_SUCCESS) *context_object = [context tallocWrapper: mem_ctx]; TRYCATCH_END(pool) } else rc = MAPISTORE_ERROR; [pool release]; GSUnregisterCurrentThread (); return rc; } static enum mapistore_error sogo_backend_create_root_folder (const char *username, enum mapistore_context_role role, uint64_t fid, const char *name, // struct indexing_context *indexing, TALLOC_CTX *mem_ctx, char **mapistore_urip) { NSAutoreleasePool *pool; NSString *userName, *folderName; NSString *mapistoreUri; int rc; DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; if (MAPIStoreContextK) { TRYCATCH_START userName = [NSString stringWithUTF8String: username]; folderName = [NSString stringWithUTF8String: name]; rc = [MAPIStoreContextK createRootFolder: &mapistoreUri withFID: fid andName: folderName forUser: userName withRole: role]; if (rc == MAPISTORE_SUCCESS) *mapistore_urip = [mapistoreUri asUnicodeInMemCtx: mem_ctx]; TRYCATCH_END(pool) } else rc = MAPISTORE_ERROR; [pool release]; GSUnregisterCurrentThread (); return rc; } static enum mapistore_error sogo_backend_list_contexts(const char *username, struct indexing_context *indexing, TALLOC_CTX *mem_ctx, struct mapistore_contexts_list **contexts_listp) { NSAutoreleasePool *pool; NSString *userName; int rc; DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; if (MAPIStoreContextK) { TRYCATCH_START userName = [NSString stringWithUTF8String: username]; *contexts_listp = [MAPIStoreContextK listAllContextsForUser: userName withIndexing: indexing inMemCtx: mem_ctx]; rc = MAPISTORE_SUCCESS; TRYCATCH_END(pool) } else rc = MAPISTORE_ERROR; [pool release]; GSUnregisterCurrentThread (); return rc; } // andFID: fid // uint64_t fid, // void **private_data) /** \details return the mapistore path associated to a given message or folder ID \param private_data pointer to the current sogo context \param fmid the folder/message ID to lookup \param type whether it is a folder or message \param path pointer on pointer to the path to return \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error */ static enum mapistore_error sogo_context_get_path(void *backend_object, TALLOC_CTX *mem_ctx, uint64_t fmid, char **path) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (backend_object) { wrapper = backend_object; context = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [context getPath: path ofFMID: fmid inMemCtx: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_context_get_root_folder(void *backend_object, TALLOC_CTX *mem_ctx, uint64_t fid, void **folder_object) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreContext *context; MAPIStoreFolder *folder; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (backend_object) { wrapper = backend_object; context = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [context getRootFolder: &folder withFID: fid]; if (rc == MAPISTORE_SUCCESS) *folder_object = [folder tallocWrapper: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } /** \details Open a folder from the sogo backend \param private_data pointer to the current sogo context \param parent_fid the parent folder identifier \param fid the identifier of the colder to open \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ static enum mapistore_error sogo_folder_open_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid, void **childfolder_object) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreFolder *folder, *childFolder; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [folder openFolder: &childFolder withFID: fid]; if (rc == MAPISTORE_SUCCESS) *childfolder_object = [childFolder tallocWrapper: mem_ctx]; // [context tearDownRequest]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } /** \details Create a folder in the sogo backend \param private_data pointer to the current sogo context \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ static enum mapistore_error sogo_folder_create_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid, struct SRow *aRow, void **childfolder_object) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreFolder *folder, *childFolder; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [folder createFolder: &childFolder withRow: aRow andFID: fid]; if (rc == MAPISTORE_SUCCESS) *childfolder_object = [childFolder tallocWrapper: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } /** \details Delete a folder from the sogo backend \param private_data pointer to the current sogo context \param parent_fid the FID for the parent of the folder to delete \param fid the FID for the folder to delete \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ static enum mapistore_error sogo_folder_delete(void *folder_object) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreFolder *folder; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [folder deleteFolder]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_folder_get_child_count(void *folder_object, enum mapistore_table_type table_type, uint32_t *child_count) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreFolder *folder; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [folder getChildCount: child_count ofTableType: table_type]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_folder_open_message(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t mid, bool write_access, void **message_object) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreFolder *folder; MAPIStoreMessage *message; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [folder openMessage: &message withMID: mid forWriting: write_access inMemCtx: mem_ctx]; if (rc == MAPISTORE_SUCCESS) *message_object = [message tallocWrapper: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_folder_create_message(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t mid, uint8_t associated, void **message_object) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreFolder *folder; MAPIStoreMessage *message; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [folder createMessage: &message withMID: mid isAssociated: associated]; if (rc == MAPISTORE_SUCCESS) *message_object = [message tallocWrapper: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreFolder *folder; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [folder deleteMessageWithMID: mid andFlags: flags]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_folder_move_copy_messages(void *folder_object, void *source_folder_object, TALLOC_CTX *mem_ctx, uint32_t mid_count, uint64_t *src_mids, uint64_t *t_mids, struct Binary_r **target_change_keys, uint8_t want_copy) { MAPIStoreFolder *sourceFolder, *targetFolder; NSAutoreleasePool *pool; struct MAPIStoreTallocWrapper *wrapper; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; targetFolder = wrapper->instance; wrapper = source_folder_object; sourceFolder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [targetFolder moveCopyMessagesWithMIDs: src_mids andCount: mid_count fromFolder: sourceFolder withMIDs: t_mids andChangeKeys: target_change_keys wantCopy: want_copy inMemCtx: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_folder_move_folder(void *folder_object, void *target_folder_object, TALLOC_CTX *mem_ctx, const char *new_folder_name) { NSAutoreleasePool *pool; MAPIStoreFolder *moveFolder, *targetFolder; NSString *newFolderName; struct MAPIStoreTallocWrapper *wrapper; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; moveFolder = wrapper->instance; wrapper = target_folder_object; if (wrapper) targetFolder = wrapper->instance; else targetFolder = nil; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; if (new_folder_name) newFolderName = [NSString stringWithUTF8String: new_folder_name]; else newFolderName = nil; TRYCATCH_START rc = [moveFolder moveCopyToFolder: targetFolder withNewName: newFolderName isMove: YES isRecursive: YES inMemCtx: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_folder_copy_folder(void *folder_object, void *target_folder_object, TALLOC_CTX *mem_ctx, bool recursive, const char *new_folder_name) { NSAutoreleasePool *pool; MAPIStoreFolder *copyFolder, *targetFolder; NSString *newFolderName; struct MAPIStoreTallocWrapper *wrapper; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; copyFolder = wrapper->instance; wrapper = target_folder_object; targetFolder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; newFolderName = [NSString stringWithUTF8String: new_folder_name]; TRYCATCH_START rc = [copyFolder moveCopyToFolder: targetFolder withNewName: newFolderName isMove: NO isRecursive: recursive inMemCtx: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx, enum mapistore_table_type table_type, uint64_t change_num, struct UI8Array_r **fmidsp, uint64_t *cnp) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreFolder *folder; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [folder getDeletedFMIDs: fmidsp andCN: cnp fromChangeNumber: change_num inTableType: table_type inMemCtx: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx, enum mapistore_table_type table_type, uint32_t handle_id, void **table_object, uint32_t *row_count) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreFolder *folder; MAPIStoreTable *table; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [folder getTable: &table andRowCount: row_count tableType: table_type andHandleId: handle_id]; if (rc == MAPISTORE_SUCCESS) *table_object = [table tallocWrapper: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_folder_modify_permissions(void *folder_object, uint8_t flags, uint16_t pcount, struct PermissionData *permissions) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreFolder *folder; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [folder modifyPermissions: permissions withCount: pcount andFlags: flags]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_folder_preload_message_bodies(void *folder_object, enum mapistore_table_type table_type, const struct UI8Array_r *mids) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreFolder *folder; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (folder_object) { wrapper = folder_object; folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [folder preloadMessageBodiesWithMIDs: mids ofTableType: table_type]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_message_get_message_data(void *message_object, TALLOC_CTX *mem_ctx, struct mapistore_message **msg_dataP) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreMessage *message; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (message_object) { wrapper = message_object; message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START [message getMessageData: msg_dataP inMemCtx: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); rc = MAPISTORE_SUCCESS; } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_message_create_attachment (void *message_object, TALLOC_CTX *mem_ctx, void **attachment_object, uint32_t *aidp) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreMessage *message; MAPIStoreAttachment *attachment; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (message_object) { wrapper = message_object; message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [message createAttachment: &attachment inAID: aidp]; if (rc == MAPISTORE_SUCCESS) *attachment_object = [attachment tallocWrapper: mem_ctx]; // [context tearDownRequest]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_message_open_attachment (void *message_object, TALLOC_CTX *mem_ctx, uint32_t aid, void **attachment_object) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreMessage *message; MAPIStoreAttachment *attachment; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (message_object) { wrapper = message_object; message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [message getAttachment: &attachment withAID: aid]; if (rc == MAPISTORE_SUCCESS) *attachment_object = [attachment tallocWrapper: mem_ctx]; // [context tearDownRequest]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_message_get_attachment_table (void *message_object, TALLOC_CTX *mem_ctx, void **table_object, uint32_t *row_count) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreMessage *message; MAPIStoreAttachmentTable *table; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (message_object) { wrapper = message_object; message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [message getAttachmentTable: &table andRowCount: row_count]; if (rc == MAPISTORE_SUCCESS) *table_object = [table tallocWrapper: mem_ctx]; // [context tearDownRequest]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_message_modify_recipients (void *message_object, struct SPropTagArray *columns, uint16_t count, struct mapistore_message_recipient *recipients) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreMessage *message; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (message_object) { wrapper = message_object; message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [message modifyRecipientsWithRecipients: recipients andCount: count andColumns: columns]; // [context tearDownRequest]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_message_set_read_flag (void *message_object, uint8_t flag) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreMessage *message; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (message_object) { wrapper = message_object; message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [message setReadFlag: flag]; // [context tearDownRequest]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreMessage *message; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (message_object) { wrapper = message_object; message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [message saveMessage: mem_ctx]; // [context tearDownRequest]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_message_submit (void *message_object, enum SubmitFlags flags) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreMailVolatileMessage *message; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (message_object) { wrapper = message_object; message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [message submitWithFlags: flags]; // [context tearDownRequest]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_message_attachment_open_embedded_message (void *attachment_object, TALLOC_CTX *mem_ctx, void **message_object, uint64_t *midP, struct mapistore_message **msg) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreAttachment *attachment; MAPIStoreEmbeddedMessage *message; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (attachment_object) { wrapper = attachment_object; attachment = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [attachment openEmbeddedMessage: &message withMID: midP withMAPIStoreMsg: msg inMemCtx: mem_ctx]; if (rc == MAPISTORE_SUCCESS) *message_object = [message tallocWrapper: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_message_attachment_create_embedded_message (void *attachment_object, TALLOC_CTX *mem_ctx, void **message_object, struct mapistore_message **msg) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreAttachment *attachment; MAPIStoreEmbeddedMessage *message; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (attachment_object) { wrapper = attachment_object; attachment = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [attachment createEmbeddedMessage: &message withMAPIStoreMsg: msg inMemCtx: mem_ctx]; if (rc == MAPISTORE_SUCCESS) *message_object = [message tallocWrapper: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_table_get_available_properties(void *table_object, TALLOC_CTX *mem_ctx, struct SPropTagArray **propertiesP) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreTable *table; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (table_object) { wrapper = table_object; table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [table getAvailableProperties: propertiesP inMemCtx: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_table_set_columns (void *table_object, uint16_t count, enum MAPITAGS *properties) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreTable *table; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (table_object) { wrapper = table_object; table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [table setColumns: properties withCount: count]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_table_set_restrictions (void *table_object, struct mapi_SRestriction *restrictions, uint8_t *table_status) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreTable *table; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (table_object) { wrapper = table_object; table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START [table setRestrictions: restrictions]; //[table cleanupCaches]; rc = MAPISTORE_SUCCESS; *table_status = TBLSTAT_COMPLETE; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_table_set_sort_order (void *table_object, struct SSortOrderSet *sort_order, uint8_t *table_status) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreTable *table; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (table_object) { wrapper = table_object; table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START [table setSortOrder: sort_order]; [table cleanupCaches]; rc = MAPISTORE_SUCCESS; *table_status = TBLSTAT_COMPLETE; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_table_get_row (void *table_object, TALLOC_CTX *mem_ctx, enum mapistore_query_type query_type, uint32_t row_id, struct mapistore_property_data **data) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreTable *table; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (table_object) { wrapper = table_object; table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [table getRow: data withRowID: row_id andQueryType: query_type inMemCtx: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_table_get_row_count (void *table_object, enum mapistore_query_type query_type, uint32_t *row_countp) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreTable *table; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (table_object) { wrapper = table_object; table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [table getRowCount: row_countp withQueryType: query_type]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_table_handle_destructor (void *table_object, uint32_t handle_id) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreTable *table; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (table_object) { wrapper = table_object; table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START [table destroyHandle: handle_id]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); rc = MAPISTORE_SUCCESS; } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_properties_get_available_properties(void *object, TALLOC_CTX *mem_ctx, struct SPropTagArray **propertiesP) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreObject *propObject; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (object) { wrapper = object; propObject = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [propObject getAvailableProperties: propertiesP inMemCtx: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_properties_get_properties (void *object, TALLOC_CTX *mem_ctx, uint16_t count, enum MAPITAGS *properties, struct mapistore_property_data *data) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreObject *propObject; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (object) { wrapper = object; propObject = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [propObject getProperties: data withTags: properties andCount: count inMemCtx: mem_ctx]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_properties_set_properties (void *object, struct SRow *aRow) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; MAPIStoreObject *propObject; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (object) { wrapper = object; propObject = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START rc = [propObject addPropertiesFromRow: aRow]; TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); } else { rc = sogo_backend_unexpected_error(); } return rc; } static enum mapistore_error sogo_manager_generate_uri (TALLOC_CTX *mem_ctx, const char *user, const char *folder, const char *message, const char *rootURI, char **uri) { NSAutoreleasePool *pool; NSString *partialURLString, *username, *directory; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); if (uri == NULL) return MAPISTORE_ERR_INVALID_PARAMETER; /* This fixes a crash occurring during the instantiation of the NSAutoreleasePool below. */ GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; TRYCATCH_START // printf("rootURI = %s\n", rootURI); if (rootURI) partialURLString = [NSString stringWithUTF8String: rootURI]; else { /* sogo uri are of type: sogo://[username]:[password]@[folder type]/folder/id */ username = [NSString stringWithUTF8String: (user ? user : "*")]; /* Do proper directory lookup here */ directory = [NSString stringWithUTF8String: (folder ? folder : "*")]; partialURLString = [NSString stringWithFormat: @"sogo://%@:*@%@", username, directory]; } if (![partialURLString hasSuffix: @"/"]) partialURLString = [partialURLString stringByAppendingString: @"/"]; if (message) partialURLString = [partialURLString stringByAppendingFormat: @"%s.eml", message]; // printf("uri = %s\n", [partialURLString UTF8String]); *uri = talloc_strdup (mem_ctx, [partialURLString UTF8String]); TRYCATCH_END(pool) [pool release]; GSUnregisterCurrentThread (); return MAPISTORE_SUCCESS; } /** \details Entry point for mapistore SOGO backend \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error */ int mapistore_init_backend(void) { struct mapistore_backend backend; int ret; static BOOL registered = NO; if (registered) ret = MAPISTORE_SUCCESS; else { registered = YES; backend.backend.name = "SOGo"; backend.backend.description = "mapistore SOGo backend"; backend.backend.namespace = "sogo://"; backend.backend.init = sogo_backend_init; backend.backend.create_context = sogo_backend_create_context; backend.backend.create_root_folder = sogo_backend_create_root_folder; backend.backend.list_contexts = sogo_backend_list_contexts; backend.context.get_path = sogo_context_get_path; backend.context.get_root_folder = sogo_context_get_root_folder; backend.folder.open_folder = sogo_folder_open_folder; backend.folder.create_folder = sogo_folder_create_folder; backend.folder.delete = sogo_folder_delete; backend.folder.open_message = sogo_folder_open_message; backend.folder.create_message = sogo_folder_create_message; backend.folder.delete_message = sogo_folder_delete_message; backend.folder.move_copy_messages = sogo_folder_move_copy_messages; backend.folder.move_folder = sogo_folder_move_folder; backend.folder.copy_folder = sogo_folder_copy_folder; backend.folder.get_deleted_fmids = sogo_folder_get_deleted_fmids; backend.folder.get_child_count = sogo_folder_get_child_count; backend.folder.open_table = sogo_folder_open_table; backend.folder.modify_permissions = sogo_folder_modify_permissions; backend.folder.preload_message_bodies = sogo_folder_preload_message_bodies; backend.message.create_attachment = sogo_message_create_attachment; backend.message.get_attachment_table = sogo_message_get_attachment_table; backend.message.open_attachment = sogo_message_open_attachment; backend.message.open_embedded_message = sogo_message_attachment_open_embedded_message; backend.message.create_embedded_message = sogo_message_attachment_create_embedded_message; backend.message.get_message_data = sogo_message_get_message_data; backend.message.modify_recipients = sogo_message_modify_recipients; backend.message.set_read_flag = sogo_message_set_read_flag; backend.message.save = sogo_message_save; backend.message.submit = sogo_message_submit; backend.table.get_available_properties = sogo_table_get_available_properties; backend.table.set_restrictions = sogo_table_set_restrictions; backend.table.set_sort_order = sogo_table_set_sort_order; backend.table.set_columns = sogo_table_set_columns; backend.table.get_row = sogo_table_get_row; backend.table.get_row_count = sogo_table_get_row_count; backend.table.handle_destructor = sogo_table_handle_destructor; backend.properties.get_available_properties = sogo_properties_get_available_properties; backend.properties.get_properties = sogo_properties_get_properties; backend.properties.set_properties = sogo_properties_set_properties; backend.manager.generate_uri = sogo_manager_generate_uri; /* Register ourselves with the MAPISTORE subsystem */ ret = mapistore_backend_register (&backend); if (ret != MAPISTORE_SUCCESS) DEBUG(0, ("Failed to register the '%s' mapistore backend!\n", backend.backend.name)); } return ret; }