/* MAPIStoreSOGo.m - this file is part of SOGo * * Copyright (C) 2010 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 "MAPIApplication.h" #import "MAPIStoreContext.h" #undef DEBUG #include "MAPIStoreSOGo.h" /** \details Initialize sogo mapistore backend \return MAPISTORE_SUCCESS on success */ static int sogo_init (void) { NSAutoreleasePool *pool; SOGoProductLoader *loader; Class MAPIApplicationK; SOGoSystemDefaults *sd; NSUserDefaults *ud; SoProductRegistry *registry; 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"); sd = [SOGoSystemDefaults sharedSystemDefaults]; // /* We force the plugin to base its configuration on the SOGo tree. */ ud = [NSUserDefaults standardUserDefaults]; [ud registerDefaults: [ud persistentDomainForName: @"sogod"]]; 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]; [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 int sogo_create_context(TALLOC_CTX *mem_ctx, const char *uri, void **private_data) { NSAutoreleasePool *pool; sogo_context *cContext; Class MAPIStoreContextK; id context; int rc; DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; MAPIStoreContextK = NSClassFromString (@"MAPIStoreContext"); if (MAPIStoreContextK) { context = [MAPIStoreContextK contextFromURI: uri inMemCtx: mem_ctx]; [context retain]; cContext = talloc_zero(mem_ctx, sogo_context); cContext->objcContext = context; *private_data = cContext; rc = MAPISTORE_SUCCESS; } else rc = MAPISTORE_ERROR; [pool release]; return rc; } /** \details Delete a connection context from the sogo backend \param private_data pointer to the current sogo context \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ static int sogo_delete_context(void *private_data) { NSAutoreleasePool *pool; sogo_context *cContext; pool = [NSAutoreleasePool new]; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); cContext = private_data; [cContext->objcContext release]; [pool release]; talloc_free (cContext); return MAPISTORE_SUCCESS; } /** \details Delete data associated to a given folder or message \param private_data pointer to the current sogo context \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ static int sogo_release_record(void *private_data, uint64_t fmid, uint8_t type) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; pool = [NSAutoreleasePool new]; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context releaseRecordWithFMID: fmid ofTableType: type]; [context tearDownRequest]; [pool release]; return rc; } /** \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 int sogo_get_path(void *private_data, uint64_t fmid, uint8_t type, char **path) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context getPath: path ofFMID: fmid withTableType: type]; [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_get_fid_by_name(void *private_data, uint64_t parent_fid, const char* foldername, uint64_t *fid) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context getFID: fid byName: foldername inParentFID: parent_fid]; [context tearDownRequest]; [pool release]; 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 int sogo_op_mkdir(void *private_data, uint64_t parent_fid, uint64_t fid, struct SRow *aRow) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context mkDir: aRow withFID: fid inParentFID: parent_fid]; [context tearDownRequest]; [pool release]; 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 int sogo_op_rmdir(void *private_data, uint64_t parent_fid, uint64_t fid) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context rmDirWithFID: fid inParentFID: parent_fid]; [context tearDownRequest]; [pool release]; 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 int sogo_op_opendir(void *private_data, uint64_t parent_fid, uint64_t fid) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context openDir: fid inParentFID: parent_fid]; [context tearDownRequest]; [pool release]; return rc; } /** \details Close a folder from the sogo backend \param private_data pointer to the current sogo context \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ static int sogo_op_closedir(void *private_data) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context closeDir]; [context tearDownRequest]; [pool release]; return rc; } /** \details Read directory content from the sogo backend \param private_data pointer to the current sogo context \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ static int sogo_op_readdir_count(void *private_data, uint64_t fid, uint8_t table_type, uint32_t *RowCount) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context readCount: RowCount ofTableType: table_type inFID: fid]; [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_get_table_property(void *private_data, uint64_t fid, uint8_t table_type, enum table_query_type query_type, uint32_t pos, uint32_t proptag, void **data) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; // DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context getTableProperty: data withTag: proptag atPosition: pos withTableType: table_type andQueryType: query_type inFID: fid]; [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_openmessage(void *private_data, uint64_t fid, uint64_t mid, struct mapistore_message *msg) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; if (!context) DEBUG (5, (" context data is empty, failure ahead...")); rc = [context openMessage: msg withMID: mid inFID: fid]; if (rc) DEBUG (5, (" failure opening message\n")); [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_createmessage(void *private_data, uint64_t fid, uint64_t mid, uint8_t associated) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context createMessagePropertiesWithMID: mid inFID: fid isAssociated: associated]; [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_savechangesmessage(void *private_data, uint64_t mid, uint8_t flags) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context saveChangesInMessageWithMID: mid andFlags: flags]; [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_submitmessage(void *private_data, uint64_t mid, uint8_t flags) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context submitMessageWithMID: mid andFlags: flags]; [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_getprops(void *private_data, uint64_t fmid, uint8_t type, struct SPropTagArray *SPropTagArray, struct SRow *aRow) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context getProperties: SPropTagArray ofTableType: type inRow: aRow withMID: fmid]; [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_setprops(void *private_data, uint64_t fmid, uint8_t type, struct SRow *aRow) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context setPropertiesWithFMID: fmid ofTableType: type inRow: aRow]; [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_set_property_from_fd(void *private_data, uint64_t fmid, uint8_t type, uint32_t property, int fd) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; NSFileHandle *fileHandle; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; fileHandle = [[NSFileHandle alloc] initWithFileDescriptor: fd closeOnDealloc: NO]; rc = [context setProperty: property withFMID: fmid ofTableType: type fromFile: fileHandle]; [fileHandle release]; [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_get_property_into_fd(void *private_data, uint64_t fmid, uint8_t type, uint32_t property, int fd) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; NSFileHandle *fileHandle; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; fileHandle = [[NSFileHandle alloc] initWithFileDescriptor: fd closeOnDealloc: NO]; rc = [context getProperty: property withFMID: fmid ofTableType: type intoFile: fileHandle]; [fileHandle release]; [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_modifyrecipients(void *private_data, uint64_t mid, struct ModifyRecipientRow *rows, uint16_t count) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context modifyRecipientsWithMID: mid inRows: rows withCount: count]; [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_deletemessage(void *private_data, uint64_t fid, uint64_t mid, uint8_t flags) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context deleteMessageWithMID: mid inFID: fid withFlags: flags]; [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_get_folders_list(void *private_data, uint64_t fmid, struct indexing_folders_list **folders_list) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; [context setupRequest]; rc = [context getFoldersList: folders_list withFMID: fmid]; [context tearDownRequest]; [pool release]; return rc; } static int sogo_op_set_restrictions (void *private_data, uint64_t fid, uint8_t type, struct mapi_SRestriction *res, uint8_t *tableStatus) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; if (context) { [context setupRequest]; rc = [context setRestrictions: res withFID: fid andTableType: type getTableStatus: tableStatus]; [context tearDownRequest]; [pool release]; } else { NSLog (@" UNEXPECTED WEIRDNESS: RECEIVED NO CONTEXT"); rc = MAPI_E_NOT_FOUND; } return rc; } static int sogo_op_set_sort_order (void *private_data, uint64_t fid, uint8_t type, struct SSortOrderSet *set, uint8_t *tableStatus) { NSAutoreleasePool *pool; sogo_context *cContext; MAPIStoreContext *context; int rc; DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); pool = [NSAutoreleasePool new]; cContext = private_data; context = cContext->objcContext; if (context) { [context setupRequest]; rc = [context setSortOrder: set withFID: fid andTableType: type getTableStatus: tableStatus]; [context tearDownRequest]; [pool release]; } else { NSLog (@" UNEXPECTED WEIRDNESS: RECEIVED NO CONTEXT"); rc = MAPI_E_NOT_FOUND; } return rc; } /** \details Entry point for mapistore SOGO backend \return MAPI_E_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_ERROR; } else { registered = YES; /* Fill in our name */ backend.name = "SOGo"; backend.description = "mapistore SOGo backend"; backend.namespace = "sogo://"; backend.init = sogo_init; backend.create_context = sogo_create_context; backend.delete_context = sogo_delete_context; backend.release_record = sogo_release_record; backend.get_path = sogo_get_path; backend.op_get_fid_by_name = sogo_op_get_fid_by_name; backend.op_mkdir = sogo_op_mkdir; backend.op_rmdir = sogo_op_rmdir; backend.op_opendir = sogo_op_opendir; backend.op_closedir = sogo_op_closedir; backend.op_readdir_count = sogo_op_readdir_count; backend.op_get_table_property = sogo_op_get_table_property; backend.op_get_folders_list = sogo_op_get_folders_list; backend.op_set_restrictions = sogo_op_set_restrictions; backend.op_set_sort_order = sogo_op_set_sort_order; backend.op_openmessage = sogo_op_openmessage; backend.op_createmessage = sogo_op_createmessage; backend.op_modifyrecipients = sogo_op_modifyrecipients; backend.op_savechangesmessage = sogo_op_savechangesmessage; backend.op_submitmessage = sogo_op_submitmessage; backend.op_deletemessage = sogo_op_deletemessage; backend.op_setprops = sogo_op_setprops; backend.op_getprops = sogo_op_getprops; backend.op_set_property_from_fd = sogo_op_set_property_from_fd; backend.op_get_property_into_fd = sogo_op_get_property_into_fd; /* 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.name)); } } return ret; }