sogo/OpenChange/MAPIStoreMessage.m

1001 lines
26 KiB
Objective-C

/* MAPIStoreMessage.m - this file is part of SOGo
*
* Copyright (C) 2011-2012 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* 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 <Foundation/NSArray.h>
#import <Foundation/NSBundle.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSURL.h>
#import <NGExtensions/NSObject+Logs.h>
#import <SOGo/SOGoObject.h>
#import <SOGo/SOGoPermissions.h>
#import <SOGo/SOGoUser.h>
#import "MAPIStoreActiveTables.h"
#import "MAPIStoreAttachment.h"
#import "MAPIStoreAttachmentTable.h"
#import "MAPIStoreContext.h"
#import "MAPIStoreEmbeddedMessage.h"
#import "MAPIStoreFolder.h"
#import "MAPIStoreMessageTable.h"
#import "MAPIStorePropertySelectors.h"
#import "MAPIStoreSamDBUtils.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import "RTFHandler.h"
#import "MAPIStoreMessage.h"
#undef DEBUG
#include <stdbool.h>
#include <gen_ndr/exchange.h>
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
static Class MAPIStoreFolderK, MAPIStoreEmbeddedMessageK;
static NSString *resourcesDir = nil;
static NSData *
uncompressRTF (NSData *compressedRTF)
{
NSData *rtfData = nil;
DATA_BLOB *rtf;
TALLOC_CTX *mem_ctx;
mem_ctx = talloc_zero (NULL, TALLOC_CTX);
rtf = talloc_zero (mem_ctx, DATA_BLOB);
if (uncompress_rtf (mem_ctx,
(uint8_t *) [compressedRTF bytes], [compressedRTF length],
rtf)
== MAPI_E_SUCCESS)
rtfData = [NSData dataWithBytes: rtf->data length: rtf->length];
talloc_free (mem_ctx);
return rtfData;
}
static NSData *
rtf2html (NSData *compressedRTF)
{
NSData *rtf;
NSMutableData *html = nil;
rtf = uncompressRTF (compressedRTF);
if (rtf)
{
//html = [NSMutableData data];
RTFHandler *handler;
handler = [[RTFHandler alloc] initWithData: rtf];
AUTORELEASE(handler);
html = [handler parse];
}
return html;
}
@interface SOGoObject (MAPIStoreProtocol)
- (NSString *) davContentLength;
@end
@implementation MAPIStoreMessage
+ (void) initialize
{
if (!resourcesDir)
{
resourcesDir = [[NSBundle bundleForClass: self] resourcePath];
[resourcesDir retain];
}
MAPIStoreFolderK = [MAPIStoreFolder class];
MAPIStoreEmbeddedMessageK = [MAPIStoreEmbeddedMessage class];
}
- (id) init
{
//[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
if ((self = [super init]))
{
attachmentParts = [NSMutableDictionary new];
activeTables = [NSMutableArray new];
activeUserRoles = nil;
}
return self;
}
- (void) dealloc
{
//[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
[activeUserRoles release];
[attachmentKeys release];
[attachmentParts release];
[activeTables release];
[super dealloc];
}
- (void) getMessageData: (struct mapistore_message **) dataPtr
inMemCtx: (TALLOC_CTX *) memCtx
{
void *propValue;
struct mapistore_message *msgData;
// [self logWithFormat: @"INCOMPLETE METHOD '%s' (%d): no recipient handling",
// __FUNCTION__, __LINE__];
msgData = talloc_zero (memCtx, struct mapistore_message);
if ([self getPidTagSubjectPrefix: &propValue
inMemCtx: msgData] == MAPISTORE_SUCCESS
&& propValue)
msgData->subject_prefix = propValue;
else
msgData->subject_prefix = "";
if ([self getPidTagNormalizedSubject: &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;
}
- (NSDictionary *) _convertRecipient: (struct mapistore_message_recipient *) recipient
andColumns: (struct SPropTagArray *) columns
{
NSMutableDictionary *recipientProperties;
enum MAPITAGS prop_tag;
char *displayName = NULL;
char *email = NULL;
enum MAPI_OBJTYPE object_type = 0;
char *smtpAddress = NULL;
SOGoUser *recipientUser;
NSUInteger count;
NSString *recipientEmail = nil;
NSString *recipientFullName = nil;
id value;
recipientProperties = [NSMutableDictionary dictionaryWithCapacity: columns->cValues + 2];
for (count = 0; count < columns->cValues; count++)
{
prop_tag = columns->aulPropTag[count];
switch(prop_tag) {
case PidTagDisplayName:
displayName = recipient->data[count];
break;
case PidTagEmailAddress:
email = recipient->data[count];
break;
case PidTagObjectType:
if (recipient->data[count])
object_type = *((uint8_t*) recipient->data[count]);
break;
case PidTagSmtpAddress:
smtpAddress = recipient->data[count];
break;
default:
break;
}
if (recipient->data[count])
{
value = NSObjectFromValuePointer (prop_tag,
recipient->data[count]);
if (value)
[recipientProperties setObject: value
forKey: MAPIPropertyKey (prop_tag)];
}
}
if (recipient->username)
{
value = [NSString stringWithUTF8String: recipient->username];
[recipientProperties setObject: value forKey: @"x500dn"];
}
if (object_type == MAPI_MAILUSER && recipient->username)
{
/* values from user object have priority over data sent by the client */
recipientUser = [SOGoUser userWithLogin: [value lowercaseString]];
if (recipientUser)
{
value = [recipientUser cn];
if ([value length] > 0)
recipientFullName = value;
value = [[recipientUser allEmails] objectAtIndex: 0];
if ([value length] > 0)
recipientEmail = value;
}
}
/* If we do not have values from the user object we try to get them from the parameters */
if (!recipientFullName && displayName)
{
value = [NSString stringWithUTF8String: displayName];
if ([value length] > 0)
recipientFullName = value;
}
if (!recipientEmail && email)
{
value = [NSString stringWithUTF8String: email];
if ([value length] > 0)
recipientEmail = value;
}
if (!recipientEmail && smtpAddress)
{
value = [NSString stringWithUTF8String: smtpAddress];
if ([value length] > 0)
recipientEmail = value;
}
/* Now we can set the properties if we have them */
if (recipientFullName)
[recipientProperties setObject: recipientFullName forKey: @"fullName"];
if (recipientEmail)
[recipientProperties setObject: recipientEmail forKey: @"email"];
return recipientProperties;
}
- (int) modifyRecipientsWithRecipients: (struct mapistore_message_recipient *) newRecipients
andCount: (NSUInteger) max
andColumns: (struct SPropTagArray *) columns;
{
static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
NSDictionary *recipientProperties;
NSMutableDictionary *recipients;
NSMutableArray *list;
NSString *recType;
struct mapistore_message_recipient *recipient;
NSUInteger count;
//[self logWithFormat: @"METHOD '%s'", __FUNCTION__];
recipients = [NSMutableDictionary new];
recipientProperties = [NSDictionary dictionaryWithObject: recipients
forKey: @"recipients"];
[recipients release];
for (count = 0; count < max; count++)
{
recipient = newRecipients + count;
if (recipient->type >= MAPI_ORIG && recipient->type <= MAPI_BCC)
{
recType = recTypes[recipient->type];
list = [recipients objectForKey: recType];
if (!list)
{
list = [NSMutableArray new];
[recipients setObject: list forKey: recType];
[list release];
}
[list addObject:
[self _convertRecipient: recipient andColumns: columns]];
}
}
[self addProperties: recipientProperties];
return MAPISTORE_SUCCESS;
}
- (int) addPropertiesFromRow: (struct SRow *) aRow
{
enum mapistore_error rc;
MAPIStoreContext *context;
SOGoUser *ownerUser;
BOOL userIsOwner;
MAPIStoreMessage *mainMessage;
context = [self context];
ownerUser = [[self userContext] sogoUser];
userIsOwner = [[context activeUser] isEqual: ownerUser];
if (userIsOwner)
mainMessage = nil;
else if ([self isKindOfClass: MAPIStoreEmbeddedMessageK])
mainMessage = (MAPIStoreMessage *) [[self container] container];
else
mainMessage = self;
if (userIsOwner || [mainMessage subscriberCanModifyMessage])
rc = [super addPropertiesFromRow: aRow];
else
rc = MAPISTORE_ERR_DENIED;
return rc;
}
- (void) addProperties: (NSDictionary *) newNewProperties
{
NSData *htmlData, *rtfData;
static NSNumber *htmlKey = nil, *rtfKey = nil;
/* we intercept any RTF content and convert it to HTML */
[super addProperties: newNewProperties];
if (!htmlKey)
{
htmlKey = MAPIPropertyKey (PR_HTML);
[htmlKey retain];
}
if (!rtfKey)
{
rtfKey = MAPIPropertyKey (PR_RTF_COMPRESSED);
[rtfKey retain];
}
if (![properties objectForKey: htmlKey])
{
rtfData = [properties objectForKey: rtfKey];
if (rtfData)
{
htmlData = rtf2html (rtfData);
[properties setObject: htmlData forKey: htmlKey];
[properties removeObjectForKey: rtfKey];
[properties removeObjectForKey: MAPIPropertyKey (PR_RTF_IN_SYNC)];
}
}
}
- (MAPIStoreAttachment *) createAttachment
{
MAPIStoreAttachment *newAttachment;
uint32_t newAid;
NSString *newKey;
newAid = [[self attachmentKeys] count];
newAttachment = [MAPIStoreAttachment mapiStoreObjectInContainer: self];
// [newAttachment setIsNew: YES];
[newAttachment setAID: newAid];
newKey = [NSString stringWithFormat: @"%ul", newAid];
[attachmentParts setObject: newAttachment
forKey: newKey];
[attachmentKeys release];
attachmentKeys = nil;
return newAttachment;
}
- (int) createAttachment: (MAPIStoreAttachment **) attachmentPtr
inAID: (uint32_t *) aidPtr
{
MAPIStoreAttachment *attachment;
int rc = MAPISTORE_SUCCESS;
attachment = [self createAttachment];
if (attachment)
{
*attachmentPtr = attachment;
*aidPtr = [attachment AID];
}
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (id) lookupAttachment: (NSString *) childKey
{
[self subclassResponsibility: _cmd];
return nil;
}
- (int) getAttachment: (MAPIStoreAttachment **) attachmentPtr
withAID: (uint32_t) aid
{
MAPIStoreAttachment *attachment;
NSArray *keys;
int rc = MAPISTORE_ERR_NOT_FOUND;
keys = [self attachmentKeys];
if (aid < [keys count])
{
attachment = [self lookupAttachment: [keys objectAtIndex: aid]];
if (attachment)
{
*attachmentPtr = attachment;
rc = MAPISTORE_SUCCESS;
}
}
return rc;
}
- (int) getAttachmentTable: (MAPIStoreAttachmentTable **) tablePtr
andRowCount: (uint32_t *) countPtr
{
MAPIStoreAttachmentTable *attTable;
int rc = MAPISTORE_SUCCESS;
attTable = [self attachmentTable];
if (attTable)
{
*tablePtr = attTable;
*countPtr = [[attTable childKeys] count];
}
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (NSArray *) activeContainerMessageTables
{
return [[MAPIStoreActiveTables activeTables]
activeTablesForFMID: [container objectId]
andType: MAPISTORE_MESSAGE_TABLE];
}
- (void) copyToMessage: (MAPIStoreMessage *) newMessage inMemCtx: (TALLOC_CTX *) memCtx;
{
//TALLOC_CTX *memCtx;
struct mapistore_message *messageData;
NSArray *keys;
NSUInteger count, max;
NSString *key;
MAPIStoreAttachment *attachment, *newAttachment;
//[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
//memCtx = talloc_zero (NULL, TALLOC_CTX);
/* message headers and recipients */
[self getMessageData: &messageData inMemCtx: memCtx];
[newMessage modifyRecipientsWithRecipients: messageData->recipients
andCount: messageData->recipients_count
andColumns: messageData->columns];
/* properties */
[self copyPropertiesToObject: newMessage inMemCtx: memCtx];
/* attachments */
keys = [self attachmentKeys];
max = [keys count];
for (count = 0; count < max; count++)
{
key = [keys objectAtIndex: count];
attachment = [self lookupAttachment: key];
newAttachment = [newMessage createAttachment];
[attachment copyToAttachment: newAttachment inMemCtx: memCtx];
}
//talloc_free (memCtx);
}
- (enum mapistore_error) saveMessage: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc;
NSArray *containerTables;
NSUInteger count, max;
MAPIStoreContext *context;
SOGoUser *ownerUser;
BOOL userIsOwner;
MAPIStoreMessage *mainMessage;
//[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
containerTables = nil;
max = 0;
context = [self context];
ownerUser = [[self userContext] sogoUser];
userIsOwner = [[context activeUser] isEqual: ownerUser];
if (userIsOwner)
mainMessage = nil;
else if ([self isKindOfClass: MAPIStoreEmbeddedMessageK])
mainMessage = (MAPIStoreMessage *) [[self container] container];
else
mainMessage = self;
if (userIsOwner
|| ([self isKindOfClass: MAPIStoreEmbeddedMessageK]
&& [mainMessage subscriberCanModifyMessage])
|| (![self isKindOfClass: MAPIStoreEmbeddedMessageK]
&& ((isNew
&& [(MAPIStoreFolder *) container subscriberCanCreateMessages])
|| (!isNew && [self subscriberCanModifyMessage]))))
{
/* notifications */
if ([container isKindOfClass: MAPIStoreFolderK])
{
/* we ensure the table caches are loaded so that old and new state
can be compared */
containerTables = [self activeContainerMessageTables];
max = [containerTables count];
for (count = 0; count < max; count++)
[[containerTables objectAtIndex: count] restrictedChildKeys];
}
[self save: memCtx];
/* We make sure that any change-related properties are removed from the
properties dictionary, to make sure that related methods will be
invoked the next time they are requested. */
[properties removeObjectForKey: MAPIPropertyKey (PidTagChangeKey)];
[properties removeObjectForKey: MAPIPropertyKey (PidTagChangeNumber)];
[properties removeObjectForKey: MAPIPropertyKey (PidTagPredecessorChangeList)];
if ([container isKindOfClass: MAPIStoreFolderK])
{
/* table modified */
for (count = 0; count < max; count++)
{
id table;
table = [containerTables objectAtIndex: count];
/* Safety check here as we could have MAPIStorePermissionsTable instances
in our containerTables array. This code might need to be reworked later */
if ([table respondsToSelector: @selector(notifyChangesForChild:)])
[table notifyChangesForChild: self];
}
[container cleanupCaches];
}
[self setIsNew: NO];
rc = MAPISTORE_SUCCESS;
}
else
rc = MAPISTORE_ERR_DENIED;
return rc;
}
/* getters */
- (int) getPidTagInstID: (void **) data // TODO: DOUBT
inMemCtx: (TALLOC_CTX *) memCtx
{
/* we return a unique id based on the key */
*data = MAPILongLongValue (memCtx, [[sogoObject nameInContainer] hash]);
return MAPISTORE_SUCCESS;
}
- (int) getPidTagInstanceNum: (void **) data // TODO: DOUBT
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getLongZero: data inMemCtx: memCtx];
}
- (int) getPidTagRowType: (void **) data // TODO: DOUBT
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPILongValue (memCtx, TBL_LEAF_ROW);
return MAPISTORE_SUCCESS;
}
- (int) getPidTagDepth: (void **) data // TODO: DOUBT
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPILongLongValue (memCtx, 0);
return MAPISTORE_SUCCESS;
}
/*
Possible values are:
0x00000001 Modify
0x00000002 Read
0x00000004 Delete
0x00000008 Create Hierarchy Table
0x00000010 Create Contents Table
0x00000020 Create Associated Contents Table
*/
- (int) getPidTagAccess: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
uint32_t access = 0;
BOOL userIsOwner;
MAPIStoreContext *context;
SOGoUser *ownerUser;
MAPIStoreMessage *mainMessage;
context = [self context];
ownerUser = [[self userContext] sogoUser];
userIsOwner = [[context activeUser] isEqual: ownerUser];
if (userIsOwner)
mainMessage = nil;
else if ([self isKindOfClass: MAPIStoreEmbeddedMessageK])
mainMessage = (MAPIStoreMessage *) [[self container] container];
else
mainMessage = self;
if (userIsOwner || [mainMessage subscriberCanModifyMessage])
access |= 0x01;
if (userIsOwner || [mainMessage subscriberCanReadMessage])
access |= 0x02;
if (userIsOwner
|| ([self isKindOfClass: MAPIStoreEmbeddedMessageK]
&& [mainMessage subscriberCanModifyMessage])
|| [(MAPIStoreFolder *)
[mainMessage container] subscriberCanDeleteMessages])
access |= 0x04;
*data = MAPILongValue (memCtx, access);
return MAPISTORE_SUCCESS;
}
/*
Possible values are:
0x00000000 Read-Only
0x00000001 Modify
*/
- (int) getPidTagAccessLevel: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
uint32_t access = 0;
BOOL userIsOwner;
MAPIStoreContext *context;
SOGoUser *ownerUser;
context = [self context];
ownerUser = [[self userContext] sogoUser];
userIsOwner = [[context activeUser] isEqual: ownerUser];
if (userIsOwner || [self subscriberCanModifyMessage])
access = 0x01;
else
access = 0;
*data = MAPILongValue (memCtx, access);
return MAPISTORE_SUCCESS;
}
- (int ) getPidTagHasNamedProperties: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getYes: data inMemCtx: memCtx];
}
- (int) getPidLidSideEffects: (void **) data // TODO
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getLongZero: data inMemCtx: memCtx];
}
- (int) getPidLidCurrentVersion: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
// *data = MAPILongValue (memCtx, 115608); // Outlook 11.5608
*data = MAPILongValue (memCtx, 0x1ce3a); // Outlook 11.8330
return MAPISTORE_SUCCESS;
}
- (int) getPidLidCurrentVersionName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"11.0" asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidLidAutoProcessState: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPILongValue (memCtx, 0x00000000);
return MAPISTORE_SUCCESS;
}
- (int) getPidTagFolderId: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPILongLongValue (memCtx, [container objectId]);
return MAPISTORE_SUCCESS;
}
- (int) getPidTagMid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
int rc;
uint64_t obId;
obId = [self objectId];
if (obId == ULLONG_MAX)
rc = MAPISTORE_ERR_NOT_FOUND;
else
{
*data = MAPILongLongValue (memCtx, obId);
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidTagMessageLocaleId: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPILongValue (memCtx, 0x0409);
return MAPISTORE_SUCCESS;
}
- (int) getPidTagMessageFlags: (void **) data // TODO
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPILongValue (memCtx, MSGFLAG_FROMME | MSGFLAG_READ | MSGFLAG_UNMODIFIED);
return MAPISTORE_SUCCESS;
}
- (int) getPidTagMessageSize: (void **) data // TODO
inMemCtx: (TALLOC_CTX *) memCtx
{
/* TODO: choose another name in SOGo for that method */
*data = MAPILongValue (memCtx, [[sogoObject davContentLength] intValue]);
return MAPISTORE_SUCCESS;
}
- (int) getPidTagImportance: (void **) data // TODO -> subclass?
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPILongValue (memCtx, 1);
return MAPISTORE_SUCCESS;
}
- (int) getPidTagPriority: (void **) data // TODO -> subclass?
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getLongZero: data inMemCtx: memCtx];
}
- (int) getPidTagSensitivity: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getLongZero: data inMemCtx: memCtx];
}
- (int) getPidTagSubject: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
int rc;
TALLOC_CTX *localMemCtx;
char *prefix, *normalizedSubject;
localMemCtx = talloc_zero (memCtx, TALLOC_CTX);
if ([self getProperty: (void **) &prefix
withTag: PidTagSubjectPrefix
inMemCtx: localMemCtx]
!= MAPISTORE_SUCCESS)
prefix = "";
rc = [self getProperty: (void **) &normalizedSubject
withTag: PidTagNormalizedSubject
inMemCtx: localMemCtx];
if (rc == MAPISTORE_SUCCESS)
*data = talloc_asprintf (memCtx, "%s%s", prefix, normalizedSubject);
talloc_free(localMemCtx);
return rc;
}
- (int) getPidTagNormalizedSubject: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return MAPISTORE_ERR_NOT_FOUND;
}
- (int) getPidTagOriginalSubject: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidTagSubject: data inMemCtx: memCtx];
}
- (int) getPidTagConversationTopic: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidTagNormalizedSubject: data inMemCtx: memCtx];
}
- (int) getPidTagSubjectPrefix: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getEmptyString: data inMemCtx: memCtx];
}
- (int) getPidTagDeleteAfterSubmit: (void **) data // TODO
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getNo: data inMemCtx: memCtx];
}
- (int) getPidTagDisplayTo: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getEmptyString: data inMemCtx: memCtx];
}
- (int) getPidTagDisplayCc: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getEmptyString: data inMemCtx: memCtx];
}
- (int) getPidTagDisplayBcc: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getEmptyString: data inMemCtx: memCtx];
}
// - (int) getPidTagOriginalDisplayTo: (void **) data
// {
// return [self getPidTagDisplayTo: data];
// }
// - (int) getPidTagOriginalDisplayCc: (void **) data
// {
// return [self getPidTagDisplayCc: data];
// }
// - (int) getPidTagOriginalDisplayBcc: (void **) data
// {
// return [self getPidTagDisplayBcc: data];
// }
- (int) getPidTagLastModifierName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSURL *contextUrl;
contextUrl = (NSURL *) [[self context] url];
*data = [[contextUrl user] asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidTagMessageClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
[self subclassResponsibility: _cmd];
return MAPISTORE_ERR_NOT_FOUND;
}
- (int) getPidTagOriginalMessageClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getProperty: data withTag: PidTagMessageClass inMemCtx: memCtx];
}
- (int) getPidTagHasAttachments: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPIBoolValue (memCtx,
[[self attachmentKeys] count] > 0);
return MAPISTORE_SUCCESS;
}
- (int) getPidTagAssociated: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getNo: data inMemCtx: memCtx];;
}
- (enum mapistore_error) setReadFlag: (uint8_t) flag
{
// [self subclassResponsibility: _cmd];
return MAPISTORE_ERROR;
}
- (void) save: (TALLOC_CTX *) memCtx
{
[self subclassResponsibility: _cmd];
}
- (NSArray *) attachmentKeys
{
if (!attachmentKeys)
{
attachmentKeys = [self attachmentKeysMatchingQualifier: nil
andSortOrderings: nil];
[attachmentKeys retain];
}
return attachmentKeys;
}
- (NSArray *) attachmentKeysMatchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings
{
if (qualifier)
[self errorWithFormat: @"qualifier is not used for attachments"];
if (sortOrderings)
[self errorWithFormat: @"sort orderings are not used for attachments"];
return [attachmentParts allKeys];
}
- (MAPIStoreAttachmentTable *) attachmentTable
{
return [MAPIStoreAttachmentTable tableForContainer: self];
}
- (void) addActiveTable: (MAPIStoreTable *) activeTable
{
[activeTables addObject: activeTable];
}
- (void) removeActiveTable: (MAPIStoreTable *) activeTable
{
[activeTables removeObject: activeTable];
}
- (NSArray *) activeUserRoles
{
MAPIStoreContext *context;
MAPIStoreUserContext *userContext;
if (!activeUserRoles)
{
context = [self context];
userContext = [self userContext];
activeUserRoles = [[context activeUser]
rolesForObject: sogoObject
inContext: [userContext woContext]];
[activeUserRoles retain];
}
return activeUserRoles;
}
- (BOOL) subscriberCanReadMessage
{
return NO;
}
- (BOOL) subscriberCanModifyMessage
{
return NO;
}
@end