diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile new file mode 100644 index 000000000..c164baba9 --- /dev/null +++ b/OpenChange/GNUmakefile @@ -0,0 +1,35 @@ +# GNUstep makefile + +include ../config.make +include $(GNUSTEP_MAKEFILES)/common.make +include ../Version + +PKG_CONFIG_PATH=/usr/local/samba/lib/pkgconfig + +ADDITIONAL_INCLUDE_DIRS += $(shell pkg-config libmapiproxy --cflags) -I../SoObjects -I../SOPE +ADDITIONAL_LIB_DIRS += -L../SOPE/GDLContentStore/obj/ $(shell pkg-config libmapiproxy --libs) + +SAMBA_LIB_DIR = $(shell pkg-config libmapiproxy --variable=libdir) + +MAPISTORESOGO = MAPIStoreSOGo +$(MAPISTORESOGO)_VERSION = 1.0.0 +LIBRARY_NAME = $(MAPISTORESOGO) +$(MAPISTORESOGO)_INSTALL_DIR = $(SAMBA_LIB_DIR)/mapistore_backends + +$(MAPISTORESOGO)_OBJC_FILES += \ + MAPIApplication.m \ + MAPIStoreAuthenticator.m \ + MAPIStoreContext.m \ + MAPIStoreMapping.m \ + MAPIStoreSOGo.m \ + \ + MAPIStoreCalendarContext.m \ + MAPIStoreContactsContext.m \ + MAPIStoreMailContext.m \ + \ + NSCalendarDate+MAPIStore.m \ + NSString+MAPIStore.m + +-include GNUmakefile.preamble +include $(GNUSTEP_MAKEFILES)/library.make +-include GNUmakefile.postamble diff --git a/OpenChange/MAPIApplication.h b/OpenChange/MAPIApplication.h new file mode 100644 index 000000000..572e6062b --- /dev/null +++ b/OpenChange/MAPIApplication.h @@ -0,0 +1,43 @@ +/* MAPIApplication.h - this file is part of $PROJECT_NAME_HERE$ + * + * Copyright (C) 2010 Wolfgang Sourdeau + * + * 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 2, 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. + */ + +#ifndef MAPIAPPLICATION_H +#define MAPIAPPLICATION_H + +#import + +@class MAPIStoreContext; + +@interface MAPIApplication : SoApplication +{ + MAPIStoreContext *mapiContext; +} + +- (id) authenticatorInContext: (id) context; + +- (void) setMAPIStoreContext: (MAPIStoreContext *) newMAPIStoreContext; + +@end + +extern MAPIApplication *MAPIApp; + +#endif /* MAPIAPPLICATION_H */ diff --git a/OpenChange/MAPIApplication.m b/OpenChange/MAPIApplication.m new file mode 100644 index 000000000..92744e3f7 --- /dev/null +++ b/OpenChange/MAPIApplication.m @@ -0,0 +1,105 @@ +/* MAPIApplication.m - this file is part of $PROJECT_NAME_HERE$ + * + * Copyright (C) 2010 Wolfgang Sourdeau + * + * 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 2, 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 "MAPIStoreContext.h" + +#import "MAPIApplication.h" + +MAPIApplication *MAPIApp = nil; + +@interface UnixSignalHandler : NSObject + ++ sharedHandler; + +- (void)removeObserver:(id)observer; + +@end + +@implementation MAPIApplication + +- (id) init +{ + SOGoProductLoader *loader; + NSUserDefaults *ud; + SOGoSystemDefaults *sd; + + if (!MAPIApp) { + /* 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"]]; + + NSLog (@"(config check) imap server: %@", [sd imapServer]); + + // TODO publish + loader = [SOGoProductLoader productLoader]; + [loader loadProducts: [NSArray arrayWithObjects: + @"Contacts.SOGo", + @"Appointments.SOGo", + @"Mailer.SOGo", + nil]]; + + // TODO publish + [iCalEntityObject initializeSOGoExtensions]; + + MAPIApp = [super init]; + [MAPIApp retain]; + + /* This is a hack to revert what is done in [WOCoreApplication + init] */ + [[NSClassFromString(@"UnixSignalHandler") sharedHandler] + removeObserver: self]; + } + + return MAPIApp; +} + +- (void) dealloc +{ + [mapiContext release]; + [super dealloc]; +} + +- (void) setMAPIStoreContext: (MAPIStoreContext *) newMAPIStoreContext +{ + ASSIGN (mapiContext, newMAPIStoreContext); +} + +- (id) authenticatorInContext: (id) context +{ + return [mapiContext authenticator]; +} + +@end diff --git a/OpenChange/MAPIStoreAuthenticator.h b/OpenChange/MAPIStoreAuthenticator.h new file mode 100644 index 000000000..eda741095 --- /dev/null +++ b/OpenChange/MAPIStoreAuthenticator.h @@ -0,0 +1,49 @@ +/* MAPIStoreAuthenticator.h - this file is part of $PROJECT_NAME_HERE$ + * + * Copyright (C) 2010 Wolfgang Sourdeau + * + * 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 2, 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. + */ + +#ifndef MAPISTOREAUTHENTICATOR_H +#define MAPISTOREAUTHENTICATOR_H + +#import + +@class NSString; + +@class WOContext; + +@interface MAPIStoreAuthenticator : NSObject +{ + NSString *username; + NSString *password; +} + +- (void) setUsername: (NSString *) newUsername; +- (NSString *) username; + +- (void) setPassword: (NSString *) newPassword; + +- (NSString *) imapPasswordInContext: (WOContext *) context + forServer: (NSString *) imapServer + forceRenew: (BOOL) renew; + +@end + +#endif /* MAPISTOREAUTHENTICATOR_H */ diff --git a/OpenChange/MAPIStoreAuthenticator.m b/OpenChange/MAPIStoreAuthenticator.m new file mode 100644 index 000000000..35ad29eec --- /dev/null +++ b/OpenChange/MAPIStoreAuthenticator.m @@ -0,0 +1,74 @@ +/* MAPIStoreAuthenticator.m - this file is part of SOGo + * + * Copyright (C) 2010 Wolfgang Sourdeau + * + * 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 2, 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 "MAPIStoreAuthenticator.h" + +@implementation MAPIStoreAuthenticator + +- (void) dealloc +{ + [username release]; + [password release]; + [super dealloc]; +} + +- (void) setUsername: (NSString *) newUsername +{ + ASSIGN (username, newUsername); +} + +- (NSString *) username +{ + return username; +} + +- (void) setPassword: (NSString *) newPassword +{ + ASSIGN (password, newPassword); +} + +- (SOGoUser *) userInContext: (WOContext *)_ctx +{ + return [SOGoUser userWithLogin: username + roles: [NSArray arrayWithObject: SoRole_Authenticated]]; +} + +- (NSString *) imapPasswordInContext: (WOContext *) context + forServer: (NSString *) imapServer + forceRenew: (BOOL) renew +{ + NSString *imapPassword; + + if (renew) + imapPassword = nil; + else + imapPassword = password; + + return imapPassword; +} + +@end diff --git a/OpenChange/MAPIStoreCalendarContext.h b/OpenChange/MAPIStoreCalendarContext.h new file mode 100644 index 000000000..54be02022 --- /dev/null +++ b/OpenChange/MAPIStoreCalendarContext.h @@ -0,0 +1,32 @@ +/* MAPIStoreCalendarContext.h - 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 2, 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. + */ + +#ifndef MAPISTORECALENDARCONTEXT_H +#define MAPISTORECALENDARCONTEXT_H + +#import "MAPIStoreContext.h" + +@interface MAPIStoreCalendarContext : MAPIStoreContext + +@end + +#endif /* MAPISTORECALENDARCONTEXT_H */ diff --git a/OpenChange/MAPIStoreCalendarContext.m b/OpenChange/MAPIStoreCalendarContext.m new file mode 100644 index 000000000..44968cd62 --- /dev/null +++ b/OpenChange/MAPIStoreCalendarContext.m @@ -0,0 +1,183 @@ +/* MAPIStoreCalendarContext.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 2, 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 "MAPIApplication.h" +#import "MAPIStoreAuthenticator.h" +#import "NSCalendarDate+MAPIStore.h" +#import "NSString+MAPIStore.h" + +#import "MAPIStoreCalendarContext.h" + +#undef DEBUG +#include + +static Class SOGoUserFolderK; + +@implementation MAPIStoreCalendarContext + ++ (void) initialize +{ + SOGoUserFolderK = [SOGoUserFolderK class]; +} + +- (void) setupModuleFolder +{ + id userFolder; + + userFolder = [SOGoUserFolderK objectWithName: [authenticator username] + inContainer: MAPIApp]; + [woContext setClientObject: userFolder]; + [userFolder retain]; // LEAK + + moduleFolder = [userFolder lookupName: @"Calendar" + inContext: woContext + acquire: NO]; + [moduleFolder retain]; +} + +- (int) getMessageTableChildproperty: (void **) data + atURL: (NSString *) childURL + withTag: (uint32_t) proptag + inFolder: (SOGoFolder *) folder + withFID: (uint64_t) fid +{ + uint32_t *longValue; + uint8_t *boolValue; + // id child; + id event; + int rc; + + rc = MAPI_E_SUCCESS; + switch (proptag) { + case PR_ICON_INDEX: // TODO + longValue = talloc_zero(memCtx, uint32_t); + *longValue = 0x00000400; /* see http://msdn.microsoft.com/en-us/library/cc815472.aspx */ + // *longValue = 0x00000401 for recurring event + // *longValue = 0x00000402 for meeting + // *longValue = 0x00000403 for recurring meeting + // *longValue = 0x00000404 for invitation + *data = longValue; + break; + case PR_MESSAGE_CLASS_UNICODE: + *data = talloc_strdup(memCtx, "IPM.Appointment"); + break; + case 0x818f0040: // DTSTART + event = [[self lookupObject: childURL] component: NO secure: NO]; + *data = [[event startDate] asFileTimeInMemCtx: memCtx]; + break; + case 0x818a0040: // DTEND + event = [[self lookupObject: childURL] component: NO secure: NO]; + *data = [[event endDate] asFileTimeInMemCtx: memCtx]; + break; + case 0x82410003: // LABEL idx, should be saved in an X- property + longValue = talloc_zero(memCtx, uint32_t); + *longValue = 0; + *data = longValue; + break; + case PR_SUBJECT_UNICODE: // SUMMARY + case PR_NORMALIZED_SUBJECT_UNICODE: + case PR_CONVERSATION_TOPIC_UNICODE: + event = [[self lookupObject: childURL] component: NO secure: NO]; + *data = [[event summary] asUnicodeInMemCtx: memCtx]; + break; + case 0x810c001f: // LOCATION + event = [[self lookupObject: childURL] component: NO secure: NO]; + *data = [[event location] asUnicodeInMemCtx: memCtx]; + break; + case 0x8224000b: // private (bool), should depend on CLASS + boolValue = talloc_zero(memCtx, uint8_t); + *boolValue = NO; + *data = boolValue; + break; + case PR_SENSITIVITY: // not implemented, depends on CLASS + // normal = 0, private = 2 + longValue = talloc_zero(memCtx, uint32_t); + *longValue = 0; + *data = longValue; + break; + + // case PR_VD_NAME_UNICODE: + // *data = talloc_strdup(memCtx, "PR_VD_NAME_UNICODE"); + // break; + // case PR_EMS_AB_DXA_REMOTE_CLIENT_UNICODE: "Home:" ??? + // *data = talloc_strdup(memCtx, "PR_EMS..."); + // break; + default: + rc = [super getMessageTableChildproperty: data + atURL: childURL + withTag: proptag + inFolder: folder + withFID: fid]; + } + +// #define PR_REPLY_TIME PROP_TAG(PT_SYSTIME , 0x0030) /* 0x00300040 */ +// #define PR_MESSAGE_FLAGS PROP_TAG(PT_LONG , 0x0e07) /* 0x0e070003 */ +// #define PR_MSG_STATUS PROP_TAG(PT_LONG , 0x0e17) /* 0x0e170003 */ +// #define PR_INTERNET_MESSAGE_ID_UNICODE PROP_TAG(PT_UNICODE , 0x1035) /* 0x1035001f */ +// #define PR_FLAG_STATUS PROP_TAG(PT_LONG , 0x1090) /* 0x10900003 */ +// #define PR_CREATION_TIME PROP_TAG(PT_SYSTIME , 0x3007) /* 0x30070040 */ +// #define PR_SEARCH_KEY PROP_TAG(PT_BINARY , 0x300b) /* 0x300b0102 */ + + +// #define PR_EMS_AB_INCOMING_MSG_SIZE_LIMIT PROP_TAG(PT_LONG , 0x8190) /* 0x81900003 */ +// Not found: 81930003 // ? +// Not found: 80fa000b // ? +// Not found: 81c4000b // ? +// Not found: 81e7000b // ? +// Not found: 81ee000b // ? + +// Not found: 81f80003 // +// Not found: 82020102 // +// Not found: 818b0102 // +// Not found: 81d1001f // + + return rc; +} + +// - (int) getFolderTableChildproperty: (void **) data +// atURL: (NSString *) childURL +// withTag: (uint32_t) proptag +// inFolder: (SOGoFolder *) folder +// withFID: (uint64_t) fid +// { +// int rc; + +// [self logWithFormat: @"XXXXX unexpected!!!!!!!!!"]; +// rc = MAPI_E_SUCCESS; +// switch (proptag) { +// default: +// rc = [super getFolderTableChildproperty: data +// atURL: childURL +// withTag: proptag +// inFolder: folder +// withFID: fid]; +// } + +// return rc; +// } + +@end diff --git a/OpenChange/MAPIStoreContactsContext.h b/OpenChange/MAPIStoreContactsContext.h new file mode 100644 index 000000000..171978ca8 --- /dev/null +++ b/OpenChange/MAPIStoreContactsContext.h @@ -0,0 +1,32 @@ +/* MAPIStoreContactsContext.h - 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 2, 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. + */ + +#ifndef MAPISTORECONTACTSCONTEXT_H +#define MAPISTORECONTACTSCONTEXT_H + +#import "MAPIStoreContext.h" + +@interface MAPIStoreContactsContext : MAPIStoreContext + +@end + +#endif /* MAPISTORECONTACTSCONTEXT_H */ diff --git a/OpenChange/MAPIStoreContactsContext.m b/OpenChange/MAPIStoreContactsContext.m new file mode 100644 index 000000000..ccf8b00de --- /dev/null +++ b/OpenChange/MAPIStoreContactsContext.m @@ -0,0 +1,296 @@ +/* MAPIStoreContactsContext.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 2, 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 "MAPIApplication.h" +#import "MAPIStoreAuthenticator.h" +#import "NSString+MAPIStore.h" + +#import "MAPIStoreContactsContext.h" + +#undef DEBUG +#include + +static Class SOGoUserFolderK; + +@implementation MAPIStoreContactsContext + ++ (void) initialize +{ + SOGoUserFolderK = [SOGoUserFolderK class]; +} + +- (void) setupModuleFolder +{ + id userFolder; + + userFolder = [SOGoUserFolderK objectWithName: [authenticator username] + inContainer: MAPIApp]; + [woContext setClientObject: userFolder]; + [userFolder retain]; // LEAK + + moduleFolder = [userFolder lookupName: @"Contacts" + inContext: woContext + acquire: NO]; + [moduleFolder retain]; +} + +// - (int) getCommonTableChildproperty: (void **) data +// atURL: (NSString *) childURL +// withTag: (uint32_t) proptag +// inFolder: (SOGoFolder *) folder +// withFID: (uint64_t) fid +// { +// int rc; + +// rc = MAPI_E_SUCCESS; +// switch (proptag) { +// default: +// rc = [super getCommonTableChildproperty: data +// atURL: childURL +// withTag: proptag +// inFolder: folder +// withFID: fid]; +// } + +// return rc; +// } + +- (NSString *) _phoneOfType: (NSString *) aType + excluding: (NSString *) aTypeToExclude + inCard: (NGVCard *) card +{ + NSArray *elements; + NSArray *phones; + NSString *phone; + + phones = [card childrenWithTag: @"tel"]; + + elements = [phones cardElementsWithAttribute: @"type" + havingValue: aType]; + + phone = nil; + + if ([elements count] > 0) + { + CardElement *ce; + int i; + + for (i = 0; i < [elements count]; i++) + { + ce = [elements objectAtIndex: i]; + phone = [ce value: 0]; + + if (!aTypeToExclude) + break; + + if (![ce hasAttribute: @"type" havingValue: aTypeToExclude]) + break; + + phone = nil; + } + } + + if (!phone) + phone = @""; + + return phone; +} + +- (int) getMessageTableChildproperty: (void **) data + atURL: (NSString *) childURL + withTag: (uint32_t) proptag + inFolder: (SOGoFolder *) folder + withFID: (uint64_t) fid +{ + NSString *stringValue; + uint32_t *longValue; + id child; + int rc; + + rc = MAPI_E_SUCCESS; + switch (proptag) { + case PR_ICON_INDEX: // TODO + longValue = talloc_zero(memCtx, uint32_t); + *longValue = 0x00000200; /* see http://msdn.microsoft.com/en-us/library/cc815472.aspx */ + *data = longValue; + break; + case PR_MESSAGE_CLASS_UNICODE: + *data = talloc_strdup(memCtx, "IPM.Contact"); + break; + // case PR_VD_NAME_UNICODE: + // *data = talloc_strdup(memCtx, "PR_VD_NAME_UNICODE"); + // break; + // case PR_EMS_AB_DXA_REMOTE_CLIENT_UNICODE: "Home:" ??? + // *data = talloc_strdup(memCtx, "PR_EMS..."); + // break; + case PR_SUBJECT_UNICODE: + *data = talloc_strdup(memCtx, "PR_SUBJECT..."); + break; + case PR_OAB_NAME_UNICODE: + *data = talloc_strdup(memCtx, "PR_OAB_NAME_UNICODE"); + break; + case PR_OAB_LANGID: + longValue = talloc_zero(memCtx, uint32_t); + *longValue = 1033; /* English US */ + *data = longValue; + break; + + case PR_TITLE_UNICODE: + child = [self lookupObject: childURL]; + stringValue = [[child vCard] title]; + *data = [stringValue asUnicodeInMemCtx: memCtx]; + break; + + case PR_COMPANY_NAME_UNICODE: + child = [self lookupObject: childURL]; + /* that's buggy but it's for the demo */ + stringValue = [[[child vCard] org] componentsJoinedByString: @", "]; + *data = [stringValue asUnicodeInMemCtx: memCtx]; + break; + + case 0x3001001f: // Full Name + case 0x81c2001f: // contact block title name + rc = [super getMessageTableChildproperty: data + atURL: childURL + withTag: PR_DISPLAY_NAME_UNICODE + inFolder: folder + withFID: fid]; + break; + case 0x81b0001f: // E-mail + child = [self lookupObject: childURL]; + stringValue = [[child vCard] preferredEMail]; + *data = [stringValue asUnicodeInMemCtx: memCtx]; + break; + case PR_BODY_UNICODE: + child = [self lookupObject: childURL]; + stringValue = [[child vCard] note]; + *data = [stringValue asUnicodeInMemCtx: memCtx]; + break; + + case PR_OFFICE_TELEPHONE_NUMBER_UNICODE: + child = [self lookupObject: childURL]; + stringValue = [self _phoneOfType: @"work" + excluding: @"fax" + inCard: [child vCard]]; + *data = [stringValue asUnicodeInMemCtx: memCtx]; + break; + case PR_HOME_TELEPHONE_NUMBER_UNICODE: + child = [self lookupObject: childURL]; + stringValue = [self _phoneOfType: @"home" + excluding: @"fax" + inCard: [child vCard]]; + *data = [stringValue asUnicodeInMemCtx: memCtx]; + break; + case PR_MOBILE_TELEPHONE_NUMBER_UNICODE: + child = [self lookupObject: childURL]; + stringValue = [self _phoneOfType: @"cell" + excluding: nil + inCard: [child vCard]]; + *data = [stringValue asUnicodeInMemCtx: memCtx]; + break; + case PR_PRIMARY_TELEPHONE_NUMBER_UNICODE: + child = [self lookupObject: childURL]; + stringValue = [self _phoneOfType: @"pref" + excluding: nil + inCard: [child vCard]]; + *data = [stringValue asUnicodeInMemCtx: memCtx]; + break; + + // case PR_POSTAL_ADDRESS_UNICODE: + // case PR_INTERNET_MESSAGE_ID_UNICODE: + // case PR_CAR_TELEPHONE_NUMBER_UNICODE: + // case PR_OTHER_TELEPHONE_NUMBER_UNICODE: + // case PR_BUSINESS_FAX_NUMBER_UNICODE: + // case PR_HOME_FAX_NUMBER_UNICODE: + // case PR_COMPANY_MAIN_PHONE_NUMBER_UNICODE: + // case PR_EMS_AB_GROUP_BY_ATTR_4_UNICODE: + // case PR_CALLBACK_TELEPHONE_NUMBER_UNICODE: + // case PR_DEPARTMENT_NAME_UNICODE: + // case PR_OFFICE2_TELEPHONE_NUMBER_UNICODE: + // case PR_RADIO_TELEPHONE_NUMBER_UNICODE: + // case PR_PAGER_TELEPHONE_NUMBER_UNICODE: + // case PR_PRIMARY_FAX_NUMBER_UNICODE: + // case PR_TELEX_NUMBER_UNICODE: + // case PR_ISDN_NUMBER_UNICODE: + // case PR_ASSISTANT_TELEPHONE_NUMBER_UNICODE: + // case PR_HOME2_TELEPHONE_NUMBER_UNICODE: + // case PR_TTYTDD_PHONE_NUMBER_UNICODE: + // case PR_BUSINESS_HOME_PAGE_UNICODE: + // *data = talloc_strdup(memCtx, "[Generic and fake unicode value]"); + // break; + +// (18:54:45) Wolfgang-: 0x80a7001f ( Business: ) -> don't ask me which "business" +// (18:55:05) Wolfgang-: 0x809c001f ( Other: ) +// (18:55:58) Wolfgang-: 0x81b5001f: E-mail 2 + + +// #define PR_REPLY_TIME PROP_TAG(PT_SYSTIME , 0x0030) /* 0x00300040 */ +// #define PR_SENSITIVITY PROP_TAG(PT_LONG , 0x0036) /* 0x00360003 */ +// #define PR_FOLLOWUP_ICON PROP_TAG(PT_LONG , 0x1095) /* 0x10950003 */ +// #define PR_SEARCH_KEY PROP_TAG(PT_BINARY , 0x300b) /* 0x300b0102 */ +// #define PR_VIEW_STYLE PROP_TAG(PT_LONG , 0x6834) /* 0x68340003 */ +// #define PR_VD_VERSION PROP_TAG(PT_LONG , 0x7007) /* 0x70070003 */ + + default: + rc = [super getMessageTableChildproperty: data + atURL: childURL + withTag: proptag + inFolder: folder + withFID: fid]; + } + + return rc; +} + +- (int) getFolderTableChildproperty: (void **) data + atURL: (NSString *) childURL + withTag: (uint32_t) proptag + inFolder: (SOGoFolder *) folder + withFID: (uint64_t) fid +{ + int rc; + + [self logWithFormat: @"XXXXX unexpected!!!!!!!!!"]; + rc = MAPI_E_SUCCESS; + switch (proptag) { + default: + rc = [super getFolderTableChildproperty: data + atURL: childURL + withTag: proptag + inFolder: folder + withFID: fid]; + } + + return rc; +} + +@end diff --git a/OpenChange/MAPIStoreContext.h b/OpenChange/MAPIStoreContext.h new file mode 100644 index 000000000..1e8d26ea9 --- /dev/null +++ b/OpenChange/MAPIStoreContext.h @@ -0,0 +1,131 @@ +/* MAPIStoreContext.h - this file is part of $PROJECT_NAME_HERE$ + * + * Copyright (C) 2010 Wolfgang Sourdeau + * + * 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 2, 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. + */ + +#ifndef MAPISTORECONTEXT_H +#define MAPISTORECONTEXT_H + +#import + +#define SENSITIVITY_NONE 0 +#define SENSITIVITY_PERSONAL 1 +#define SENSITIVITY_PRIVATE 2 +#define SENSITIVITY_COMPANY_CONFIDENTIAL 3 + +@class NSMutableDictionary; +@class NSString; + +@class WOContext; + +@class SOGoFolder; +@class SOGoObject; + +@class MAPIStoreAuthenticator; + +@interface MAPIStoreContext : NSObject +{ + NSMutableDictionary *objectCache; + MAPIStoreAuthenticator *authenticator; + WOContext *woContext; + NSMutableDictionary *messageCache; + NSMutableDictionary *subfolderCache; + SOGoFolder *moduleFolder; + void *memCtx; +} + ++ (id) contextFromURI: (const char *) newUri; + +- (void) setupModuleFolder; + +- (void) setMemCtx: (void *) newMemCtx; + +- (void) setAuthenticator: (MAPIStoreAuthenticator *) newAuthenticator; +- (MAPIStoreAuthenticator *) authenticator; + +- (void) setupRequest; +- (void) tearDownRequest; + +- (id) lookupObject: (NSString *) objectURLString; + +/* backend methods */ +- (int) getFID: (uint64_t *) fid + byName: (const char *) foldername + inParentFID: (uint64_t) parent_fid; + +- (int) getTableProperty: (void **) data + withTag: (uint32_t) proptag + atPosition: (uint32_t) pos + withTableType: (uint8_t) tableType + inFID: (uint64_t) fid; + +- (int) mkDir: (struct SRow *) aRow + withFID: (uint64_t) fid + inParentFID: (uint64_t) parentFID; +- (int) rmDirWithFID: (uint64_t) fid + inParentFID: (uint64_t) parentFid; +- (int) openDir: (uint64_t) fid + inParentFID: (uint64_t) parentFID; +- (int) closeDir; +- (int) readCount: (uint32_t *) rowCount + ofTableType: (uint8_t) tableType + inFID: (uint64_t) fid; +- (int) openMessage: (struct mapistore_message *) msg + withMID: (uint64_t) mid + inFID: (uint64_t) fid; +- (int) createMessageWithMID: (uint64_t) mid + inFID: (uint64_t) fid; +- (int) saveChangesInMessageWithMID: (uint64_t) mid + andFlags: (uint8_t) flags; +- (int) submitMessageWithMID: (uint64_t) mid + andFlags: (uint8_t) flags; +- (int) getProperties: (struct SPropTagArray *) SPropTagArray + inRow: (struct SRow *) aRow + withMID: (uint64_t) fmid + type: (uint8_t) tableType; +- (int) setPropertiesWithMID: (uint64_t) fmid + type: (uint8_t) type + inRow: (struct SRow *) aRow; +- (int) deleteMessageWithMID: (uint64_t) mid + withFlags: (uint8_t) flags; + +/* subclass methods */ + +- (int) getCommonTableChildproperty: (void **) data + atURL: (NSString *) childURL + withTag: (uint32_t) proptag + inFolder: (SOGoFolder *) folder + withFID: (uint64_t) fid; + +- (int) getMessageTableChildproperty: (void **) data + atURL: (NSString *) childURL + withTag: (uint32_t) proptag + inFolder: (SOGoFolder *) folder + withFID: (uint64_t) fid; + +- (int) getFolderTableChildproperty: (void **) data + atURL: (NSString *) childURL + withTag: (uint32_t) proptag + inFolder: (SOGoFolder *) folder + withFID: (uint64_t) fid; + +@end + +#endif /* MAPISTORECONTEXT_H */ diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m new file mode 100644 index 000000000..6fa48232d --- /dev/null +++ b/OpenChange/MAPIStoreContext.m @@ -0,0 +1,845 @@ +/* MAPIStoreContext.m - this file is part of $PROJECT_NAME_HERE$ + * + * Copyright (C) 2010 Wolfgang Sourdeau + * + * 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 2, 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 +#import + +#import +#import + +#import +#import +#import +#import + +#import "MAPIApplication.h" +#import "MAPIStoreAuthenticator.h" +#import "MAPIStoreMapping.h" + +#import "MAPIStoreContext.h" + +#import "NSString+MAPIStore.h" + +#undef DEBUG +#include +#include +// #include + + // NSNullK = NSClassFromString (@"NSNull"); + + // SOGoMailAccountsK = NSClassFromString (@"SOGoMailAccounts"); + // SOGoMailAccountK = NSClassFromString (@"SOGoMailAccount"); + // SOGoMailFolderK = NSClassFromString (@"SOGoMailFolder"); + // SOGoUserFolderK = NSClassFromString (@"SOGoUserFolder"); + +static Class SOGoObjectK, SOGoMailAccountK, SOGoMailFolderK; + +@interface SOGoFolder (MAPIStoreProtocol) + +- (BOOL) create; +- (NSException *) delete; + +@end + +@interface SOGoObject (MAPIStoreProtocol) + +- (NSString *) davContentLength; + +@end + +@implementation MAPIStoreContext : NSObject + +/* sogo://username:password@{contacts,calendar,tasks,journal,notes,mail}/dossier/id */ + +static MAPIStoreMapping *mapping = nil; + ++ (void) initialize +{ + SOGoObjectK = [SOGoObject class]; + SOGoMailAccountK = [SOGoMailAccount class]; + SOGoMailFolderK = [SOGoMailFolder class]; + mapping = [MAPIStoreMapping new]; +} + ++ (id) contextFromURI: (const char *) newUri +{ + MAPIStoreContext *context; + MAPIStoreAuthenticator *authenticator; + NSString *contextClass, *module, *completeURLString, *urlString; + NSURL *baseURL; + + NSLog (@"METHOD '%s' (%d) -- uri: '%s'", __FUNCTION__, __LINE__, newUri); + + context = nil; + + urlString = [NSString stringWithUTF8String: newUri]; + if (urlString) { + completeURLString = [@"sogo://" stringByAppendingString: urlString]; + baseURL = [NSURL URLWithString: completeURLString]; + if (baseURL) { + module = [baseURL host]; + if (module) { + if ([module isEqualToString: @"mail"]) + contextClass = @"MAPIStoreMailContext"; + else if ([module isEqualToString: @"contacts"]) + contextClass = @"MAPIStoreContactsContext"; + else if ([module isEqualToString: @"calendar"]) + contextClass = @"MAPIStoreCalendarContext"; + else { + NSLog (@"ERROR: unrecognized module name '%@'", module); + contextClass = nil; + } + + if (contextClass) { + [mapping registerURL: completeURLString]; + context = [NSClassFromString (contextClass) new]; + [context autorelease]; + + authenticator = [MAPIStoreAuthenticator new]; + [authenticator setUsername: [baseURL user]]; + [authenticator setPassword: [baseURL password]]; + [context setAuthenticator: authenticator]; + [authenticator release]; + + [context setupRequest]; + [context setupModuleFolder]; + [context tearDownRequest]; + } + } + } + else + NSLog (@"ERROR: url could not be parsed"); + } + else + NSLog (@"ERROR: url is an invalid UTF-8 string"); + + return context; +} + +- (id) init +{ + if ((self = [super init])) { + // objectCache = [NSMutableDictionary new]; + messageCache = [NSMutableDictionary new]; + subfolderCache = [NSMutableDictionary new]; + woContext = [WOContext contextWithRequest: nil]; + [woContext retain]; + moduleFolder = nil; + } + + [self logWithFormat: @"-init"]; + + return self; +} + +- (void) dealloc +{ + [self logWithFormat: @"-dealloc"]; + + // [objectCache release]; + [messageCache release]; + [subfolderCache release]; + + [moduleFolder release]; + [woContext release]; + [authenticator release]; + [super dealloc]; +} + +- (void) setAuthenticator: (MAPIStoreAuthenticator *) newAuthenticator +{ + ASSIGN (authenticator, newAuthenticator); +} + +- (MAPIStoreAuthenticator *) authenticator +{ + return authenticator; +} + +- (void) setMemCtx: (void *) newMemCtx +{ + memCtx = newMemCtx; +} + +- (void) setupRequest +{ + NSMutableDictionary *info; + + [MAPIApp setMAPIStoreContext: self]; + info = [[NSThread currentThread] threadDictionary]; + [info setObject: woContext forKey:@"WOContext"]; +} + +- (void) tearDownRequest +{ + NSMutableDictionary *info; + + info = [[NSThread currentThread] threadDictionary]; + [info removeObjectForKey:@"WOContext"]; + [MAPIApp setMAPIStoreContext: nil]; +} + +- (void) setupModuleFolder +{ + [self subclassResponsibility: _cmd]; +} + +- (id) lookupObject: (NSString *) objectURLString +{ + id object; + NSURL *objectURL; + NSArray *path; + int count, max; + NSString *pathString, *nameInContainer; + + // object = [objectCache objectForKey: objectURLString]; + // if (!object) { + objectURL = [NSURL URLWithString: objectURLString]; + if (!objectURL) + [self errorWithFormat: @"url string gave nil NSURL: '%@'", objectURLString]; + object = moduleFolder; + + pathString = [objectURL path]; + if ([pathString hasPrefix: @"/"]) + pathString = [pathString substringFromIndex: 1]; + if ([pathString length] > 0) { + path = [pathString componentsSeparatedByString: @"/"]; + max = [path count]; + if (max > 0) { + for (count = 0; + object && count < max; + count++) { + nameInContainer = [[path objectAtIndex: count] + stringByUnescapingURL]; + object = [object lookupName: nameInContainer + inContext: woContext + acquire: NO]; + if ([object isKindOfClass: SOGoObjectK]) + [woContext setClientObject: object]; + else + object = nil; + } + } + } else + object = nil; + + [woContext setClientObject: object]; + // if (object && [object isKindOfClass: SOGoObjectK]) + // [objectCache setObject: object + // forKey: objectURLString]; + // else { + // object = nil; + // [woContext setClientObject: nil]; + // } + + return object; +} + +- (NSString *) _createFolder: (struct SRow *) aRow + inParentURL: (NSString *) parentFolderURL +{ + NSString *newFolderURL; + NSString *folderName, *nameInContainer; + SOGoFolder *parentFolder, *newFolder; + int i; + + newFolderURL = nil; + + folderName = nil; + for (i = 0; !folderName && i < aRow->cValues; i++) { + if (aRow->lpProps[i].ulPropTag == PR_DISPLAY_NAME_UNICODE) { + folderName = [NSString stringWithUTF8String: aRow->lpProps[i].value.lpszW]; + } + else if (aRow->lpProps[i].ulPropTag == PR_DISPLAY_NAME) { + folderName = [NSString stringWithUTF8String: aRow->lpProps[i].value.lpszA]; + } + } + + if (folderName) { + parentFolder = [self lookupObject: parentFolderURL]; + if (parentFolder) { + if ([parentFolder isKindOfClass: SOGoMailAccountK] + || [parentFolder isKindOfClass: SOGoMailFolderK]) { + nameInContainer = [NSString stringWithFormat: @"folder%@", + [folderName asCSSIdentifier]]; + newFolder = [SOGoMailFolderK objectWithName: nameInContainer + inContainer: parentFolder]; + if ([newFolder create]) + newFolderURL = [NSString stringWithFormat: @"%@/%@", + parentFolderURL, + [nameInContainer stringByEscapingURL]]; + } + } + } + + return newFolderURL; +} + +/** + \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 + */ + +- (int) mkDir: (struct SRow *) aRow + withFID: (uint64_t) fid + inParentFID: (uint64_t) parentFID +{ + NSString *folderURL, *parentFolderURL; + int rc; + + [self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; + + folderURL = [mapping urlFromID: fid]; + if (folderURL) + rc = MAPISTORE_ERR_EXIST; + else { + parentFolderURL = [mapping urlFromID: parentFID]; + if (!parentFolderURL) + [self errorWithFormat: @"No url found for FID: %lld", parentFID]; + if (parentFolderURL) { + folderURL = [self _createFolder: aRow inParentURL: parentFolderURL]; + if (folderURL) { + [mapping registerURL: folderURL withID: fid]; + // if ([sogoFolder isKindOfClass: SOGoMailAccountK]) + // [sogoFolder subscribe]; + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + } + else + rc = MAPISTORE_ERR_NO_DIRECTORY; + } + + return rc; +} + + +/** + \details Delete a folder from the sogo backend + + \param private_data pointer to the current sogo context + \param parentFID 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 + */ +- (int) rmDirWithFID: (uint64_t) fid + inParentFID: (uint64_t) parentFid +{ + [self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; + + return MAPISTORE_SUCCESS; +} + + +/** + \details Open a folder from the sogo backend + + \param private_data pointer to the current sogo context + \param parentFID the parent folder identifier + \param fid the identifier of the colder to open + + \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR + */ +- (int) openDir: (uint64_t) fid + inParentFID: (uint64_t) parentFID +{ + [self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; + + return MAPISTORE_SUCCESS; +} + + +/** + \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 + */ +- (int) closeDir +{ + [self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; + + return MAPISTORE_SUCCESS; +} + +- (NSArray *) _messageKeysForFolderURL: (NSString *) folderURL +{ + NSArray *keys; + SOGoFolder *folder; + + keys = [messageCache objectForKey: folderURL]; + if (!keys) { + folder = [self lookupObject: folderURL]; + if (folder) + keys = [folder toOneRelationshipKeys]; + else + keys = (NSArray *) [NSNull null]; + [messageCache setObject: keys forKey: folderURL]; + } + + return keys; +} + +- (NSArray *) _subfolderKeysForFolderURL: (NSString *) folderURL +{ + NSArray *keys; + SOGoFolder *folder; + + keys = [subfolderCache objectForKey: folderURL]; + if (!keys) { + folder = [self lookupObject: folderURL]; + if (folder) { + keys = [folder toManyRelationshipKeys]; + if (!keys) + keys = (NSArray *) [NSNull null]; + } + else + keys = (NSArray *) [NSNull null]; + [subfolderCache setObject: keys forKey: folderURL]; + } + + return keys; +} + +/** + \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 + */ +- (int) readCount: (uint32_t *) rowCount + ofTableType: (uint8_t) tableType + inFID: (uint64_t) fid +{ + NSArray *ids; + NSString *url; + int rc; + + [self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; + + url = [mapping urlFromID: fid]; + if (!url) + [self errorWithFormat: @"No url found for FID: %lld", fid]; + + switch (tableType) { + case MAPISTORE_FOLDER_TABLE: + ids = [self _subfolderKeysForFolderURL: url]; + break; + case MAPISTORE_MESSAGE_TABLE: + ids = [self _messageKeysForFolderURL: url]; + break; + default: + rc = MAPISTORE_ERR_INVALID_PARAMETER; + ids = nil; + } + + if ([ids isKindOfClass: [NSArray class]]) { + rc = MAPI_E_SUCCESS; + *rowCount = [ids count]; + } + else + rc = MAPISTORE_ERR_NO_DIRECTORY; + + return rc; +} + +- (int) getCommonTableChildproperty: (void **) data + atURL: (NSString *) childURL + withTag: (uint32_t) proptag + inFolder: (SOGoFolder *) folder + withFID: (uint64_t) fid +{ + NSString *stringValue; + id child; + // uint64_t *llongValue; + // uint32_t *longValue; + int rc; + + rc = MAPI_E_SUCCESS; + switch (proptag) { + case PR_DISPLAY_NAME_UNICODE: + child = [self lookupObject: childURL]; + *data = [[child displayName] asUnicodeInMemCtx: memCtx]; + break; + default: + if ((proptag & 0x001F) == 0x001F) { + stringValue = [NSString stringWithFormat: @"Unhandled unicode value: 0x%x", proptag]; + *data = [stringValue asUnicodeInMemCtx: memCtx]; + [self errorWithFormat: @"Unknown proptag (returned): %.8x for child '%@'", + proptag, childURL]; + break; + } + else { + [self errorWithFormat: @"Unknown proptag: %.8x for child '%@'", + proptag, childURL]; + *data = NULL; + } + rc = MAPI_E_NOT_FOUND; + } + + return rc; +} + +- (int) getMessageTableChildproperty: (void **) data + atURL: (NSString *) childURL + withTag: (uint32_t) proptag + inFolder: (SOGoFolder *) folder + withFID: (uint64_t) fid +{ + uint32_t *longValue; + uint64_t *llongValue; + int rc; + + rc = MAPI_E_SUCCESS; + switch (proptag) { + case PR_INST_ID: // TODO: DOUBT + llongValue = talloc_zero(memCtx, uint64_t); + // *llongValue = 1; + *llongValue = [childURL hash]; /* we return a unique id based on the url */ + *data = llongValue; + break; + // case PR_INST_ID: // TODO: DOUBT + case PR_INSTANCE_NUM: // TODO: DOUBT + longValue = talloc_zero(memCtx, uint32_t); + *longValue = 0; + *data = longValue; + break; + case PR_VD_VERSION: + longValue = talloc_zero(memCtx, uint32_t); + *longValue = 8; /* mandatory value... wtf? */ + *data = longValue; + break; + // case PR_DEPTH: // TODO: DOUBT + // longValue = talloc_zero(memCtx, uint32_t); + // *longValue = 1; + // *data = longValue; + // break; + case PR_FID: + llongValue = talloc_zero(memCtx, uint64_t); + *llongValue = fid; + *data = llongValue; + case PR_MID: + llongValue = talloc_zero(memCtx, uint64_t); + *llongValue = [mapping idFromURL: childURL]; + if (*llongValue == NSNotFound) { + [mapping registerURL: childURL]; + *llongValue = [mapping idFromURL: childURL]; + } + *data = llongValue; + break; + + /* those are queried while they really pertain to the + addressbook module */ +// #define PR_OAB_LANGID PROP_TAG(PT_LONG , 0x6807) /* 0x68070003 */ + // case PR_OAB_NAME_UNICODE: + // case PR_OAB_CONTAINER_GUID_UNICODE: + +// 0x68420102 PidTagScheduleInfoDelegatorWantsCopy (BOOL) + + + default: + rc = [self getCommonTableChildproperty: data + atURL: childURL + withTag: proptag + inFolder: folder + withFID: fid]; + } + + return rc; +} + +- (NSString *) _parentURLFromURL: (NSString *) urlString +{ + NSString *newURL; + NSArray *parts; + NSMutableArray *newParts; + + parts = [urlString componentsSeparatedByString: @"/"]; + if ([parts count] > 3) { + newParts = [parts mutableCopy]; + [newParts autorelease]; + [newParts removeLastObject]; + newURL = [newParts componentsJoinedByString: @"/"]; + } + else + newURL = nil; + + return newURL; +} + +- (int) getFolderTableChildproperty: (void **) data + atURL: (NSString *) childURL + withTag: (uint32_t) proptag + inFolder: (SOGoFolder *) folder + withFID: (uint64_t) fid +{ + // id child; + uint64_t *llongValue; + uint8_t *boolValue; + uint32_t *longValue; + struct Binary_r *binaryValue; + int rc; + NSString *parentURL; + + rc = MAPI_E_SUCCESS; + switch (proptag) { + case PR_FID: + llongValue = talloc_zero(memCtx, uint64_t); + *llongValue = [mapping idFromURL: childURL]; + if (*llongValue == NSNotFound) { + [mapping registerURL: childURL]; + *llongValue = [mapping idFromURL: childURL]; + } + *data = llongValue; + break; + case PR_PARENT_FID: + llongValue = talloc_zero(memCtx, uint64_t); + parentURL = [self _parentURLFromURL: childURL]; + if (parentURL) { + *llongValue = [mapping idFromURL: childURL]; + if (*llongValue == NSNotFound) { + [mapping registerURL: childURL]; + *llongValue = [mapping idFromURL: childURL]; + } + *data = llongValue; + } + else { + *data = NULL; + rc = MAPISTORE_ERR_NOT_FOUND; + } + break; + case PR_ATTR_HIDDEN: + case PR_ATTR_SYSTEM: + case PR_ATTR_READONLY: + boolValue = talloc_zero(memCtx, uint8_t); + *boolValue = NO; + *data = boolValue; + break; + case PR_SUBFOLDERS: + boolValue = talloc_zero(memCtx, uint8_t); + *boolValue = ([[self _subfolderKeysForFolderURL: childURL] + count] > 0); + *data = boolValue; + break; + case PR_CONTENT_COUNT: + longValue = talloc_zero(memCtx, uint32_t); + *longValue = ([[self _messageKeysForFolderURL: childURL] + count] > 0); + *data = longValue; + break; + case PR_EXTENDED_FOLDER_FLAGS: // TODO: DOUBT: how to indicate the + // number of subresponses ? + binaryValue = talloc_zero(memCtx, struct Binary_r); + *data = binaryValue; + break; + default: + rc = [self getCommonTableChildproperty: data + atURL: childURL + withTag: proptag + inFolder: folder + withFID: fid]; + } + + return rc; +} + +- (int) getTableProperty: (void **) data + withTag: (uint32_t) proptag + atPosition: (uint32_t) pos + withTableType: (uint8_t) tableType + inFID: (uint64_t) fid +{ + NSArray *children; + NSString *folderURL, *childURL, *childName; + SOGoFolder *folder; + int rc; + + [self logWithFormat: @"METHOD '%s' (%d) -- proptag: 0x%.8x, pos: %ld, tableType: %d, fid: %lld", + __FUNCTION__, __LINE__, proptag, pos, tableType, fid]; + + folderURL = [mapping urlFromID: fid]; + if (folderURL) { + folder = [self lookupObject: folderURL]; + switch (tableType) { + case MAPISTORE_FOLDER_TABLE: + children = [self _subfolderKeysForFolderURL: folderURL]; + break; + case MAPISTORE_MESSAGE_TABLE: + children = [self _messageKeysForFolderURL: folderURL]; + break; + default: + children = nil; + break; + } + + if ([children count] > pos) { + childName = [children objectAtIndex: pos]; + childURL = [folderURL stringByAppendingFormat: @"/%@", + [childName stringByEscapingURL]]; + + if (tableType == MAPISTORE_FOLDER_TABLE) { + [self logWithFormat: @" querying child folder at URL: %@", childURL]; + rc = [self getFolderTableChildproperty: data + atURL: childURL + withTag: proptag + inFolder: folder + withFID: fid]; + } + else { + [self logWithFormat: @" querying child message at URL: %@", childURL]; + rc = [self getMessageTableChildproperty: data + atURL: childURL + withTag: proptag + inFolder: folder + withFID: fid]; + } + /* Unhandled: */ +// #define PR_EXPIRY_TIME PROP_TAG(PT_SYSTIME , 0x0015) /* 0x00150040 */ +// #define PR_REPLY_TIME PROP_TAG(PT_SYSTIME , 0x0030) /* 0x00300040 */ +// #define PR_SENSITIVITY PROP_TAG(PT_LONG , 0x0036) /* 0x00360003 */ +// #define PR_MESSAGE_DELIVERY_TIME PROP_TAG(PT_SYSTIME , 0x0e06) /* 0x0e060040 */ +// #define PR_FOLLOWUP_ICON PROP_TAG(PT_LONG , 0x1095) /* 0x10950003 */ +// #define PR_ITEM_TEMPORARY_FLAGS PROP_TAG(PT_LONG , 0x1097) /* 0x10970003 */ +// #define PR_SEARCH_KEY PROP_TAG(PT_BINARY , 0x300b) /* 0x300b0102 */ +// #define PR_CONTENT_COUNT PROP_TAG(PT_LONG , 0x3602) /* 0x36020003 */ +// #define PR_CONTENT_UNREAD PROP_TAG(PT_LONG , 0x3603) /* 0x36030003 */ +// #define PR_FID PROP_TAG(PT_I8 , 0x6748) /* 0x67480014 */ +// unknown 36de0003 http://social.msdn.microsoft.com/Forums/en-US/os_exchangeprotocols/thread/17c68add-1f62-4b68-9d83-f9ec7c1c6c9b +// unknown 819d0003 +// unknown 81f80003 +// unknown 81fa000b + + } + else + rc = MAPISTORE_ERROR; + } + else { + [self errorWithFormat: @"No url found for FID: %lld", fid]; + rc = MAPISTORE_ERR_NOT_FOUND; + } + + return rc; +} + + +- (int) openMessage: (struct mapistore_message *) msg + withMID: (uint64_t) mid + inFID: (uint64_t) fid +{ + [self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; + + return MAPI_E_SUCCESS; +} + +- (int) createMessageWithMID: (uint64_t) mid + inFID: (uint64_t) fid +{ + [self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; + + return MAPI_E_SUCCESS; +} + +- (int) saveChangesInMessageWithMID: (uint64_t) mid + andFlags: (uint8_t) flags +{ + [self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; + + return MAPI_E_SUCCESS; +} + +- (int) submitMessageWithMID: (uint64_t) mid + andFlags: (uint8_t) flags +{ + [self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; + + return MAPI_E_SUCCESS; +} + +- (int) getProperties: (struct SPropTagArray *) SPropTagArray + inRow: (struct SRow *) aRow + withMID: (uint64_t) fmid + type: (uint8_t) tableType +{ + [self logWithFormat: @"METHOD '%s' (%d) -- tableType: %d, mid: %lld", + __FUNCTION__, __LINE__, tableType, fmid]; + + switch (tableType) { + case MAPISTORE_FOLDER: + break; + case MAPISTORE_MESSAGE: + break; + } + + return MAPI_E_SUCCESS; +} + +- (int) getFID: (uint64_t *) fid + byName: (const char *) foldername + inParentFID: (uint64_t) parent_fid +{ + [self logWithFormat: @"METHOD '%s' (%d) -- foldername: %s, parent_fid: %lld", + __FUNCTION__, __LINE__, foldername, parent_fid]; + + return MAPISTORE_ERR_INVALID_PARAMETER; +} + +- (int) setPropertiesWithMID: (uint64_t) fmid + type: (uint8_t) type + inRow: (struct SRow *) aRow +{ + [self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; + + switch (type) { + case MAPISTORE_FOLDER: + break; + case MAPISTORE_MESSAGE: + break; + } + + return MAPI_E_SUCCESS; +} + +- (int) deleteMessageWithMID: (uint64_t) mid + withFlags: (uint8_t) flags +{ + [self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; + + return MAPI_E_SUCCESS; +} + +@end diff --git a/OpenChange/MAPIStoreMailContext.h b/OpenChange/MAPIStoreMailContext.h new file mode 100644 index 000000000..d2c47475e --- /dev/null +++ b/OpenChange/MAPIStoreMailContext.h @@ -0,0 +1,32 @@ +/* MAPIStoreMailContext.h - 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 2, 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. + */ + +#ifndef MAPISTOREMAILCONTEXT_H +#define MAPISTOREMAILCONTEXT_H + +#import "MAPIStoreContext.h" + +@interface MAPIStoreMailContext : MAPIStoreContext + +@end + +#endif /* MAPISTOREMAILCONTEXT_H */ diff --git a/OpenChange/MAPIStoreMailContext.m b/OpenChange/MAPIStoreMailContext.m new file mode 100644 index 000000000..46fa84c38 --- /dev/null +++ b/OpenChange/MAPIStoreMailContext.m @@ -0,0 +1,211 @@ +/* MAPIStoreMailContext.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 2, 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 "MAPIApplication.h" +#import "MAPIStoreAuthenticator.h" +#import "NSCalendarDate+MAPIStore.h" +#import "NSString+MAPIStore.h" + +#import "MAPIStoreMailContext.h" + +#undef DEBUG +#include + +static Class SOGoUserFolderK; + +@implementation MAPIStoreMailContext + ++ (void) initialize +{ + SOGoUserFolderK = [SOGoUserFolderK class]; +} + +- (void) setupModuleFolder +{ + id userFolder, accountsFolder; + + userFolder = [SOGoUserFolderK objectWithName: [authenticator username] + inContainer: MAPIApp]; + [woContext setClientObject: userFolder]; + [userFolder retain]; // LEAK + + accountsFolder = [userFolder lookupName: @"Mail" + inContext: woContext + acquire: NO]; + [woContext setClientObject: accountsFolder]; + [accountsFolder retain]; // LEAK + + moduleFolder = [accountsFolder lookupName: @"0" + inContext: woContext + acquire: NO]; + [moduleFolder retain]; +} + +// - (int) getCommonTableChildproperty: (void **) data +// atURL: (NSString *) childURL +// withTag: (uint32_t) proptag +// inFolder: (SOGoFolder *) folder +// withFID: (uint64_t) fid +// { +// int rc; + +// rc = MAPI_E_SUCCESS; +// switch (proptag) { +// default: +// rc = [super getCommonTableChildproperty: data +// atURL: childURL +// withTag: proptag +// inFolder: folder +// withFID: fid]; +// } + +// return rc; +// } + +- (int) getMessageTableChildproperty: (void **) data + atURL: (NSString *) childURL + withTag: (uint32_t) proptag + inFolder: (SOGoFolder *) folder + withFID: (uint64_t) fid +{ + uint8_t *boolValue; + uint32_t *longValue; + SOGoMailObject *child; + NSCalendarDate *offsetDate; + int rc; + + rc = MAPI_E_SUCCESS; + switch (proptag) { + case PR_ICON_INDEX: // TODO + longValue = talloc_zero(memCtx, uint32_t); + *longValue = 0x00000100; /* read mail, see http://msdn.microsoft.com/en-us/library/cc815472.aspx */ + *data = longValue; + break; + case PR_SUBJECT_UNICODE: + child = [self lookupObject: childURL]; + *data = [[child decodedSubject] asUnicodeInMemCtx: memCtx]; + break; + case PR_MESSAGE_CLASS_UNICODE: + *data = talloc_strdup(memCtx, "IPM.Note"); + break; + case PR_HASATTACH: + boolValue = talloc_zero(memCtx, uint8_t); + *boolValue = NO; + *data = boolValue; + break; + case PR_MESSAGE_DELIVERY_TIME: + child = [self lookupObject: childURL]; + offsetDate = [[child date] addYear: -1 month: 0 day: 0 + hour: 0 minute: 0 second: 0]; + *data = [offsetDate asFileTimeInMemCtx: memCtx]; + break; + // case PR_ROW_TYPE: // TODO: DOUBT + // longValue = talloc_zero(memCtx, uint32_t); + // *longValue = 1; + // *data = longValue; + // break; + case PR_FLAG_STATUS: // TODO + case PR_MSG_STATUS: // TODO + case PR_MESSAGE_FLAGS: // TODO + case PR_SENSITIVITY: // TODO + longValue = talloc_zero(memCtx, uint32_t); + *longValue = 0; + *data = longValue; + break; + case PR_IMPORTANCE: + longValue = talloc_zero(memCtx, uint32_t); + *longValue = 1; + *data = longValue; + break; + case PR_MESSAGE_SIZE: // TODO + child = [self lookupObject: childURL]; + longValue = talloc_zero(memCtx, uint32_t); + /* TODO: choose another name for that method */ + *longValue = [[child davContentLength] intValue]; + *data = longValue; + break; +// #define PR_REPLY_TIME PROP_TAG(PT_SYSTIME , 0x0030) /* 0x00300040 */ +// #define PR_EXPIRY_TIME PROP_TAG(PT_SYSTIME , 0x0015) /* 0x00150040 */ +// #define PR_MESSAGE_DELIVERY_TIME PROP_TAG(PT_SYSTIME , 0x0e06) /* 0x0e060040 */ +// #define PR_FOLLOWUP_ICON PROP_TAG(PT_LONG , 0x1095) /* 0x10950003 */ +// #define PR_ITEM_TEMPORARY_FLAGS PROP_TAG(PT_LONG , 0x1097) /* 0x10970003 */ +// #define PR_SEARCH_KEY PROP_TAG(PT_BINARY , 0x300b) /* 0x300b0102 */ + + + + case PR_SENT_REPRESENTING_NAME_UNICODE: + child = [self lookupObject: childURL]; + *data = [[child from] asUnicodeInMemCtx: memCtx]; + break; + case PR_INTERNET_MESSAGE_ID_UNICODE: + child = [self lookupObject: childURL]; + *data = [[child messageId] asUnicodeInMemCtx: memCtx]; + break; + default: + rc = [super getMessageTableChildproperty: data + atURL: childURL + withTag: proptag + inFolder: folder + withFID: fid]; + } + + return rc; +} + +- (int) getFolderTableChildproperty: (void **) data + atURL: (NSString *) childURL + withTag: (uint32_t) proptag + inFolder: (SOGoFolder *) folder + withFID: (uint64_t) fid +{ + uint32_t *longValue; + int rc; + + rc = MAPI_E_SUCCESS; + switch (proptag) { + case PR_CONTENT_UNREAD: + longValue = talloc_zero(memCtx, uint32_t); + *longValue = 0; + *data = longValue; + break; + case PR_CONTAINER_CLASS_UNICODE: + *data = talloc_strdup(memCtx, "IPF.Note"); + break; + default: + rc = [super getFolderTableChildproperty: data + atURL: childURL + withTag: proptag + inFolder: folder + withFID: fid]; + } + + return rc; +} + +@end diff --git a/OpenChange/MAPIStoreMapping.h b/OpenChange/MAPIStoreMapping.h new file mode 100644 index 000000000..eccbb3cad --- /dev/null +++ b/OpenChange/MAPIStoreMapping.h @@ -0,0 +1,46 @@ +/* MAPIStoreMapping.h - this file is part of $PROJECT_NAME_HERE$ + * + * 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 2, 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. + */ + +#ifndef MAPISTOREMAPPING_H +#define MAPISTOREMAPPING_H + +#import + +@class NSMutableDictionary; +@class NSString; + +@interface MAPIStoreMapping : NSObject +{ + NSMutableDictionary *mapping; /* FID/MID -> url */ + NSMutableDictionary *reverseMapping; /* url -> FID/MID */ +} + +- (NSString *) urlFromID: (uint64_t) idKey; + +- (uint64_t) idFromURL: (NSString *) url; +- (BOOL) registerURL: (NSString *) urlString + withID: (uint64_t) idNbr; +- (void) registerURL: (NSString *) urlString; + +@end + +#endif /* MAPISTOREMAPPING_H */ diff --git a/OpenChange/MAPIStoreMapping.m b/OpenChange/MAPIStoreMapping.m new file mode 100644 index 000000000..f0a4282e6 --- /dev/null +++ b/OpenChange/MAPIStoreMapping.m @@ -0,0 +1,136 @@ +/* MAPIStoreMapping.m - this file is part of $PROJECT_NAME_HERE$ + * + * 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 2, 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 "MAPIStoreMapping.h" + +static const uint64_t idIncrement = 0x010000; /* we choose a high enough id to avoid any clash with system folders */ +static uint64_t idCounter = 0x200001; + +@implementation MAPIStoreMapping + +- (id) init +{ + if ((self = [super init])) { + mapping = [NSMutableDictionary new]; + reverseMapping = [NSMutableDictionary new]; + } + + return self; +} + +- (void) dealloc +{ + [mapping release]; + [reverseMapping release]; + [super dealloc]; +} + +- (NSString *) urlFromID: (uint64_t) idNbr +{ + NSNumber *key; + + key = [NSNumber numberWithUnsignedLongLong: idNbr]; + + return [mapping objectForKey: key]; +} + +- (uint64_t) idFromURL: (NSString *) url +{ + NSNumber *idKey; + uint64_t idNbr; + + idKey = [reverseMapping objectForKey: url]; + if (idKey) + idNbr = [idKey unsignedLongLongValue]; + else + idNbr = NSNotFound; + + return idNbr; +} + +- (BOOL) registerURL: (NSString *) urlString + withID: (uint64_t) idNbr +{ + NSNumber *idKey; + BOOL rc; + + idKey = [NSNumber numberWithUnsignedLongLong: idNbr]; + if ([mapping objectForKey: idKey] || [reverseMapping objectForKey: urlString]) { + [self errorWithFormat: @"attempt to double register an entry ('%@', %lld)", + urlString, idNbr]; + rc = NO; + } + else { + [mapping setObject: urlString forKey: idKey]; + [reverseMapping setObject: idKey forKey: urlString]; + rc = YES; + [self logWithFormat: @"registered url '%@' with id %lld (0x%.8x)", + urlString, idNbr, (uint32_t) idNbr]; + } + + return rc; +} + +- (void) registerURL: (NSString *) urlString +{ + uint64_t idNbr; + + // newID = openchangedb_get_new_folderID(); + if (![reverseMapping objectForKey: urlString]) { + if ([urlString isEqualToString: @"sogo://openchange:openchange@mail/folderINBOX"]) { + idNbr = 0x160001; + if (![self registerURL: urlString withID: idNbr]) + [self errorWithFormat: @"Unable to register root folder: %@", + urlString]; + } + // else if ([urlString isEqualToString: @"sogo://openchange:openchange@mail/folderSent"]) { + // idNbr = 0x140001; + // idCounter = idNbr; + // } + else if ([urlString isEqualToString: @"sogo://openchange:openchange@contacts/personal"]) { + idNbr = 0x1a0001; + if (![self registerURL: urlString withID: idNbr]) + [self errorWithFormat: @"Unable to register root folder: %@", + urlString]; + } + else if ([urlString isEqualToString: @"sogo://openchange:openchange@calendar/personal"]) { + idNbr = 0x190001; + if (![self registerURL: urlString withID: idNbr]) + [self errorWithFormat: @"Unable to register root folder: %@", + urlString]; + } + else { + idCounter += idIncrement; + while (![self registerURL: urlString withID: idCounter]) + idCounter += idIncrement; + } + // [self _registerURL: urlString withID: newID]; + } +} + +@end diff --git a/OpenChange/MAPIStoreSOGo.h b/OpenChange/MAPIStoreSOGo.h new file mode 100644 index 000000000..ae6fda84f --- /dev/null +++ b/OpenChange/MAPIStoreSOGo.h @@ -0,0 +1,38 @@ +#ifndef __MAPISTORE_SOGO_H +#define __MAPISTORE_SOGO_H + +#include +#include +#include + +/* These are essentially local versions of part of the + C99 __STDC_FORMAT_MACROS */ +#ifndef PRIx64 +#if __WORDSIZE == 64 + #define PRIx64 "lx" +#else + #define PRIx64 "llx" +#endif +#endif + +#ifndef PRIX64 +#if __WORDSIZE == 64 + #define PRIX64 "lX" +#else + #define PRIX64 "llX" +#endif +#endif + +@class MAPIStoreContext; + +typedef struct { + MAPIStoreContext *objcContext; +} sogo_context; + +__BEGIN_DECLS + +int mapistore_init_backend(void); + +__END_DECLS + +#endif /* !__MAPISTORE_SOGO_H */ diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m new file mode 100644 index 000000000..1584fd3ef --- /dev/null +++ b/OpenChange/MAPIStoreSOGo.m @@ -0,0 +1,580 @@ +/* + OpenChange Storage Abstraction Layer library + SOGo backend + + OpenChange Project + + Copyright (C) + + This program 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 of the License, or + (at your option) any later version. + + This program 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. If not, see . + */ + +#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; + + pool = [NSAutoreleasePool new]; + [MAPIApplication 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; + MAPIStoreContext *context; + + pool = [NSAutoreleasePool new]; + + DEBUG(0, ("[%s:%d]\n", __FUNCTION__, __LINE__)); + + context = [MAPIStoreContext contextFromURI: uri]; + [context setMemCtx: mem_ctx]; + [context retain]; + + cContext = talloc_zero(mem_ctx, sogo_context); + cContext->objcContext = context; + *private_data = cContext; + + [pool release]; + + return MAPISTORE_SUCCESS; +} + + +/** + \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, ("[%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; + + pool = [NSAutoreleasePool new]; + + DEBUG(5, ("[%s:%d]\n", __FUNCTION__, __LINE__)); + + switch (type) { + case MAPISTORE_FOLDER: + break; + case MAPISTORE_MESSAGE: + break; + } + + [pool release]; + + return MAPISTORE_SUCCESS; +} + + +/** + \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; + + pool = [NSAutoreleasePool new]; + + DEBUG(5, ("[%s:%d]\n", __FUNCTION__, __LINE__)); + + switch (type) { + case MAPISTORE_FOLDER: + break; + case MAPISTORE_MESSAGE: + break; + } + + [pool release]; + + return MAPISTORE_SUCCESS; +} + +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; + + 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; + + 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; + + 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; + + 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; + + 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; + + 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, + uint32_t pos, + uint32_t proptag, + void **data) +{ + NSAutoreleasePool *pool; + sogo_context *cContext; + MAPIStoreContext *context; + int rc; + + pool = [NSAutoreleasePool new]; + + cContext = private_data; + context = cContext->objcContext; + [context setupRequest]; + + rc = [context getTableProperty: data withTag: proptag atPosition: pos + withTableType: table_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; + + pool = [NSAutoreleasePool new]; + + cContext = private_data; + context = cContext->objcContext; + [context setupRequest]; + + rc = [context openMessage: msg withMID: mid inFID: fid]; + + [context tearDownRequest]; + [pool release]; + + return rc; +} + + +static int sogo_op_createmessage(void *private_data, + uint64_t fid, + uint64_t mid) +{ + NSAutoreleasePool *pool; + sogo_context *cContext; + MAPIStoreContext *context; + int rc; + + pool = [NSAutoreleasePool new]; + + cContext = private_data; + context = cContext->objcContext; + [context setupRequest]; + + rc = [context createMessageWithMID: mid inFID: fid]; + + [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; + + 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; + + 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; + + pool = [NSAutoreleasePool new]; + + cContext = private_data; + context = cContext->objcContext; + [context setupRequest]; + + rc = [context getProperties: SPropTagArray inRow: aRow withMID: fmid type: type]; + + [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; + + pool = [NSAutoreleasePool new]; + + cContext = private_data; + context = cContext->objcContext; + [context setupRequest]; + + rc = [context setPropertiesWithMID: fmid type: type inRow: aRow]; + + [context tearDownRequest]; + [pool release]; + + return rc; +} + +static int sogo_op_deletemessage(void *private_data, + uint64_t mid, + uint8_t flags) +{ + NSAutoreleasePool *pool; + sogo_context *cContext; + MAPIStoreContext *context; + int rc; + + pool = [NSAutoreleasePool new]; + + cContext = private_data; + context = cContext->objcContext; + [context setupRequest]; + + rc = [context deleteMessageWithMID: mid withFlags: flags]; + + [context tearDownRequest]; + [pool release]; + + 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; + + /* Fill in our name */ + backend.name = "sogo"; + backend.description = "mapistore sogo backend"; + backend.namespace = "sogo://"; + + /* Fill in all the operations */ + 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_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_openmessage = sogo_op_openmessage; + backend.op_createmessage = sogo_op_createmessage; + backend.op_savechangesmessage = sogo_op_savechangesmessage; + backend.op_submitmessage = sogo_op_submitmessage; + backend.op_getprops = sogo_op_getprops; + backend.op_get_fid_by_name = sogo_op_get_fid_by_name; + backend.op_setprops = sogo_op_setprops; + backend.op_deletemessage = sogo_op_deletemessage; + + /* 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; +} diff --git a/OpenChange/NSCalendarDate+MAPIStore.h b/OpenChange/NSCalendarDate+MAPIStore.h new file mode 100644 index 000000000..5fc03b56d --- /dev/null +++ b/OpenChange/NSCalendarDate+MAPIStore.h @@ -0,0 +1,34 @@ +/* NSCalendarDate+MAPIStore.h - 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 2, 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. + */ + +#ifndef NSCALENDARDATE_MAPISTORE_H +#define NSCALENDARDATE_MAPISTORE_H + +#import + +@interface NSCalendarDate (MAPIStoreDataTypes) + +- (struct FILETIME *) asFileTimeInMemCtx: (void *) memCtx; + +@end + +#endif /* NSCALENDARDATE+MAPISTORE_H */ diff --git a/OpenChange/NSCalendarDate+MAPIStore.m b/OpenChange/NSCalendarDate+MAPIStore.m new file mode 100644 index 000000000..bed237679 --- /dev/null +++ b/OpenChange/NSCalendarDate+MAPIStore.m @@ -0,0 +1,56 @@ +/* NSCalendarDate+MAPIStore.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 2, 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 "NSCalendarDate+MAPIStore.h" + +#undef DEBUG +#include +#include + +@implementation NSCalendarDate (MAPIStoreDataTypes) + +- (struct FILETIME *) asFileTimeInMemCtx: (void *) memCtx +{ + static NSCalendarDate *refDate = nil; + struct FILETIME *timeValue; + NSTimeZone *utc; + uint64_t interval; + + if (!refDate) { + utc = [NSTimeZone timeZoneWithName: @"UTC"]; + refDate = [NSCalendarDate dateWithYear: 1601 month: 1 day: 1 + hour: 0 minute: 0 second: 0 + timeZone: utc]; + [refDate retain]; + } + interval = (((uint64_t) [self timeIntervalSinceDate: refDate]) * 10000000); + timeValue = talloc_zero(memCtx, struct FILETIME); + timeValue->dwLowDateTime = (uint32_t) (interval & 0xffffffff); + timeValue->dwHighDateTime = (uint32_t) ((interval >> 32) & 0xffffffff); + + return timeValue; +} + +@end diff --git a/OpenChange/NSString+MAPIStore.h b/OpenChange/NSString+MAPIStore.h new file mode 100644 index 000000000..f7e47958f --- /dev/null +++ b/OpenChange/NSString+MAPIStore.h @@ -0,0 +1,34 @@ +/* NSString+MAPIStore.h - 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 2, 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. + */ + +#ifndef NSSTRING_MAPISTORE_H +#define NSSTRING_MAPISTORE_H + +#import + +@interface NSString (MAPIStoreDataTypes) + +- (char *) asUnicodeInMemCtx: (void *) memCtx; + +@end + +#endif /* NSSTRING+MAPISTORE_H */ diff --git a/OpenChange/NSString+MAPIStore.m b/OpenChange/NSString+MAPIStore.m new file mode 100644 index 000000000..fcb4eca1e --- /dev/null +++ b/OpenChange/NSString+MAPIStore.m @@ -0,0 +1,38 @@ +/* NSString+MAPIStore.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 2, 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. + */ + +#include + +#import "NSString+MAPIStore.h" + +@implementation NSString (MAPIStoreDataTypes) + +- (char *) asUnicodeInMemCtx: (void *) memCtx +{ + char *unicode; + + unicode = talloc_strdup(memCtx, [self UTF8String]); + + return unicode; +} + +@end