/* MAPIStoreContactsMessage.m - this file is part of SOGo * * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * Ludovic Marcotte * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #import #import #import #import #import #import #import #import #import #import #import #import #import #import "MAPIStoreAttachment.h" #import "MAPIStoreContactsAttachment.h" #import "MAPIStoreContactsFolder.h" #import "MAPIStorePropertySelectors.h" #import "MAPIStoreTypes.h" #import "NSArray+MAPIStore.h" #import "NSDate+MAPIStore.h" #import "NSData+MAPIStore.h" #import "NSObject+MAPIStore.h" #import "NSString+MAPIStore.h" #import "MAPIStoreContactsMessage.h" #undef DEBUG #include #include #include #include #include @implementation SOGoContactGCSEntry (MAPIStoreExtension) - (Class) mapistoreMessageClass { return [MAPIStoreContactsMessage class]; } @end @implementation MAPIStoreContactsMessage - (id) init { if ((self = [super init])) { fetchedAttachments = NO; } return self; } // TODO: this should be combined with the version found // in UIxContactEditor.m - (CardElement *) _elementWithTag: (NSString *) tag ofType: (NSString *) type forCard: (NGVCard *) card { NSArray *elements; CardElement *element; elements = [card childrenWithTag: tag andAttribute: @"type" havingValue: type]; if ([elements count] > 0) element = [elements objectAtIndex: 0]; else { element = [CardElement new]; [element autorelease]; [element setTag: tag]; [element addType: type]; [card addChild: element]; } return element; } - (int) getPidTagIconIndex: (void **) data // TODO inMemCtx: (TALLOC_CTX *) memCtx { /* see http://msdn.microsoft.com/en-us/library/cc815472.aspx */ *data = MAPILongValue (memCtx, 0x00000200); return MAPISTORE_SUCCESS; } - (int) getPidTagAlternateRecipientAllowed: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getYes: data inMemCtx: memCtx]; } - (int) getPidTagMessageFlags: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { *data = MAPILongValue (memCtx, MSGFLAG_READ); return MAPISTORE_SUCCESS; } - (int) getPidTagDeleteAfterSubmit: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getNo: data inMemCtx: memCtx]; } - (int) getPidTagMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { *data = talloc_strdup (memCtx, "IPM.Contact"); return MAPISTORE_SUCCESS; } // - (int) getPidTagOfflineAddressBookName: (void **) data // inMemCtx: (TALLOC_CTX *) memCtx // { // *data = talloc_strdup (memCtx, "PR_OAB_NAME_UNICODE"); // return MAPISTORE_SUCCESS; // } // - (int) getPidTagOfflineAddressBookLanguageId: (void **) data // inMemCtx: (TALLOC_CTX *) memCtx // { // /* see http://msdn.microsoft.com/en-us/goglobal/bb895996.asxp */ // /* English US */ // *data = MAPILongValue (memCtx, 0x0409); // return MAPISTORE_SUCCESS; // } - (int) getPidTagTitle: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; stringValue = [[sogoObject vCard] title]; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagProfession: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; int rc = MAPISTORE_SUCCESS; stringValue = [[sogoObject vCard] role]; if (stringValue) *data = [stringValue asUnicodeInMemCtx: memCtx]; else rc = MAPISTORE_ERR_NOT_FOUND; return rc; } - (int) getPidTagCompanyName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { CardElement *org; org = [[sogoObject vCard] org]; *data = [[org flattenedValueAtIndex: 0 forKey: @""] asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagDepartmentName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { CardElement *org; org = [[sogoObject vCard] org]; *data = [[org flattenedValueAtIndex: 1 forKey: @""] asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagSendInternetEncoding: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { *data = MAPILongValue (memCtx, 0x00065001); return MAPISTORE_SUCCESS; } - (int) getPidTagNormalizedSubject: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getPidTagDisplayName: data inMemCtx: memCtx]; } - (int) getPidLidFileUnder: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *surName, *givenName, *middleName; NSMutableString *fileUnder; CardElement *n; n = [[sogoObject vCard] n]; surName = [n flattenedValueAtIndex: 0 forKey: @""]; fileUnder = [surName mutableCopy]; [fileUnder autorelease]; [fileUnder appendString: @","]; givenName = [n flattenedValueAtIndex: 1 forKey: @""]; if ([givenName length] > 0) [fileUnder appendFormat: @" %@", givenName]; middleName = [n flattenedValueAtIndex: 2 forKey: @""]; if ([middleName length] > 0) [fileUnder appendFormat: @" %@", middleName]; *data = [fileUnder asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidLidFileUnderId: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { *data = MAPILongValue (memCtx, 0x00008017); /* what ol2003 sets */ return MAPISTORE_SUCCESS; } - (int) getPidLidEmail1DisplayName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NGVCard *vCard; NSString *fn, *email; vCard = [sogoObject vCard]; fn = [vCard fn]; email = [vCard preferredEMail]; *data = [[NSString stringWithFormat: @"%@ (%@)", fn, email] asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidLidEmail1OriginalDisplayName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getPidLidEmail1EmailAddress: data inMemCtx: memCtx]; } - (int) getPidLidEmail1EmailAddress: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; stringValue = [[sogoObject vCard] preferredEMail]; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagAccount: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getPidLidEmail1EmailAddress: data inMemCtx: memCtx]; } - (int) getPidTagContactEmailAddresses: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; stringValue = [[sogoObject vCard] preferredEMail]; if (!stringValue) stringValue = @""; *data = [[NSArray arrayWithObject: stringValue] asMVUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagEmsAbTargetAddress: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; stringValue = [[sogoObject vCard] preferredEMail]; *data = [[NSString stringWithFormat: @"SMTP:%@", stringValue] asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagSearchKey: (void **) data // TODO inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; stringValue = [[sogoObject vCard] preferredEMail]; *data = [[stringValue dataUsingEncoding: NSASCIIStringEncoding] asBinaryInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagMailPermission: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getYes: data inMemCtx: memCtx]; } - (int) getPidLidEmail2EmailAddress: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSMutableArray *emails; NSString *email, *stringValue; NGVCard *card; NSUInteger count, max; emails = [NSMutableArray array]; stringValue = nil; card = [sogoObject vCard]; [emails addObjectsFromArray: [card childrenWithTag: @"email"]]; [emails removeObjectsInArray: [card childrenWithTag: @"email" andAttribute: @"type" havingValue: @"pref"]]; max = [emails count]; for (count = 0; !stringValue && count < max; count++) { email = [[emails objectAtIndex: count] flattenedValuesForKey: @""]; if ([email caseInsensitiveCompare: [card preferredEMail]] != NSOrderedSame) stringValue = email; } if (!stringValue) stringValue = @""; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidLidEmail2OriginalDisplayName: (void **) data // Other email inMemCtx: (TALLOC_CTX *) memCtx { return [self getPidLidEmail2EmailAddress: data inMemCtx: memCtx]; } - (int) getPidTagBody: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { int rc = MAPISTORE_SUCCESS; NSString *stringValue; stringValue = [[sogoObject vCard] note]; if ([stringValue length] > 0) *data = [stringValue asUnicodeInMemCtx: memCtx]; else rc = MAPISTORE_ERR_NOT_FOUND; return rc; } - (int) _getElement: (NSString *) elementTag ofType: (NSString *) aType excluding: (NSString *) aTypeToExclude atPos: (NSUInteger) pos inData: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSArray *elements; CardElement *ce; NSUInteger count, max; NGVCard *vCard; NSString *stringValue; stringValue = nil; vCard = [sogoObject vCard]; elements = [[vCard childrenWithTag: elementTag] cardElementsWithAttribute: @"type" havingValue: aType]; max = [elements count]; for (count = 0; !stringValue && count < max; count++) { ce = [elements objectAtIndex: count]; if (!aTypeToExclude || ![ce hasAttribute: @"type" havingValue: aTypeToExclude]) stringValue = [ce flattenedValueAtIndex: pos forKey: @""]; } if (!stringValue) stringValue = @""; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagBusinessTelephoneNumber: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"tel" ofType: @"work" excluding: @"fax" atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidTagHomeTelephoneNumber: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"tel" ofType: @"home" excluding: @"fax" atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidTagMobileTelephoneNumber: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"tel" ofType: @"cell" excluding: nil atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidTagPagerTelephoneNumber: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"tel" ofType: @"pager" excluding: nil atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidTagPrimaryTelephoneNumber: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"tel" ofType: @"pref" excluding: nil atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidTagBusinessFaxNumber: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"tel" ofType: @"fax" excluding: nil atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidTagBusinessHomePage: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"url" ofType: @"work" excluding: nil atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidTagPersonalHomePage: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"url" ofType: @"home" excluding: nil atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidLidEmail1AddressType: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getSMTPAddrType: data inMemCtx: memCtx]; } - (int) getPidLidEmail2AddressType: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getSMTPAddrType: data inMemCtx: memCtx]; } - (int) getPidLidEmail3AddressType: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getSMTPAddrType: data inMemCtx: memCtx]; } - (int) getPidLidInstantMessagingAddress: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-aim"] flattenedValuesForKey: @""]; if (!stringValue) stringValue = @""; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidLidPostalAddressId: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSArray *elements; CardElement *element; uint32_t longValue = 0; NGVCard *vCard; vCard = [sogoObject vCard]; elements = [[vCard childrenWithTag: @"adr"] cardElementsWithAttribute: @"type" havingValue: @"pref"]; if ([elements count] > 0) { element = [elements objectAtIndex: 0]; if ([element hasAttribute: @"type" havingValue: @"home"]) longValue = 1; // The Home Address is the mailing address. else if ([element hasAttribute: @"type" havingValue: @"work"]) longValue = 2; // The Work Address is the mailing address. } *data = MAPILongValue (memCtx, longValue); return MAPISTORE_SUCCESS; } // // getters when no address is selected as the Mailing Address // - (int) getPidTagPostalAddress: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"label" ofType: @"pref" excluding: nil atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidTagPostOfficeBox: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"pref" excluding: nil atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidTagStreetAddress: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"pref" excluding: nil atPos: 2 inData: data inMemCtx: memCtx]; } - (int) getPidTagLocality: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"pref" excluding: nil atPos: 3 inData: data inMemCtx: memCtx]; } - (int) getPidTagStateOrProvince: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"pref" excluding: nil atPos: 4 inData: data inMemCtx: memCtx]; } - (int) getPidTagPostalCode: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"pref" excluding: nil atPos: 5 inData: data inMemCtx: memCtx]; } - (int) getPidTagCountry: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"pref" excluding: nil atPos: 6 inData: data inMemCtx: memCtx]; } // // home address getters // - (int) getPidLidHomeAddress: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"label" ofType: @"home" excluding: nil atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidTagHomeAddressPostOfficeBox: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"home" excluding: nil atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidTagHomeAddressStreet: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"home" excluding: nil atPos: 2 inData: data inMemCtx: memCtx]; } - (int) getPidTagHomeAddressCity: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"home" excluding: nil atPos: 3 inData: data inMemCtx: memCtx]; } - (int) getPidTagHomeAddressStateOrProvince: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"home" excluding: nil atPos: 4 inData: data inMemCtx: memCtx]; } - (int) getPidTagHomeAddressPostalCode: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"home" excluding: nil atPos: 5 inData: data inMemCtx: memCtx]; } - (int) getPidTagHomeAddressCountry: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"home" excluding: nil atPos: 6 inData: data inMemCtx: memCtx]; } // // Work addresss // - (int) getPidLidWorkAddress: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"label" ofType: @"work" excluding: nil atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidLidWorkAddressPostOfficeBox: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"work" excluding: nil atPos: 0 inData: data inMemCtx: memCtx]; } - (int) getPidLidWorkAddressStreet: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"work" excluding: nil atPos: 2 inData: data inMemCtx: memCtx]; } - (int) getPidLidWorkAddressCity: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"work" excluding: nil atPos: 3 inData: data inMemCtx: memCtx]; } - (int) getPidLidWorkAddressState: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"work" excluding: nil atPos: 4 inData: data inMemCtx: memCtx]; } - (int) getPidLidWorkAddressPostalCode: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"work" excluding: nil atPos: 5 inData: data inMemCtx: memCtx]; } - (int) getPidLidWorkAddressCountry: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self _getElement: @"adr" ofType: @"work" excluding: nil atPos: 6 inData: data inMemCtx: memCtx]; } // // // - (int) getPidTagNickname: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; stringValue = [[sogoObject vCard] nickname]; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagBirthday: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSCalendarDate *dateValue; NSString *stringValue; int rc = MAPISTORE_SUCCESS; stringValue = [[sogoObject vCard] bday]; if (stringValue) { dateValue = [NSCalendarDate dateWithString: stringValue calendarFormat: @"%Y-%m-%d"]; //dateValue = [dateValue addYear: 0 month: 0 day: 1 hour: 0 minute: 0 second: 0]; *data = [dateValue asFileTimeInMemCtx: memCtx]; } else rc = MAPISTORE_ERR_NOT_FOUND; return rc; } - (int) getPidTagWeddingAnniversary: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSCalendarDate *dateValue; NSString *stringValue; int rc = MAPISTORE_SUCCESS; stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-anniversary"] flattenedValuesForKey: @""]; if (stringValue && ! [stringValue isEqualToString: @""]) { dateValue = [NSCalendarDate dateWithString: stringValue calendarFormat: @"%Y-%m-%d"]; *data = [dateValue asFileTimeInMemCtx: memCtx]; } else rc = MAPISTORE_ERR_NOT_FOUND; return rc; } - (int) getPidTagSpouseName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; int rc = MAPISTORE_SUCCESS; stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-spouse"] flattenedValuesForKey: @""]; if (stringValue) *data = [stringValue asUnicodeInMemCtx: memCtx]; else rc = MAPISTORE_ERR_NOT_FOUND; return rc; } - (int) getPidTagManagerName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; int rc = MAPISTORE_SUCCESS; stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-manager"] flattenedValuesForKey: @""]; if (stringValue) *data = [stringValue asUnicodeInMemCtx: memCtx]; else rc = MAPISTORE_ERR_NOT_FOUND; return rc; } - (int) getPidTagAssistant: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; int rc = MAPISTORE_SUCCESS; stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-assistant"] flattenedValuesForKey: @""]; if (stringValue) *data = [stringValue asUnicodeInMemCtx: memCtx]; else rc = MAPISTORE_ERR_NOT_FOUND; return rc; } - (int) getPidTagOfficeLocation: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; int rc = MAPISTORE_SUCCESS; stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-office"] flattenedValuesForKey: @""]; if (stringValue) *data = [stringValue asUnicodeInMemCtx: memCtx]; else rc = MAPISTORE_ERR_NOT_FOUND; return rc; } - (int) getPidLidFreeBusyLocation: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; int rc = MAPISTORE_SUCCESS; stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"fburl"] flattenedValuesForKey: @""]; if (stringValue) *data = [stringValue asUnicodeInMemCtx: memCtx]; else rc = MAPISTORE_ERR_NOT_FOUND; return rc; } // // Decomposed fullname getters // - (int) getPidTagSurname: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] flattenedValueAtIndex: 0 forKey: @""]; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagGivenName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] flattenedValueAtIndex: 1 forKey: @""]; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagMiddleName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] flattenedValueAtIndex: 2 forKey: @""]; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagDisplayNamePrefix: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] flattenedValueAtIndex: 3 forKey: @""]; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagGeneration: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { NSString *stringValue; stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] flattenedValueAtIndex: 4 forKey: @""]; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } - (int) getPidTagSensitivity: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getLongZero: data inMemCtx: memCtx]; } /* attachments (photos) */ - (void) _fetchAttachmentParts { NGVCardPhoto *photo; MAPIStoreContactsAttachment *attachment; NSString *encoding; photo = (NGVCardPhoto *) [[sogoObject vCard] firstChildWithTag: @"photo"]; if (photo) { encoding = [[photo value: 0 ofAttribute: @"encoding"] uppercaseString]; if ([encoding isEqualToString: @"B"] || [encoding isEqualToString: @"BASE64"]) { attachment = [MAPIStoreContactsAttachment mapiStoreObjectInContainer: self]; [attachment setAID: 0]; [attachment setPhoto: photo]; [attachmentParts setObject: attachment forKey: @"photo"]; } } fetchedAttachments = YES; } - (int) getPidLidHasPicture: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { if (!fetchedAttachments) [self _fetchAttachmentParts]; *data = MAPIBoolValue (memCtx, ([attachmentParts count] > 0)); return MAPISTORE_SUCCESS; } - (NSArray *) attachmentKeysMatchingQualifier: (EOQualifier *) qualifier andSortOrderings: (NSArray *) sortOrderings { if (!fetchedAttachments) [self _fetchAttachmentParts]; return [super attachmentKeysMatchingQualifier: qualifier andSortOrderings: sortOrderings]; } - (id) lookupAttachment: (NSString *) childKey { if (!fetchedAttachments) [self _fetchAttachmentParts]; return [attachmentParts objectForKey: childKey]; } - (void) _updatePhotoInVCard: (NGVCard *) card fromProperties: (NSDictionary *) attachmentProps { NSString *photoExt, *photoType, *content; CardElement *photo; if ([[attachmentProps objectForKey: MAPIPropertyKey (PR_ATTACHMENT_CONTACTPHOTO)] boolValue]) { photoExt = [[attachmentProps objectForKey: MAPIPropertyKey (PR_ATTACH_EXTENSION_UNICODE)] uppercaseString]; if ([photoExt isEqualToString: @".JPG"]) photoType = @"JPEG"; else if ([photoExt isEqualToString: @".PNG"]) photoType = @"PNG"; else if ([photoExt isEqualToString: @".BMP"]) photoType = @"BMP"; else if ([photoExt isEqualToString: @".GIF"]) photoType = @"GIF"; else photoType = nil; content = [[attachmentProps objectForKey: MAPIPropertyKey (PR_ATTACH_DATA_BIN)] stringByEncodingBase64]; if (photoType && content) { photo = [card uniqueChildWithTag: @"photo"]; [photo setValue: 0 ofAttribute: @"type" to: photoType]; [photo setValue: 0 ofAttribute: @"encoding" to: @"b"]; [photo setSingleValue: [content stringByReplacingString: @"\n" withString: @""] atIndex: 0 forKey: @""]; } } } - (BOOL) subscriberCanReadMessage { return [[self activeUserRoles] containsObject: SOGoRole_ObjectViewer]; } - (BOOL) subscriberCanModifyMessage { NSArray *roles; roles = [self activeUserRoles]; return ((isNew && [roles containsObject: SOGoRole_ObjectCreator]) || (!isNew && [roles containsObject: SOGoRole_ObjectEditor])); } // // // - (void) save:(TALLOC_CTX *) memCtx { NSArray *elements, *units; CardElement *element; NGVCard *newCard; MAPIStoreAttachment *attachment; int postalAddressId; id value; [self logWithFormat: @"setMAPIProperties: %@", properties]; newCard = [sogoObject vCard]; [newCard setTag: @"vcard"]; [newCard setVersion: @"3.0"]; [newCard setProdID: @"-//Inverse inc.//OpenChange+SOGo//EN"]; [newCard setProfile: @"vCard"]; // Decomposed fullname [newCard setNWithFamily: [properties objectForKey: MAPIPropertyKey(PR_SURNAME_UNICODE)] given: [properties objectForKey: MAPIPropertyKey(PR_GIVEN_NAME_UNICODE)] additional: [properties objectForKey: MAPIPropertyKey(PR_MIDDLE_NAME_UNICODE)] prefixes: [properties objectForKey: MAPIPropertyKey(PR_DISPLAY_NAME_PREFIX_UNICODE)] suffixes: [properties objectForKey: MAPIPropertyKey(PR_GENERATION_UNICODE)]]; // // display name // value = [properties objectForKey: MAPIPropertyKey(PR_DISPLAY_NAME_UNICODE)]; if (value) [newCard setFn: value]; // // email addresses handling // elements = [newCard childrenWithTag: @"email"]; value = [properties objectForKey: MAPIPropertyKey(PidLidEmail1EmailAddress)]; if (value) { if ([elements count] > 0) [[elements objectAtIndex: 0] setSingleValue: value forKey: @""]; else [newCard addEmail: value types: [NSArray arrayWithObject: @"pref"]]; } value = [properties objectForKey: MAPIPropertyKey (PidLidEmail2EmailAddress)]; if (value) { if ([elements count] > 1) [[elements objectAtIndex: 1] setSingleValue: value forKey: @""]; else [newCard addEmail: value types: nil]; } value = [properties objectForKey: MAPIPropertyKey (PidLidEmail3EmailAddress)]; if (value) { if ([elements count] > 2) [[elements objectAtIndex: 2] setSingleValue: value forKey: @""]; else [newCard addEmail: value types: nil]; } // // work postal addresses handling // // Possible values for PidLidPostalAddressId are: // // 0x00000000 - No address is selected as the Mailing Address. // 0x00000001 - The Home Address is the Mailing Address. // 0x00000002 - The Work Address is the Mailing Address // 0x00000003 - The Other Address is the Mailing Address. // // postalAddressId = [[properties objectForKey: MAPIPropertyKey (PidLidPostalAddressId)] intValue]; value = [properties objectForKey: MAPIPropertyKey(PidLidWorkAddress)]; if ([value length]) { elements = [newCard childrenWithTag: @"label" andAttribute: @"type" havingValue: @"work"]; if ([elements count] > 0) element = [elements objectAtIndex: 0]; else { element = [CardElement elementWithTag: @"label"]; [element addAttribute: @"type" value: @"work"]; [newCard addChild: element]; } if (postalAddressId == 2) { [element removeValue: @"pref" fromAttribute: @"type"]; [element addAttribute: @"type" value: @"pref"]; } [element setSingleValue: value forKey: @""]; } elements = [newCard childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"work"]; if ([elements count] > 0) element = [elements objectAtIndex: 0]; else { element = [CardElement elementWithTag: @"adr"]; [element addAttribute: @"type" value: @"work"]; [newCard addChild: element]; } if (postalAddressId == 2) [element addAttribute: @"type" value: @"pref"]; value = [properties objectForKey: MAPIPropertyKey(PidLidWorkAddressPostOfficeBox)]; if (value) [element setSingleValue: value atIndex: 0 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PidLidWorkAddressStreet)]; if (value) [element setSingleValue: value atIndex: 2 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PidLidWorkAddressCity)]; if (value) [element setSingleValue: value atIndex: 3 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PidLidWorkAddressState)]; if (value) [element setSingleValue: value atIndex: 4 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PidLidWorkAddressPostalCode)]; if (value) [element setSingleValue: value atIndex: 5 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PidLidWorkAddressCountry)]; if (value) [element setSingleValue: value atIndex: 6 forKey: @""]; // // home postal addresses handling // value = [properties objectForKey: MAPIPropertyKey(PidLidHomeAddress)]; if ([value length]) { elements = [newCard childrenWithTag: @"label" andAttribute: @"type" havingValue: @"home"]; if ([elements count] > 0) element = [elements objectAtIndex: 0]; else { element = [CardElement elementWithTag: @"label"]; [element addAttribute: @"type" value: @"home"]; [newCard addChild: element]; } if (postalAddressId == 1) { [element removeValue: @"pref" fromAttribute: @"type"]; [element addAttribute: @"type" value: @"pref"]; } [element setSingleValue: value forKey: @""]; } elements = [newCard childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"home"]; if ([elements count] > 0) element = [elements objectAtIndex: 0]; else { element = [CardElement elementWithTag: @"adr"]; [element addAttribute: @"type" value: @"home"]; [newCard addChild: element]; } if (postalAddressId == 1) [element addAttribute: @"type" value: @"pref"]; value = [properties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_POST_OFFICE_BOX_UNICODE)]; if (value) [element setSingleValue: value atIndex: 0 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey( PR_HOME_ADDRESS_STREET_UNICODE)]; if (value) [element setSingleValue: value atIndex: 2 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_CITY_UNICODE)]; if (value) [element setSingleValue: value atIndex: 3 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_STATE_OR_PROVINCE_UNICODE)]; if (value) [element setSingleValue: value atIndex: 4 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_POSTAL_CODE_UNICODE)]; if (value) [element setSingleValue: value atIndex: 5 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_COUNTRY_UNICODE)]; if (value) [element setSingleValue: value atIndex: 6 forKey: @""]; // // telephone numbers: work, home, fax, pager and mobile // element = [self _elementWithTag: @"tel" ofType: @"work" forCard: newCard]; value = [properties objectForKey: MAPIPropertyKey(PR_OFFICE_TELEPHONE_NUMBER_UNICODE)]; if (value) [element setSingleValue: value forKey: @""]; element = [self _elementWithTag: @"tel" ofType: @"home" forCard: newCard]; value = [properties objectForKey: MAPIPropertyKey(PR_HOME_TELEPHONE_NUMBER_UNICODE)]; if (value) [element setSingleValue: value forKey: @""]; element = [self _elementWithTag: @"tel" ofType: @"fax" forCard: newCard]; value = [properties objectForKey: MAPIPropertyKey(PR_BUSINESS_FAX_NUMBER_UNICODE)]; if (value) [element setSingleValue: value forKey: @""]; element = [self _elementWithTag: @"tel" ofType: @"pager" forCard: newCard]; value = [properties objectForKey: MAPIPropertyKey(PR_PAGER_TELEPHONE_NUMBER_UNICODE)]; if (value) [element setSingleValue: value forKey: @""]; element = [self _elementWithTag: @"tel" ofType: @"cell" forCard: newCard]; value = [properties objectForKey: MAPIPropertyKey(PR_MOBILE_TELEPHONE_NUMBER_UNICODE)]; if (value) [element setSingleValue: value forKey: @""]; // // job title, profession, nickname, company name, deparment, work url, im address/screen name and birthday // value = [properties objectForKey: MAPIPropertyKey(PR_TITLE_UNICODE)]; if (value) [newCard setTitle: value]; value = [properties objectForKey: MAPIPropertyKey(PR_PROFESSION_UNICODE)]; if (value) { [newCard setRole: value]; } value = [properties objectForKey: MAPIPropertyKey(PR_NICKNAME_UNICODE)]; if (value) [newCard setNickname: value]; value = [properties objectForKey: MAPIPropertyKey(PR_DEPARTMENT_NAME_UNICODE)]; if (value) units = [NSArray arrayWithObject: value]; else units = nil; value = [properties objectForKey: MAPIPropertyKey(PR_COMPANY_NAME_UNICODE)]; if (value) [newCard setOrg: value units: units]; value = [properties objectForKey: MAPIPropertyKey(PR_BUSINESS_HOME_PAGE_UNICODE)]; if (value) { [[self _elementWithTag: @"url" ofType: @"work" forCard: newCard] setSingleValue: value forKey: @""]; } value = [properties objectForKey: MAPIPropertyKey(PidLidInstantMessagingAddress)]; if (value) { [[newCard uniqueChildWithTag: @"x-aim"] setSingleValue: value forKey: @""]; } value = [properties objectForKey: MAPIPropertyKey(PR_BIRTHDAY)]; if (value) { [newCard setBday: [value descriptionWithCalendarFormat: @"%Y-%m-%d"]]; } // // wedding anniversary, spouse's name, manager's name, assistant's name, office location, freebusy location // value = [properties objectForKey: MAPIPropertyKey(PidTagWeddingAnniversary)]; if (value) { [[newCard uniqueChildWithTag: @"x-ms-anniversary"] setSingleValue: [value descriptionWithCalendarFormat: @"%Y-%m-%d"] forKey: @""]; } value = [properties objectForKey: MAPIPropertyKey(PR_SPOUSE_NAME_UNICODE)]; if (value) { [[newCard uniqueChildWithTag: @"x-ms-spouse"] setSingleValue: value forKey: @""]; } value = [properties objectForKey: MAPIPropertyKey(PR_MANAGER_NAME_UNICODE)]; if (value) { [[newCard uniqueChildWithTag: @"x-ms-manager"] setSingleValue: value forKey: @""]; } value = [properties objectForKey: MAPIPropertyKey(PR_ASSISTANT_UNICODE)]; if (value) { [[newCard uniqueChildWithTag: @"x-ms-assistant"] setSingleValue: value forKey: @""]; } value = [properties objectForKey: MAPIPropertyKey(PR_OFFICE_LOCATION_UNICODE)]; if (value) { [[newCard uniqueChildWithTag: @"x-ms-office"] setSingleValue: value forKey: @""]; } value = [properties objectForKey: MAPIPropertyKey(PidLidFreeBusyLocation)]; if (value) { [[newCard uniqueChildWithTag: @"fburl"] setSingleValue: value forKey: @""]; } /* photo */ if ([attachmentParts count] > 0) { attachment = [[attachmentParts allValues] objectAtIndex: 0]; [self _updatePhotoInVCard: newCard fromProperties: [attachment properties]]; } /* Note */ value = [properties objectForKey: MAPIPropertyKey (PR_BODY_UNICODE)]; if (!value) { value = [properties objectForKey: MAPIPropertyKey (PR_HTML)]; if (value) { value = [[NSString alloc] initWithData: value encoding: NSUTF8StringEncoding]; [value autorelease]; value = [value htmlToText]; } } if (value) [newCard setNote: value]; // // we save the new/modified card // [sogoObject saveComponent: newCard]; [self updateVersions]; } @end