diff --git a/ChangeLog b/ChangeLog index dab7cf589..8748a06d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ 2011-09-30 Wolfgang Sourdeau + * OpenChange/MAPIStoreMailMessage.m (-getMessageData:inMemCtx:): + same as below. + + * OpenChange/MAPIStoreCalendarMessage.m + (-getMessageData:inMemCtx:): delegated code to + MAPIStoreAppointmentWrapper so that organizers and invitees are + properly reported both in invitation emails and events. + + * OpenChange/MAPIStoreMessage.m (MAPIStoreInternalEntryId) + (MAPIStoreExternalEntryId): new helper functions that return an + NSData with the entry id for the requested user or contact. + (-getMessageData:inMemCtx:): adapted to the new mapistore_message + struct and column handling. + * OpenChange/NSData+MAPIStore.m (-appendUInt16): new method. * OpenChange/EOQualifier+MAPIFS.m (-[EOKeyValueQUalifier diff --git a/OpenChange/MAPIStoreAppointmentWrapper.h b/OpenChange/MAPIStoreAppointmentWrapper.h index c95859bed..07df6df95 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.h +++ b/OpenChange/MAPIStoreAppointmentWrapper.h @@ -47,6 +47,9 @@ extern NSTimeZone *utcTZ; inTimeZone: (NSTimeZone *) newTimeZone; /* getters */ +- (void) fillMessageData: (struct mapistore_message *) dataPtr + inMemCtx: (TALLOC_CTX *) memCtx; + - (int) getPrIconIndex: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; - (int) getPrOwnerApptId: (void **) data diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index 99cb7012a..70c11eb03 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -24,6 +24,7 @@ #import #import #import +#import #import #import #import @@ -31,7 +32,9 @@ #import #import #import +#import +#import "MAPIStoreMessage.h" #import "MAPIStoreRecurrenceUtils.h" #import "MAPIStoreTypes.h" #import "NSData+MAPIStore.h" @@ -118,6 +121,229 @@ static NSCharacterSet *hexCharacterSet = nil; [super dealloc]; } +- (void) fillMessageData: (struct mapistore_message *) msgData + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSString *username, *cn, *email; + NSData *entryId; + NSArray *attendees; + iCalPerson *person; + iCalPersonPartStat partStat; + uint32_t partStatValue; + SOGoUserManager *mgr; + NSDictionary *contactInfos; + struct mapistore_message_recipient *recipient; + int count, max, p; + + msgData->columns = set_SPropTagArray (msgData, 9, + PR_OBJECT_TYPE, + PR_DISPLAY_TYPE, + PR_7BIT_DISPLAY_NAME_UNICODE, + PR_SMTP_ADDRESS_UNICODE, + PR_SEND_INTERNET_ENCODING, + PR_RECIPIENT_DISPLAY_NAME_UNICODE, + PR_RECIPIENT_FLAGS, + PR_RECIPIENT_ENTRYID, + PR_RECIPIENT_TRACKSTATUS); +// , +// PR_RECORD_KEY); + + attendees = [event attendees]; + max = [attendees count]; + + if (max > 0) + { + mgr = [SOGoUserManager sharedUserManager]; + msgData->recipients_count = max + 1; + msgData->recipients = talloc_array (msgData, struct mapistore_message_recipient *, max + 1); + for (count = 0; count < max; count++) + { + msgData->recipients[count] + = talloc_zero (msgData, struct mapistore_message_recipient); + recipient = msgData->recipients[count]; + + person = [attendees objectAtIndex: count]; + cn = [person cn]; + email = [person rfc822Email]; + if ([cn length] == 0) + cn = email; + contactInfos = [mgr contactInfosForUserWithUIDorEmail: email]; + + if (contactInfos) + { + username = [contactInfos objectForKey: @"c_uid"]; + recipient->username = [username asUnicodeInMemCtx: msgData]; + entryId = MAPIStoreInternalEntryId (username); + } + else + entryId = MAPIStoreExternalEntryId (cn, email); + recipient->type = MAPI_TO; + + /* properties */ + p = 0; + recipient->data = talloc_array (msgData, void *, msgData->columns->cValues); + memset (recipient->data, 0, msgData->columns->cValues * sizeof (void *)); + + // PR_OBJECT_TYPE = MAPI_MAILUSER (see MAPI_OBJTYPE) + recipient->data[p] = MAPILongValue (msgData, MAPI_MAILUSER); + p++; + + // PR_DISPLAY_TYPE = DT_MAILUSER (see MS-NSPI) + recipient->data[p] = MAPILongValue (msgData, 0); + p++; + + // PR_7BIT_DISPLAY_NAME_UNICODE + recipient->data[p] = [cn asUnicodeInMemCtx: msgData]; + p++; + + // PR_SMTP_ADDRESS_UNICODE + recipient->data[p] = [email asUnicodeInMemCtx: msgData]; + p++; + + // PR_SEND_INTERNET_ENCODING = 0x00060000 (plain text, see OXCMAIL) + recipient->data[p] = MAPILongValue (msgData, 0x00060000); + p++; + + // PR_RECIPIENT_DISPLAY_NAME_UNICODE + recipient->data[p] = [cn asUnicodeInMemCtx: msgData]; + p++; + + // PR_RECIPIENT_FLAGS + recipient->data[p] = MAPILongValue (msgData, 1); + p++; + + // PR_RECIPIENT_ENTRYID + recipient->data[p] = [entryId asBinaryInMemCtx: msgData]; + p++; + + // PR_RECIPIENT_TRACKSTATUS + /* + respNone 0x00000000 + No response is required for this object. This is the case for Appointment objects and Meeting Response objects. + respOrganized 0x00000001 + This Meeting object belongs to the organizer. + respTentative 0x00000002 + This value on the attendee's Meeting object indicates that the + attendee has tentatively accepted the Meeting Request object. + respAccepted 0x00000003 + This value on the attendee's Meeting object indicates that the + attendee has accepted the Meeting Request object. + respDeclined 0x00000004 + This value on the attendee's Meeting object indicates that the attendee has declined the Meeting Request + object. + respNotResponded 0x00000005 + This value on the attendee's Meeting object indicates that the attendee has + not yet responded. This value is on the Meet + */ + partStat = [person participationStatus]; + switch (partStat) + { + case iCalPersonPartStatAccepted: + partStatValue = 3; + break; + case iCalPersonPartStatDeclined: + partStatValue = 4; + break; + case iCalPersonPartStatTentative: + partStatValue = 2; + break; + default: + partStatValue = 5; + } + recipient->data[p] = MAPILongValue (msgData, partStatValue); + p++; + + // // PR_RECORD_KEY + // recipient->data[p] = [entryId asBinaryInMemCtx: msgData]; + // p++; + } + + /* On with the organizer: */ + { + msgData->recipients[max] + = talloc_zero (msgData, struct mapistore_message_recipient); + recipient = msgData->recipients[max]; + + person = [event organizer]; + cn = [person cn]; + email = [person rfc822Email]; + contactInfos = [mgr contactInfosForUserWithUIDorEmail: email]; + + if (contactInfos) + { + username = [contactInfos objectForKey: @"c_uid"]; + recipient->username = [username asUnicodeInMemCtx: msgData]; + entryId = MAPIStoreInternalEntryId (username); + } + else + entryId = MAPIStoreExternalEntryId (cn, email); + recipient->type = MAPI_TO; + + p = 0; + recipient->data = talloc_array (msgData, void *, msgData->columns->cValues); + memset (recipient->data, 0, msgData->columns->cValues * sizeof (void *)); + + // PR_OBJECT_TYPE = MAPI_MAILUSER (see MAPI_OBJTYPE) + recipient->data[p] = MAPILongValue (msgData, MAPI_MAILUSER); + p++; + + // PR_DISPLAY_TYPE = DT_MAILUSER (see MS-NSPI) + recipient->data[p] = MAPILongValue (msgData, 0); + p++; + + // PR_7BIT_DISPLAY_NAME_UNICODE + recipient->data[p] = [cn asUnicodeInMemCtx: msgData]; + p++; + + // PR_SMTP_ADDRESS_UNICODE + recipient->data[p] = [email asUnicodeInMemCtx: msgData]; + p++; + + // PR_SEND_INTERNET_ENCODING = 0x00060000 (plain text, see OXCMAIL) + recipient->data[p] = MAPILongValue (msgData, 0x00060000); + p++; + + // PR_RECIPIENT_DISPLAY_NAME_UNICODE + recipient->data[p] = [cn asUnicodeInMemCtx: msgData]; + p++; + + // PR_RECIPIENT_FLAGS + recipient->data[p] = MAPILongValue (msgData, 3); + p++; + + // PR_RECIPIENT_ENTRYID = NULL + recipient->data[p] = [entryId asBinaryInMemCtx: msgData]; + p++; + + // PR_RECIPIENT_TRACKSTATUS + /* + respNone 0x00000000 + No response is required for this object. This is the case for Appointment objects and Meeting Response objects. + respOrganized 0x00000001 + This Meeting object belongs to the organizer. + respTentative 0x00000002 + This value on the attendee's Meeting object indicates that the + attendee has tentatively accepted the Meeting Request object. + respAccepted 0x00000003 + This value on the attendee's Meeting object indicates that the + attendee has accepted the Meeting Request object. + respDeclined 0x00000004 + This value on the attendee's Meeting object indicates that the attendee has declined the Meeting Request + object. + respNotResponded 0x00000005 + This value on the attendee's Meeting object indicates that the attendee has + not yet responded. This value is on the Meet + */ + recipient->data[p] = MAPILongValue (msgData, 1); + p++; + + // // PR_RECORD_KEY + // recipient->data[p] = [entryId asBinaryInMemCtx: msgData]; + // p++; + } + } +} + - (int) getPrIconIndex: (void **) data // TODO inMemCtx: (TALLOC_CTX *) memCtx { diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index 230a1b7f8..f4827a078 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -255,58 +255,11 @@ - (void) getMessageData: (struct mapistore_message **) dataPtr inMemCtx: (TALLOC_CTX *) memCtx { - NSString *text; - NSArray *attendees; - iCalPerson *person; - struct SRowSet *recipients; - int count, max; - iCalEvent *event; struct mapistore_message *msgData; [super getMessageData: &msgData inMemCtx: memCtx]; - - event = [sogoObject component: NO secure: NO]; - attendees = [event attendees]; - max = [attendees count]; - - recipients = talloc_zero (msgData, struct SRowSet); - recipients->cRows = max; - recipients->aRow = talloc_array (recipients, struct SRow, max); - for (count = 0; count < max; count++) - { - recipients->aRow[count].ulAdrEntryPad = 0; - recipients->aRow[count].cValues = 3; - recipients->aRow[count].lpProps = talloc_array (recipients->aRow, - struct SPropValue, - 4); - - // TODO (0x01 = primary recipient) - set_SPropValue_proptag (recipients->aRow[count].lpProps, - PR_RECIPIENT_TYPE, - MAPILongValue (recipients->aRow[count].lpProps, 0x01)); - - set_SPropValue_proptag (recipients->aRow[count].lpProps + 1, - PR_ADDRTYPE_UNICODE, - [@"SMTP" asUnicodeInMemCtx: recipients->aRow]); - - person = [attendees objectAtIndex: count]; - text = [person rfc822Email]; - if (!text) - text = @""; - set_SPropValue_proptag (recipients->aRow[count].lpProps + 2, - PR_EMAIL_ADDRESS_UNICODE, - [text asUnicodeInMemCtx: recipients->aRow]); - - text = [person cn]; - if ([text length] > 0) - { - recipients->aRow[count].cValues++; - set_SPropValue_proptag (recipients->aRow[count].lpProps + 3, - PR_DISPLAY_NAME_UNICODE, - [text asUnicodeInMemCtx: recipients->aRow]); - } - } - msgData->recipients = recipients; + [[self appointmentWrapper] fillMessageData: msgData + inMemCtx: memCtx]; *dataPtr = msgData; } diff --git a/OpenChange/MAPIStoreDraftsMessage.m b/OpenChange/MAPIStoreDraftsMessage.m index 7168c36ba..6a2cc41a1 100644 --- a/OpenChange/MAPIStoreDraftsMessage.m +++ b/OpenChange/MAPIStoreDraftsMessage.m @@ -28,11 +28,13 @@ #import #import #import +#import #import #import #import "MAPIStoreContext.h" #import "MAPIStoreTypes.h" +#import "NSData+MAPIStore.h" #import "NSObject+MAPIStore.h" #import "NSString+MAPIStore.h" @@ -92,14 +94,17 @@ typedef void (*getMessageData_inMemCtx_) (MAPIStoreMessage *, SEL, - (void) getMessageData: (struct mapistore_message **) dataPtr inMemCtx: (TALLOC_CTX *) memCtx { - struct SRowSet *recipients; NSArray *to; - NSInteger count, max; - NSString *text; + NSInteger count, max, p; + NSString *username, *cn, *email; + NSData *entryId; + NSDictionary *contactInfos; + SOGoUserManager *mgr; NSDictionary *headers; NGMailAddress *currentAddress; NGMailAddressParser *parser; struct mapistore_message *msgData; + struct mapistore_message_recipient *recipient; getMessageData_inMemCtx_ superMethod; if ([sogoObject isKindOfClass: SOGoDraftObjectK]) @@ -117,53 +122,99 @@ typedef void (*getMessageData_inMemCtx_) (MAPIStoreMessage *, SEL, to = [headers objectForKey: @"to"]; max = [to count]; - recipients = talloc_zero (msgData, struct SRowSet); - recipients->cRows = max; - recipients->aRow = talloc_array (recipients, struct SRow, max); - for (count = 0; count < max; count++) + + msgData->columns = set_SPropTagArray (msgData, 9, + PR_OBJECT_TYPE, + PR_DISPLAY_TYPE, + PR_7BIT_DISPLAY_NAME_UNICODE, + PR_SMTP_ADDRESS_UNICODE, + PR_SEND_INTERNET_ENCODING, + PR_RECIPIENT_DISPLAY_NAME_UNICODE, + PR_RECIPIENT_FLAGS, + PR_RECIPIENT_ENTRYID, + PR_RECIPIENT_TRACKSTATUS); + + if (max > 0) { - recipients->aRow[count].ulAdrEntryPad = 0; - recipients->aRow[count].cValues = 3; - recipients->aRow[count].lpProps = talloc_array (recipients->aRow, - struct SPropValue, - 4); - - // TODO (0x01 = primary recipient) - set_SPropValue_proptag (recipients->aRow[count].lpProps + 0, - PR_RECIPIENT_TYPE, - MAPILongValue (recipients->aRow, 0x01)); - - set_SPropValue_proptag (recipients->aRow[count].lpProps + 1, - PR_ADDRTYPE_UNICODE, - [@"SMTP" asUnicodeInMemCtx: recipients->aRow]); - - parser = [NGMailAddressParser - mailAddressParserWithString: [to objectAtIndex: count]]; - currentAddress = [parser parse]; - if ([currentAddress isKindOfClass: NGMailAddressK]) + mgr = [SOGoUserManager sharedUserManager]; + msgData->recipients_count = max; + msgData->recipients = talloc_array (msgData, struct mapistore_message_recipient *, max); + for (count = 0; count < max; count++) { - // text = [currentAddress personalName]; - // if (![text length]) - text = [currentAddress address]; - if (!text) - text = @""; - set_SPropValue_proptag (recipients->aRow[count].lpProps + 2, - PR_EMAIL_ADDRESS_UNICODE, - [text asUnicodeInMemCtx: recipients->aRow]); - - text = [currentAddress displayName]; - if ([text length] > 0) + msgData->recipients[count] + = talloc_zero (msgData, struct mapistore_message_recipient); + recipient = msgData->recipients[count]; + recipient->data = talloc_array (msgData, void *, msgData->columns->cValues); + memset (recipient->data, 0, msgData->columns->cValues * sizeof (void *)); + + email = nil; + cn = nil; + + parser = [NGMailAddressParser + mailAddressParserWithString: [to objectAtIndex: count]]; + currentAddress = [parser parse]; + if ([currentAddress isKindOfClass: NGMailAddressK]) { - recipients->aRow[count].cValues++; - set_SPropValue_proptag (recipients->aRow[count].lpProps + 3, - PR_DISPLAY_NAME_UNICODE, - [text asUnicodeInMemCtx: recipients->aRow]); + email = [currentAddress address]; + cn = [currentAddress displayName]; + contactInfos = [mgr contactInfosForUserWithUIDorEmail: email]; + + // PR_ACCOUNT_UNICODE + if (contactInfos) + { + username = [contactInfos objectForKey: @"c_uid"]; + recipient->username = [username asUnicodeInMemCtx: msgData]; + entryId = MAPIStoreInternalEntryId (username); + } + else + entryId = MAPIStoreExternalEntryId (cn, email); } + else + { + entryId = nil; + [self warnWithFormat: @"address could not be parsed" + @" properly (ignored)"]; + } + recipient->type = MAPI_TO; + + /* properties */ + p = 0; + recipient->data = talloc_array (msgData, void *, msgData->columns->cValues); + memset (recipient->data, 0, msgData->columns->cValues * sizeof (void *)); + + // PR_OBJECT_TYPE = MAPI_MAILUSER (see MAPI_OBJTYPE) + recipient->data[p] = MAPILongValue (msgData, MAPI_MAILUSER); + p++; + + // PR_DISPLAY_TYPE = DT_MAILUSER (see MS-NSPI) + recipient->data[p] = MAPILongValue (msgData, 0); + p++; + + // PR_7BIT_DISPLAY_NAME_UNICODE + recipient->data[p] = [cn asUnicodeInMemCtx: msgData]; + p++; + + // PR_SMTP_ADDRESS_UNICODE + recipient->data[p] = [email asUnicodeInMemCtx: msgData]; + p++; + + // PR_SEND_INTERNET_ENCODING = 0x00060000 (plain text, see OXCMAIL) + recipient->data[p] = MAPILongValue (msgData, 0x00060000); + p++; + + // PR_RECIPIENT_DISPLAY_NAME_UNICODE + recipient->data[p] = [cn asUnicodeInMemCtx: msgData]; + p++; + + // PR_RECIPIENT_FLAGS + recipient->data[p] = NULL; + p++; + + // PR_RECIPIENT_ENTRYID + recipient->data[p] = [entryId asShortBinaryInMemCtx: msgData]; + p++; } - else - [self warnWithFormat: @"address could not be parsed properly (ignored)"]; } - msgData->recipients = recipients; *dataPtr = msgData; } else diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 3b6dde8ec..16c073f64 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -31,6 +31,7 @@ #import #import #import +#import #import #import #import @@ -1175,57 +1176,113 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) - (void) getMessageData: (struct mapistore_message **) dataPtr inMemCtx: (TALLOC_CTX *) memCtx { - struct SRowSet *recipients; NSArray *to; - NSInteger count, max; + NSInteger count, max, p; NGImap4EnvelopeAddress *currentAddress; - NSString *text; + NSString *username, *cn, *email; + NSData *entryId; + NSDictionary *contactInfos; + SOGoUserManager *mgr; struct mapistore_message *msgData; + struct mapistore_message_recipient *recipient; [super getMessageData: &msgData inMemCtx: memCtx]; - /* Retrieve recipients from the message */ - to = [sogoObject toEnvelopeAddresses]; - max = [to count]; - recipients = talloc_zero (msgData, struct SRowSet); - recipients->cRows = max; - recipients->aRow = talloc_array (recipients, struct SRow, max); - for (count = 0; count < max; count++) + + if (!headerSetup) + [self _fetchHeaderData]; + + if (mailIsEvent) + [[self _appointmentWrapper] fillMessageData: msgData + inMemCtx: memCtx]; + else { - recipients->aRow[count].ulAdrEntryPad = 0; - recipients->aRow[count].cValues = 3; - recipients->aRow[count].lpProps = talloc_array (recipients->aRow, - struct SPropValue, - 4); + /* Retrieve recipients from the message */ + to = [sogoObject toEnvelopeAddresses]; + max = [to count]; - // TODO (0x01 = primary recipient) - set_SPropValue_proptag (recipients->aRow[count].lpProps + 0, - PR_RECIPIENT_TYPE, - MAPILongValue (recipients->aRow, 0x01)); - - set_SPropValue_proptag (recipients->aRow[count].lpProps + 1, - PR_ADDRTYPE_UNICODE, - [@"SMTP" asUnicodeInMemCtx: recipients->aRow]); + msgData->columns = set_SPropTagArray (msgData, 9, + PR_OBJECT_TYPE, + PR_DISPLAY_TYPE, + PR_7BIT_DISPLAY_NAME_UNICODE, + PR_SMTP_ADDRESS_UNICODE, + PR_SEND_INTERNET_ENCODING, + PR_RECIPIENT_DISPLAY_NAME_UNICODE, + PR_RECIPIENT_FLAGS, + PR_RECIPIENT_ENTRYID, + PR_RECIPIENT_TRACKSTATUS); - currentAddress = [to objectAtIndex: count]; - // text = [currentAddress personalName]; - // if (![text length]) - text = [currentAddress baseEMail]; - if (!text) - text = @""; - set_SPropValue_proptag (recipients->aRow[count].lpProps + 2, - PR_EMAIL_ADDRESS_UNICODE, - [text asUnicodeInMemCtx: recipients->aRow]); - - text = [currentAddress personalName]; - if ([text length] > 0) + if (max > 0) { - recipients->aRow[count].cValues++; - set_SPropValue_proptag (recipients->aRow[count].lpProps + 3, - PR_DISPLAY_NAME_UNICODE, - [text asUnicodeInMemCtx: recipients->aRow]); + mgr = [SOGoUserManager sharedUserManager]; + msgData->recipients_count = max; + msgData->recipients = talloc_array (msgData, struct mapistore_message_recipient *, max); + for (count = 0; count < max; count++) + { + msgData->recipients[count] + = talloc_zero (msgData, struct mapistore_message_recipient); + recipient = msgData->recipients[count]; + + currentAddress = [to objectAtIndex: count]; + cn = [currentAddress personalName]; + email = [currentAddress baseEMail]; + if ([cn length] == 0) + cn = email; + contactInfos = [mgr contactInfosForUserWithUIDorEmail: email]; + + if (contactInfos) + { + username = [contactInfos objectForKey: @"c_uid"]; + // recipient->username = [username asUnicodeInMemCtx: msgData]; + // entryId = MAPIStoreInternalEntryId (username); + entryId = MAPIStoreExternalEntryId (cn, email); + } + else + entryId = MAPIStoreExternalEntryId (cn, email); + recipient->type = MAPI_TO; + + /* properties */ + p = 0; + recipient->data = talloc_array (msgData, void *, msgData->columns->cValues); + memset (recipient->data, 0, msgData->columns->cValues * sizeof (void *)); + + // PR_OBJECT_TYPE = MAPI_MAILUSER (see MAPI_OBJTYPE) + recipient->data[p] = MAPILongValue (msgData, MAPI_MAILUSER); + p++; + + // PR_DISPLAY_TYPE = DT_MAILUSER (see MS-NSPI) + recipient->data[p] = MAPILongValue (msgData, 0); + p++; + + // PR_7BIT_DISPLAY_NAME_UNICODE + recipient->data[p] = [cn asUnicodeInMemCtx: msgData]; + p++; + + // PR_SMTP_ADDRESS_UNICODE + recipient->data[p] = [email asUnicodeInMemCtx: msgData]; + p++; + + // PR_SEND_INTERNET_ENCODING = 0x00060000 (plain text, see OXCMAIL) + recipient->data[p] = MAPILongValue (msgData, 0x00060000); + p++; + + // PR_RECIPIENT_DISPLAY_NAME_UNICODE + recipient->data[p] = [cn asUnicodeInMemCtx: msgData]; + p++; + + // PR_RECIPIENT_FLAGS + recipient->data[p] = MAPILongValue (msgData, 0x01); + p++; + + // PR_RECIPIENT_ENTRYID + recipient->data[p] = [entryId asBinaryInMemCtx: msgData]; + p++; + + // PR_RECIPIENT_TRACKSTATUS + recipient->data[p] = MAPILongValue (msgData, 0x00); + p++; + } } } - msgData->recipients = recipients; *dataPtr = msgData; } diff --git a/OpenChange/MAPIStoreMessage.h b/OpenChange/MAPIStoreMessage.h index 08d2ecd82..3a0facfdf 100644 --- a/OpenChange/MAPIStoreMessage.h +++ b/OpenChange/MAPIStoreMessage.h @@ -37,6 +37,9 @@ #import "MAPIStoreObject.h" +extern NSData *MAPIStoreInternalEntryId (NSString *username); +extern NSData *MAPIStoreExternalEntryId (NSString *cn, NSString *email); + @interface MAPIStoreMessage : MAPIStoreObject { NSArray *attachmentKeys; diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index c7d5ed029..0acdf6b51 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -21,6 +21,7 @@ */ #import +#import #import #import #import @@ -33,7 +34,9 @@ #import "MAPIStoreAttachmentTable.h" #import "MAPIStoreContext.h" #import "MAPIStoreFolder.h" +#import "MAPIStorePropertySelectors.h" #import "MAPIStoreTypes.h" +#import "NSData+MAPIStore.h" #import "NSObject+MAPIStore.h" #import "NSString+MAPIStore.h" @@ -46,6 +49,102 @@ #include #include +NSData *MAPIStoreInternalEntryId (NSString *username) +{ + NSMutableData *entryId; + static uint8_t providerUid[] = { 0xdc, 0xa7, 0x40, 0xc8, + 0xc0, 0x42, 0x10, 0x1a, + 0xb4, 0xb9, 0x08, 0x00, + 0x2b, 0x2f, 0xe1, 0x82 }; + NSString *x500dn; + + /* structure: + flags: 32 + provideruid: 32 * 4 + version: 32 + type: 32 + X500DN: variable */ + + entryId = [NSMutableData dataWithCapacity: 256]; + [entryId appendUInt32: 0]; // flags + [entryId appendBytes: providerUid length: 16]; // provideruid + [entryId appendUInt32: 1]; // version + [entryId appendUInt32: 0]; // type (local mail user) + + /* X500DN */ + /* FIXME: the DN will likely work on DEMO installations for now but we + really should get the dn prefix from the server */ + x500dn = [NSString stringWithFormat: @"/O=FIRST ORGANIZATION" + @"/OU=FIRST ADMINISTRATIVE GROUP" + @"/CN=RECIPIENTS/CN=%@", username]; + [entryId appendData: [x500dn dataUsingEncoding: NSISOLatin1StringEncoding]]; + [entryId appendUInt8: 0]; + + return entryId; +} + +NSData *MAPIStoreExternalEntryId (NSString *cn, NSString *email) +{ + NSMutableData *entryId; + static uint8_t providerUid[] = { 0x81, 0x2b, 0x1f, 0xa4, + 0xbe, 0xa3, 0x10, 0x19, + 0x9d, 0x6e, 0x00, 0xdd, + 0x01, 0x0f, 0x54, 0x02 }; + uint8_t flags21, flags22; + + /* structure: + flags: 32 + provideruid: 32 * 4 + version: 16 + { + PaD: 1 + MAE: 2 + Format: 4 + M: 1 + U: 1 + R: 2 + L: 1 + Pad: 4 + } + DisplayName: variable + AddressType: variable + EmailAddress: variable */ + + entryId = [NSMutableData dataWithCapacity: 256]; + [entryId appendUInt32: 0]; // flags + [entryId appendBytes: providerUid length: 16]; // provideruid + [entryId appendUInt16: 0]; // version + + flags21 = 0; /* PaD, MAE, R, Pad = 0 */ + flags21 |= 0x16; /* Format: text and HTML */ + flags21 |= 0x01; /* M: mime format */ + + flags22 = 0x90; /* U: unicode, L: no lookup */ + [entryId appendUInt8: flags21]; + [entryId appendUInt8: flags22]; + + /* DisplayName */ + if (!cn) + cn = @""; + [entryId + appendData: [cn dataUsingEncoding: NSUTF16LittleEndianStringEncoding]]; + [entryId appendUInt16: 0]; + + /* AddressType */ + [entryId + appendData: [@"SMTP" dataUsingEncoding: NSUTF16LittleEndianStringEncoding]]; + [entryId appendUInt16: 0]; + + /* EMailAddress */ + if (!email) + email = @""; + [entryId + appendData: [email dataUsingEncoding: NSUTF16LittleEndianStringEncoding]]; + [entryId appendUInt16: 0]; + + return entryId; +} + @interface SOGoObject (MAPIStoreProtocol) - (NSString *) davEntityTag; @@ -77,12 +176,6 @@ - (void) getMessageData: (struct mapistore_message **) dataPtr inMemCtx: (TALLOC_CTX *) memCtx { - static enum MAPITAGS tags[] = { PR_SUBJECT_PREFIX_UNICODE, - PR_NORMALIZED_SUBJECT_UNICODE }; - struct SRowSet *recipients; - struct SRow *properties; - NSInteger count, max; - const char *propName; void *propValue; struct mapistore_message *msgData; @@ -91,40 +184,22 @@ msgData = talloc_zero (memCtx, struct mapistore_message); - recipients = talloc_zero (msgData, struct SRowSet); - recipients->cRows = 0; - recipients->aRow = NULL; - msgData->recipients = recipients; + if ([self getPrSubjectPrefix: &propValue + inMemCtx: msgData] == MAPISTORE_SUCCESS + && propValue) + msgData->subject_prefix = propValue; + else + msgData->subject_prefix = ""; - max = 2; - properties = talloc_zero (msgData, struct SRow); - properties->cValues = 0; - properties->ulAdrEntryPad = 0; - properties->lpProps = talloc_array (properties, struct SPropValue, max); - for (count = 0; count < max; count++) - { - if ([self getProperty: &propValue withTag: tags[count] inMemCtx: msgData] - == MAPISTORE_SUCCESS) - { - if (propValue == NULL) - { - propName = get_proptag_name (tags[count]); - if (!propName) - propName = ""; - [self errorWithFormat: @"both 'success' and NULL data" - @" returned for proptag %s(0x%.8x)", - propName, tags[count]]; - } - else - { - set_SPropValue_proptag (properties->lpProps + properties->cValues, - tags[count], - propValue); - properties->cValues++; - } - } - } - msgData->properties = properties; + if ([self getPrNormalizedSubject: &propValue + inMemCtx: msgData] == MAPISTORE_SUCCESS + && propValue) + msgData->normalized_subject = propValue; + else + msgData->normalized_subject = ""; + + msgData->columns = talloc_zero(msgData, struct SPropTagArray); + msgData->recipients_count = 0; *dataPtr = msgData; }