See ChangeLog

Monotone-Parent: 8027e57cbf5cbb4ab2ee6bf9509fe2f571f150c1
Monotone-Revision: 0ffde732abb09a8e3d0382ed47a3ec787f25796e

Monotone-Author: ludovic@Sophos.ca
Monotone-Date: 2011-09-14T18:33:44
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Ludovic Marcotte 2011-09-14 18:33:44 +00:00
parent 8fb4411dd6
commit 057a38355b
22 changed files with 713 additions and 47 deletions

View File

@ -1,3 +1,26 @@
2011-09-14 Ludovic Marcotte <lmarcotte@inverse.ca>
* SoObjects/Mailer/SOGoMailBaseObject.m: (imap4Connection):
Cache "corruption" bug fix that could lead us to using the
wrong IMAP connection for OpenChange users
* OpenChange/MAPIStoreMapping.m: (unregisterURLWithID:)
We also remove the keys/values from the indexing database
* OpenChange/MAPIStoreSOGo.m
RopMoveCopyMessages, RopCopyTo and messages move/copy
notifications support for messages
* OpenChange/MAPIStoreContactsMessage.m: massive improvements
to support many new properties
* OpenChange/MAPIStoreTasksMessage.m: massive improvements
to support many new properties
* OpenChange/MAPIStoreFolder.m: (getPrAccess:inMemCtx:) fixed
permissions issue - we were returning a wrong value leading to
IMAP subfolders not being "writable"
2011-09-04 Ludovic Marcotte <lmarcotte@inverse.ca>
* OpenChange/MAPIStoreMapping.m: (MAPIStoreMappingTDBTraverse())

View File

@ -100,7 +100,7 @@ static Class MAPIStoreCalendarMessageK;
return componentQualifier;
}
- (MAPIStoreMessage *) createMessage
- (MAPIStoreMessage *) createMessageWithMID: (uint64_t) mid
{
MAPIStoreMessage *newMessage;
SOGoAppointmentObject *newEntry;

View File

@ -103,7 +103,7 @@ static Class MAPIStoreContactsMessageK;
return componentQualifier;
}
- (MAPIStoreMessage *) createMessage
- (MAPIStoreMessage *) createMessageWithMID: (uint64_t) mid
{
MAPIStoreMessage *newMessage;
SOGoContactGCSEntry *newEntry;

View File

@ -3,6 +3,7 @@
* Copyright (C) 2011 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Ludovic Marcotte <lmarcotte@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
@ -50,6 +51,31 @@
@implementation MAPIStoreContactsMessage
// 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) getPrIconIndex: (void **) data // TODO
inMemCtx: (TALLOC_CTX *) memCtx
{
@ -352,6 +378,13 @@
atPos: 0 inData: data inMemCtx: memCtx];
}
- (int) getPrPagerTelephoneNumber: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getElement: @"tel" ofType: @"pager" excluding: nil
atPos: 0 inData: data inMemCtx: memCtx];
}
- (int) getPrPrimaryTelephoneNumber: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@ -359,6 +392,13 @@
atPos: 0 inData: data inMemCtx: memCtx];
}
- (int) getPrBusinessFaxNumber: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getElement: @"tel" ofType: @"fax" excluding: nil
atPos: 0 inData: data inMemCtx: memCtx];
}
- (int) getPrBusinessHomePage: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@ -432,6 +472,10 @@
return MAPISTORE_SUCCESS;
}
//
// getters when no address is selected as the Mailing Address
//
- (int) getPrPostalAddress: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@ -481,6 +525,60 @@
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) getPrHomeAddressPostOfficeBox: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getElement: @"adr" ofType: @"home" excluding: nil
atPos: 0 inData: data inMemCtx: memCtx];
}
- (int) getPrHomeAddressStreet: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getElement: @"adr" ofType: @"home" excluding: nil
atPos: 2 inData: data inMemCtx: memCtx];
}
- (int) getPrHomeAddressCity: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getElement: @"adr" ofType: @"home" excluding: nil
atPos: 3 inData: data inMemCtx: memCtx];
}
- (int) getPrHomeAddressStateOrProvince: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getElement: @"adr" ofType: @"home" excluding: nil
atPos: 4 inData: data inMemCtx: memCtx];
}
- (int) getPrHomeAddressPostalCode: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getElement: @"adr" ofType: @"home" excluding: nil
atPos: 5 inData: data inMemCtx: memCtx];
}
- (int) getPrHomeAddressCountry: (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
{
@ -530,6 +628,9 @@
atPos: 6 inData: data inMemCtx: memCtx];
}
//
//
//
- (int) getPrNickname: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@ -565,9 +666,10 @@
- (void) save
{
NGVCard *newCard;
NSArray *elements;
NSArray *elements, *units;
CardElement *element;
NGVCard *newCard;
int postalAddressId;
id value;
@ -578,14 +680,26 @@
[newCard setVersion: @"3.0"];
[newCard setProdID: @"-//Inverse inc.//OpenChange+SOGo//EN"];
[newCard setProfile: @"vCard"];
// Decomposed fullname
[newCard setNWithFamily: [newProperties objectForKey: MAPIPropertyKey(PR_SURNAME_UNICODE)]
given: [newProperties objectForKey: MAPIPropertyKey(PR_GIVEN_NAME_UNICODE)]
additional: [newProperties objectForKey: MAPIPropertyKey(PR_MIDDLE_NAME_UNICODE)]
prefixes: [newProperties objectForKey: MAPIPropertyKey(PR_DISPLAY_NAME_PREFIX_UNICODE)]
suffixes: [newProperties objectForKey: MAPIPropertyKey(PR_GENERATION_UNICODE)]];
value = [newProperties
objectForKey: MAPIPropertyKey (PR_DISPLAY_NAME_UNICODE)];
//
// display name
//
value = [newProperties objectForKey: MAPIPropertyKey(PR_DISPLAY_NAME_UNICODE)];
if (value)
[newCard setFn: value];
//
// email addresses handling
//
elements = [newCard childrenWithTag: @"email"];
value = [newProperties objectForKey: MAPIPropertyKey (PidLidEmail1EmailAddress)];
value = [newProperties objectForKey: MAPIPropertyKey(PidLidEmail1EmailAddress)];
if (value)
{
if ([elements count] > 0)
@ -611,11 +725,21 @@
[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 = [[newProperties objectForKey: MAPIPropertyKey (PidLidPostalAddressId)]
intValue];
/* Work address */
value = [newProperties objectForKey: MAPIPropertyKey (PidLidWorkAddress)];
value = [newProperties objectForKey: MAPIPropertyKey(PidLidWorkAddress)];
if ([value length])
{
elements = [newCard childrenWithTag: @"label"
@ -652,25 +776,154 @@
}
if (postalAddressId == 2)
[element addAttribute: @"type" value: @"pref"];
value = [newProperties objectForKey: MAPIPropertyKey (PidLidWorkAddressPostOfficeBox)];
value = [newProperties objectForKey: MAPIPropertyKey(PidLidWorkAddressPostOfficeBox)];
if (value)
[element setValue: 0 to: value];
value = [newProperties objectForKey: MAPIPropertyKey (PidLidWorkAddressStreet)];
value = [newProperties objectForKey: MAPIPropertyKey(PidLidWorkAddressStreet)];
if (value)
[element setValue: 2 to: value];
value = [newProperties objectForKey: MAPIPropertyKey (PidLidWorkAddressCity)];
value = [newProperties objectForKey: MAPIPropertyKey(PidLidWorkAddressCity)];
if (value)
[element setValue: 3 to: value];
value = [newProperties objectForKey: MAPIPropertyKey (PidLidWorkAddressState)];
value = [newProperties objectForKey: MAPIPropertyKey(PidLidWorkAddressState)];
if (value)
[element setValue: 4 to: value];
value = [newProperties objectForKey: MAPIPropertyKey (PidLidWorkAddressPostalCode)];
value = [newProperties objectForKey: MAPIPropertyKey(PidLidWorkAddressPostalCode)];
if (value)
[element setValue: 5 to: value];
value = [newProperties objectForKey: MAPIPropertyKey (PidLidWorkAddressCountry)];
value = [newProperties objectForKey: MAPIPropertyKey(PidLidWorkAddressCountry)];
if (value)
[element setValue: 6 to: value];
//
// home postal addresses handling
//
value = [newProperties 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 setValue: 0 to: value];
}
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 = [newProperties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_POST_OFFICE_BOX_UNICODE)];
if (value)
[element setValue: 0 to: value];
value = [newProperties objectForKey: MAPIPropertyKey( PR_HOME_ADDRESS_STREET_UNICODE)];
if (value)
[element setValue: 2 to: value];
value = [newProperties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_CITY_UNICODE)];
if (value)
[element setValue: 3 to: value];
value = [newProperties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_STATE_OR_PROVINCE_UNICODE)];
if (value)
[element setValue: 4 to: value];
value = [newProperties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_POSTAL_CODE_UNICODE)];
if (value)
[element setValue: 5 to: value];
value = [newProperties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_COUNTRY_UNICODE)];
if (value)
[element setValue: 6 to: value];
//
// telephone numbers: work, home, fax, pager and mobile
//
element = [self _elementWithTag: @"tel" ofType: @"work" forCard: newCard];
value = [newProperties objectForKey: MAPIPropertyKey(PR_OFFICE_TELEPHONE_NUMBER_UNICODE)];
if (value)
[element setValue: 0 to: value];
element = [self _elementWithTag: @"tel" ofType: @"home" forCard: newCard];
value = [newProperties objectForKey: MAPIPropertyKey(PR_HOME_TELEPHONE_NUMBER_UNICODE)];
if (value)
[element setValue: 0 to: value];
element = [self _elementWithTag: @"tel" ofType: @"fax" forCard: newCard];
value = [newProperties objectForKey: MAPIPropertyKey(PR_BUSINESS_FAX_NUMBER_UNICODE)];
if (value)
[element setValue: 0 to: value];
element = [self _elementWithTag: @"tel" ofType: @"pager" forCard: newCard];
value = [newProperties objectForKey: MAPIPropertyKey(PR_PAGER_TELEPHONE_NUMBER_UNICODE)];
if (value)
[element setValue: 0 to: value];
element = [self _elementWithTag: @"tel" ofType: @"cell" forCard: newCard];
value = [newProperties objectForKey: MAPIPropertyKey(PR_MOBILE_TELEPHONE_NUMBER_UNICODE)];
if (value)
[element setValue: 0 to: value];
//
// job title, nickname, company name, deparment, work url, im address/screen name
//
value = [newProperties objectForKey: MAPIPropertyKey(PR_TITLE_UNICODE)];
if (value)
[newCard setTitle: value];
value = [newProperties objectForKey: MAPIPropertyKey(PR_NICKNAME_UNICODE)];
if (value)
[newCard setNickname: value];
value = [newProperties objectForKey: MAPIPropertyKey(PR_DEPARTMENT_NAME_UNICODE)];
if (value)
units = [NSArray arrayWithObject: value];
else
units = nil;
value = [newProperties objectForKey: MAPIPropertyKey(PR_COMPANY_NAME_UNICODE)];
if (value)
[newCard setOrg: value units: units];
value = [newProperties objectForKey: MAPIPropertyKey(PR_BUSINESS_HOME_PAGE_UNICODE)];
if (value)
{
[[self _elementWithTag: @"url" ofType: @"work" forCard: newCard]
setValue: 0 to: value];
}
value = [newProperties objectForKey: MAPIPropertyKey(PidLidInstantMessagingAddress)];
if (value)
{
[[newCard uniqueChildWithTag: @"x-aim"]
setValue: 0
to: value];
}
//
// we save the new/modified card
//
[sogoObject saveContentString: [newCard versitString]];
[(MAPIStoreContactsFolder *) container synchroniseCache];
}

View File

@ -100,7 +100,7 @@ static Class EOKeyValueQualifierK, MAPIStoreFSMessageK;
return newKey;
}
- (MAPIStoreMessage *) createMessage
- (MAPIStoreMessage *) createMessageWithMID: (uint64_t) mid
{
MAPIStoreMessage *newMessage;
SOGoMAPIFSMessage *fsObject;

View File

@ -43,6 +43,7 @@
@class SOGoMAPIFSFolder;
@class SOGoMAPIFSMessage;
#import "MAPIStoreObject.h"
@interface MAPIStoreFolder : MAPIStoreObject
@ -94,7 +95,8 @@
- (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings;
- (MAPIStoreMessage *) createMessage: (BOOL) isAssociated;
- (MAPIStoreMessage *) createMessageWithMID: (uint64_t) mid
isAssociated: (BOOL) isAssociated;
/* backend interface */
@ -110,12 +112,18 @@
- (int) createMessage: (MAPIStoreMessage **) messagePtr
withMID: (uint64_t) mid
isAssociated: (BOOL) isAssociated;
- (int) openMessage: (MAPIStoreMessage **) messagePtr
andMessageData: (struct mapistore_message **) dataPtr
withMID: (uint64_t) mid
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) deleteMessageWithMID: (uint64_t) mid
andFlags: (uint8_t) flags;
- (int) moveCopyMessageWithMID: (uint64_t) mid
toFolder: (MAPIStoreFolder *) targetFolder
inMessage: (MAPIStoreMessage *) targetMessage
wantCopy: (uint8_t) want_copy;
- (int) getDeletedFMIDs: (struct I8Array_r **) fmidsPtr
andCN: (uint64_t *) cnPtr
fromChangeNumber: (uint64_t) changeNum
@ -132,7 +140,7 @@
/* subclasses */
- (Class) messageClass;
- (MAPIStoreMessage *) createMessage;
- (MAPIStoreMessage *) createMessageWithMID: (uint64_t) mid;
- (MAPIStoreMessageTable *) messageTable;
- (NSArray *) messageKeysMatchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings;

View File

@ -437,7 +437,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
rc = MAPISTORE_ERR_EXIST;
else
{
message = [self createMessage: isAssociated];
message = [self createMessageWithMID: mid
isAssociated: isAssociated];
if (message)
{
baseURL = [self url];
@ -551,6 +552,18 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
return rc;
}
- (int) moveCopyMessageWithMID: (uint64_t) mid
toFolder: (MAPIStoreFolder *) targetFolder
inMessage: (MAPIStoreMessage *) targetMessage
wantCopy: (uint8_t) want_copy
{
int rc;
rc = MAPISTORE_SUCCESS;
return rc;
}
- (int) getDeletedFMIDs: (struct I8Array_r **) fmidsPtr
andCN: (uint64_t *) cnPtr
fromChangeNumber: (uint64_t) changeNum
@ -814,14 +827,30 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
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) getPrAccess: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPILongValue (memCtx, 0x63);
*data = MAPILongValue (memCtx, 0x1|0x2|0x4|0x8|0x10|0x20);
return MAPISTORE_SUCCESS;
}
/*
Possible values are:
0x00000000 Read-Only
0x00000001 Modify
*/
- (int) getPrAccessLevel: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@ -938,7 +967,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
return newMessage;
}
- (MAPIStoreMessage *) createMessage: (BOOL) isAssociated
- (MAPIStoreMessage *) createMessageWithMID: (uint64_t) mid
isAssociated: (BOOL) isAssociated
{
MAPIStoreMessage *newMessage;
WOContext *woContext;
@ -946,7 +976,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (isAssociated)
newMessage = [self _createAssociatedMessage];
else
newMessage = [self createMessage];
newMessage = [self createMessageWithMID: mid];
[newMessage setIsNew: YES];
woContext = [[self context] woContext];
[[newMessage sogoObject] setContext: woContext];
@ -1038,7 +1068,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
return Nil;
}
- (MAPIStoreMessage *) createMessage
- (MAPIStoreMessage *) createMessageWithMID: (uint64_t) mid
{
[self logWithFormat: @"ignored method: %s", __PRETTY_FUNCTION__];
return nil;

View File

@ -26,12 +26,14 @@
#import "MAPIStoreFolder.h"
@class NSCalendarDate;
@class NSMutableDictionary;
@class NSNumber;
@class NSString;
@interface MAPIStoreGCSFolder : MAPIStoreFolder
{
SOGoMAPIFSMessage *versionsMessage;
NSMutableDictionary *initialVersions;
}
/* synchronisation */
@ -42,6 +44,9 @@
/* subclasses */
- (EOQualifier *) componentQualifier;
- (void) setInitialVersion: (uint64_t) version
forMessage: (NSString *) theMessage;
@end
#endif /* MAPISTOREGCSFOLDER_H */

View File

@ -50,7 +50,9 @@
{
ASSIGN (versionsMessage,
[SOGoMAPIFSMessage objectWithName: @"versions.plist"
inContainer: propsFolder]);
inContainer: propsFolder]);
initialVersions = [[NSMutableDictionary alloc] init];
}
return self;
@ -64,6 +66,8 @@
ASSIGN (versionsMessage,
[SOGoMAPIFSMessage objectWithName: @"versions.plist"
inContainer: propsFolder]);
initialVersions = [[NSMutableDictionary alloc] init];
}
return self;
@ -72,6 +76,7 @@
- (void) dealloc
{
[versionsMessage release];
[initialVersions release];
[super dealloc];
}
@ -247,7 +252,14 @@
{
foundChange = YES;
newChangeNum = [[self context] getNewChangeNumber];
//if ([[messageEntry objectForKey: @"c_version"] intValue] == 0)
// newChangeNum = [[initialVersions objectForKey: cName] unsignedLongLongValue];
//else
{
newChangeNum = [[self context] getNewChangeNumber];
[initialVersions removeObjectForKey: cName];
}
changeNumber = [NSNumber numberWithUnsignedLongLong: newChangeNum];
[messageEntry setObject: cLastModified forKey: @"c_lastmodified"];
@ -398,4 +410,11 @@
return nil;
}
- (void) setInitialVersion: (uint64_t) version
forMessage: (NSString *) theMessage
{
[initialVersions setObject: [NSNumber numberWithUnsignedLongLong: version]
forKey: theMessage];
}
@end

View File

@ -26,6 +26,11 @@
#import "MAPIStoreMessage.h"
@interface MAPIStoreGCSMessage : MAPIStoreMessage
{
@private
uint64_t _version;
}
@end
#endif /* MAPISTOREGCSMESSAGE_H */

View File

@ -24,6 +24,7 @@
#import <NGExtensions/NSObject+Logs.h>
#import <SOGo/SOGoContentObject.h>
#import "MAPIStoreContext.h"
#import "MAPIStoreGCSFolder.h"
#import "MAPIStoreTypes.h"
@ -34,6 +35,16 @@
@implementation MAPIStoreGCSMessage
- (id) init
{
if ((self = [super init]))
{
_version = 0xffffffffffffffffLL;
}
return self;
}
- (NSCalendarDate *) creationTime
{
return [sogoObject creationDate];
@ -48,8 +59,20 @@
{
uint64_t version = 0xffffffffffffffffLL;
NSNumber *changeNumber;
if (![sogoObject isNew])
if ([sogoObject isNew])
{
#if 0
if (_version == 0xffffffffffffffffLL)
{
_version = [[self context] getNewChangeNumber];
[(MAPIStoreGCSFolder *)[self container] setInitialVersion: _version
forMessage: [self nameInContainer]];
}
version = _version;
#endif
}
else
{
changeNumber = [(MAPIStoreGCSFolder *) container
changeNumberForMessageWithKey: [self nameInContainer]];
@ -66,7 +89,7 @@
else
{
[self errorWithFormat: @"still nothing. We crash!"];
abort ();
abort();
}
}
version = [changeNumber unsignedLongLongValue] >> 16;

View File

@ -38,6 +38,7 @@
#import <Mailer/SOGoMailAccount.h>
#import <Mailer/SOGoMailAccounts.h>
#import <Mailer/SOGoMailFolder.h>
#import <Mailer/SOGoMailObject.h>
#import <Mailer/SOGoSentFolder.h>
#import <Mailer/SOGoTrashFolder.h>
#import <SOGo/NSArray+Utilities.h>
@ -47,8 +48,10 @@
#import "MAPIStoreAppointmentWrapper.h"
#import "MAPIStoreContext.h"
#import "MAPIStoreDraftsMessage.h"
#import "MAPIStoreFAIMessage.h"
#import "MAPIStoreMailMessage.h"
#import "MAPIStoreMailMessageTable.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreTypes.h"
#import "NSString+MAPIStore.h"
#import "SOGoMAPIFSMessage.h"
@ -62,6 +65,7 @@ static Class SOGoMailFolderK;
#undef DEBUG
#include <libmapi/libmapi.h>
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
@implementation MAPIStoreMailFolder
@ -631,6 +635,187 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
return deletedKeys;
}
//
// We need to support creating "fake" emails for RopCopyTo and other
// other ROPs to function properly. We don't know what will be the
// object's name (as it's the IMAP's UID) until the message really
// is created in the mail store.
//
- (MAPIStoreMessage *) createMessageWithMID: (uint64_t) mid
{
MAPIStoreMessage *message;
SOGoMailObject *mail;
mail = [SOGoMailObject objectWithName: [NSString stringWithFormat: @"%llu", mid]
inContainer: sogoObject];
message = [MAPIStoreMailMessage mapiStoreObjectWithSOGoObject: mail
inContainer: self];
return message;
}
//
// Move (or eventually copy) the mail identified by
// "mid" within this current folder. The message is
// of course coming from an other folder
//
- (int) moveCopyMessageWithMID: (uint64_t) mid
toFolder: (MAPIStoreFolder *) targetFolder
inMessage: (MAPIStoreMessage *) targetMessage
wantCopy: (uint8_t) want_copy
{
NSString *folderName, *messageURL, *uid, *url, *v;
MAPIStoreMapping *mapping;
NSDictionary *result;
unsigned int new_uid;
uint64_t target_mid;
int rc;
mapping = [[self context] mapping];
messageURL = [mapping urlFromID: mid];
if (messageURL)
{
// We get the message UID from that folder by stripping the .eml
// This is the message we'll copy in the folder specified by targetURL
uid = [messageURL lastPathComponent];
uid = [uid substringToIndex: [uid length] - 4];
folderName = [[targetFolder sogoObject] relativeImap4Name];
if (uid && [folderName length] > 0)
{
struct mapistore_object_notification_parameters *notif_parameters;
struct mapistore_connection_info *connInfo;
NGImap4Client *client;
NSArray *a;
// We copy the message, get the new UID and set the old one as deleted
client = [[[self sogoObject] imap4Connection] client];
[client select: [[self sogoObject] relativeImap4Name]];
result = [client copyUid: [uid intValue] toFolder: folderName];
if (!want_copy)
[client storeUid: [uid intValue] add: [NSNumber numberWithBool: YES] flags: [NSArray arrayWithObject: @"Deleted"]];
//
// We use the UIDPLUS IMAP extension here in order to speedup UID retreival
// If supported by the server, we'll get something like: COPYUID 1315425789 1 8
//
// Sometimes COPYUID isn't returned at all by Cyrus or in case the server doesn't
// support the UIDPLUS IMAP extension, we fallback to a simple UID search.
//
v = [[[result objectForKey: @"RawResponse"] objectForKey: @"ResponseResult"] objectForKey: @"flag"];
if (v)
{
unsigned int current_uid, uid_validity;
const char *s;
char tag[7];
s = [v cStringUsingEncoding: NSASCIIStringEncoding];
sscanf(s, "%s %u %u %u", tag, &uid_validity, &current_uid, &new_uid);
}
else
{
[client select: folderName];
a = [[client sort: @"ARRIVAL" qualifier: nil encoding: @"UTF-8"] objectForKey: @"sort"];
new_uid = [[[a sortedArrayUsingSelector: @selector(compare:)] lastObject] intValue];
}
// We compute the URL of the move message and update our mapping
url = [NSString stringWithFormat: @"%@%d.eml", [targetFolder url], new_uid];
if (!want_copy)
[mapping unregisterURLWithID: mid];
// We adjust its name within the container with the newly obtained UID. This was previously the
// MID of the message and that value was temporary since we created a "fake" message
target_mid = strtoull([[[targetMessage sogoObject] nameInContainer] UTF8String], NULL, 10);
[[targetMessage sogoObject] setNameInContainer: [NSString stringWithFormat: @"%u.eml", new_uid]];
// We unregister the previously (and temporary) registered mid and register
// it again with its new and valid URL
[mapping unregisterURLWithID: target_mid];
[mapping registerURL: url withID: target_mid];
NSArray *activeTables;
NSUInteger count, max;
/* we ensure the table caches are loaded so that old and new state
can be compared */
MAPIStoreMessage *message;
message = [self lookupMessageByURL: messageURL];
activeTables = ([message isKindOfClass: [MAPIStoreFAIMessage class]]
? [self activeFAIMessageTables]
: [self activeMessageTables]);
max = [activeTables count];
for (count = 0; count < max; count++)
[[activeTables objectAtIndex: count] restrictedChildKeys];
// We notify the client
notif_parameters = talloc_zero(NULL, struct mapistore_object_notification_parameters);
notif_parameters->object_id = [self objectId];
notif_parameters->tag_count = 5;
notif_parameters->tags = talloc_array (notif_parameters, enum MAPITAGS, 5);
notif_parameters->tags[0] = PR_CONTENT_COUNT;
notif_parameters->tags[1] = PR_DELETED_COUNT_TOTAL;
notif_parameters->tags[2] = PR_MESSAGE_SIZE;
notif_parameters->tags[3] = PR_NORMAL_MESSAGE_SIZE;
notif_parameters->tags[4] = PR_RECIPIENT_ON_NORMAL_MSG_COUNT;
notif_parameters->new_message_count = true;
notif_parameters->message_count = [[self messageKeys] count];
connInfo = [[self context] connectionInfo];
mapistore_push_notification (connInfo->mstore_ctx,
MAPISTORE_FOLDER,
MAPISTORE_OBJECT_MODIFIED,
notif_parameters);
talloc_free(notif_parameters);
/* move/copy notification */
notif_parameters = talloc_zero(NULL, struct mapistore_object_notification_parameters);
notif_parameters->tag_count = 0;
notif_parameters->new_message_count = true;
notif_parameters->message_count = 0;
notif_parameters->object_id = target_mid;
notif_parameters->folder_id = [targetFolder objectId];
notif_parameters->old_object_id = mid;
notif_parameters->old_folder_id = [self objectId];
mapistore_push_notification (connInfo->mstore_ctx,
MAPISTORE_MESSAGE,
(want_copy ? MAPISTORE_OBJECT_COPIED : MAPISTORE_OBJECT_MOVED),
notif_parameters);
talloc_free(notif_parameters);
/* table notification */
for (count = 0; count < max; count++)
[[activeTables objectAtIndex: count]
notifyChangesForChild: message];
// We cleanup cache of our source and destionation folders
[self cleanupCaches];
[targetFolder cleanupCaches];
rc = MAPISTORE_SUCCESS;
}
else
rc = MAPISTORE_ERR_NOT_FOUND;
}
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
@end
@implementation MAPIStoreInboxFolder : MAPIStoreMailFolder
@ -781,6 +966,10 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
// @end
//
//
//
@implementation MAPIStoreOutboxFolder : MAPIStoreMailFolder
+ (void) initialize
@ -799,7 +988,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
return MAPIStoreDraftsMessageK;
}
- (MAPIStoreMessage *) createMessage
- (MAPIStoreMessage *) createMessageWithMID: (uint64_t) mid
{
MAPIStoreDraftsMessage *newMessage;
SOGoDraftObject *newDraft;
@ -808,7 +997,6 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
newMessage
= [MAPIStoreDraftsMessage mapiStoreObjectWithSOGoObject: newDraft
inContainer: self];
return newMessage;
}

View File

@ -29,6 +29,7 @@
@class NSString;
@class MAPIStoreAppointmentWrapper;
@class MAPIStoreMailFolder;
@interface MAPIStoreMailMessage : MAPIStoreMessage
{

View File

@ -3,6 +3,7 @@
* Copyright (C) 2011 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Ludovic Marcotte <lmarcotte@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
@ -24,6 +25,8 @@
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGImap4/NGImap4Client.h>
#import <NGImap4/NGImap4Connection.h>
#import <NGImap4/NGImap4EnvelopeAddress.h>
#import <NGCards/iCalCalendar.h>
#import <SOGo/NSArray+Utilities.h>
@ -40,6 +43,7 @@
#import "MAPIStoreFolder.h"
#import "MAPIStoreMailAttachment.h"
#import "MAPIStoreMailFolder.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreMailMessage.h"
@ -289,13 +293,13 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
else
{
[self errorWithFormat: @"still nothing. We crash!"];
abort ();
abort();
}
}
version = [changeNumber unsignedLongLongValue] >> 16;
}
else
abort ();
abort();
return version;
}

View File

@ -55,7 +55,7 @@ MAPIStoreMappingTDBTraverse (TDB_CONTEXT *ctx, TDB_DATA data1, TDB_DATA data2,
NSNumber *idNbr;
NSString *uri;
char *idStr, *uriStr;
long long unsigned int idVal;
uint64_t idVal;
// get the key
// key examples : key(18) = "0x6900000000000001"
@ -239,13 +239,21 @@ MAPIStoreMappingTDBTraverse (TDB_CONTEXT *ctx, TDB_DATA data1, TDB_DATA data2,
- (void) unregisterURLWithID: (uint64_t) idNbr
{
NSNumber *idKey;
NSString *urlString;
NSNumber *idKey;
TDB_DATA key;
idKey = [NSNumber numberWithUnsignedLongLong: idNbr];
urlString = [mapping objectForKey: idKey];
[reverseMapping removeObjectForKey: urlString];
[mapping removeObjectForKey: idKey];
/* We hard-delete the entry from the indexing database */
key.dptr = (unsigned char *) talloc_asprintf(NULL, "0x%.16"PRIx64, idNbr);
key.dsize = strlen((const char *) key.dptr);
tdb_delete(indexing->tdb, key);
talloc_free(key.dptr);
}
@end

View File

@ -402,7 +402,8 @@ sogo_folder_create_message(void *folder_object,
folder = wrapper->MAPIStoreSOGoObject;
pool = [NSAutoreleasePool new];
rc = [folder createMessage: &message
withMID: mid isAssociated: associated];
withMID: mid
isAssociated: associated];
if (rc == MAPISTORE_SUCCESS)
*message_object = [message tallocWrapper: mem_ctx];
[pool release];
@ -441,6 +442,44 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags)
return rc;
}
static int
sogo_folder_move_copy_message(void *folder_object, uint64_t mid, void *target_folder, void *target_message, uint8_t want_copy)
{
MAPIStoreFolder *sourceFolder, *targetFolder;
MAPIStoreMessage *targetMessage;
NSAutoreleasePool *pool;
struct MAPIStoreTallocWrapper *wrapper;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
sourceFolder = wrapper->MAPIStoreSOGoObject;
wrapper = target_folder;
targetFolder = wrapper->MAPIStoreSOGoObject;
wrapper = target_message;
targetMessage = wrapper->MAPIStoreSOGoObject;
pool = [NSAutoreleasePool new];
rc = [sourceFolder moveCopyMessageWithMID: mid
toFolder: targetFolder
inMessage: targetMessage
wantCopy: want_copy];
[pool release];
}
else
{
rc = sogo_backend_unexpected_error();
}
return rc;
}
static int
sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx,
uint8_t table_type, uint64_t change_num,
@ -1031,6 +1070,7 @@ int mapistore_init_backend(void)
backend.folder.open_message = sogo_folder_open_message;
backend.folder.create_message = sogo_folder_create_message;
backend.folder.delete_message = sogo_folder_delete_message;
backend.folder.move_copy_message = sogo_folder_move_copy_message;
backend.folder.get_deleted_fmids = sogo_folder_get_deleted_fmids;
backend.folder.get_child_count = sogo_folder_get_child_count;
backend.folder.open_table = sogo_folder_open_table;

View File

@ -100,7 +100,7 @@ static Class MAPIStoreTasksMessageK;
return componentQualifier;
}
- (MAPIStoreMessage *) createMessage
- (MAPIStoreMessage *) createMessageWithMID: (uint64_t) mid
{
MAPIStoreMessage *newMessage;
SOGoTaskObject *newEntry;

View File

@ -3,6 +3,7 @@
* Copyright (C) 2011 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Ludovic Marcotte <lmarcotte@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
@ -209,6 +210,24 @@
return rc;
}
- (int) getPidLidTaskStartDate: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
int rc = MAPISTORE_SUCCESS;
NSCalendarDate *dateValue;
iCalToDo *task;
task = [sogoObject component: NO secure: NO];
dateValue = [task startDate];
if (dateValue)
*data = [dateValue asFileTimeInMemCtx: memCtx];
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (int) getPrMessageDeliveryTime: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@ -253,7 +272,11 @@
- (int) getPidLidTaskOwner: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"openchange@example.com" asUnicodeInMemCtx: memCtx];
NSString *owner;
owner = [sogoObject ownerInContext: nil];
*data = [owner asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
@ -292,17 +315,17 @@
if (value)
[vToDo setComment: value];
// Location
// location
value = [newProperties objectForKey: MAPIPropertyKey (PidLidLocation)];
if (value)
[vToDo setLocation: value];
/* created */
// created
value = [newProperties objectForKey: MAPIPropertyKey (PR_CREATION_TIME)];
if (value)
[vToDo setCreated: value];
/* last-modified + dtstamp */
// last-modified + dtstamp
value = [newProperties objectForKey: MAPIPropertyKey (PR_LAST_MODIFICATION_TIME)];
if (value)
{
@ -322,6 +345,10 @@
[date setTimeZone: tz];
[date setDateTime: value];
}
else
{
[vToDo setStartDate: nil];
}
// due
value = [newProperties objectForKey: MAPIPropertyKey (PidLidTaskDueDate)];
@ -331,6 +358,23 @@
[date setTimeZone: tz];
[date setDateTime: value];
}
else
{
[vToDo setDue: nil];
}
// completed
value = [newProperties objectForKey: MAPIPropertyKey (PidLidTaskDateCompleted)];
if (value)
{
date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"completed"];
[date setTimeZone: tz];
[date setDateTime: value];
}
else
{
[vToDo setCompleted: nil];
}
// status
value = [newProperties objectForKey: MAPIPropertyKey (PidLidTaskStatus)];
@ -365,6 +409,13 @@
priority = @"0"; // None
[vToDo setPriority: priority];
// percent complete
// NOTE: this does not seem to work on Outlook 2003. PidLidPercentComplete's value
// is always set to 0, no matter what value is set in Outlook
value = [newProperties objectForKey: MAPIPropertyKey(PidLidPercentComplete)];
if (value)
[vToDo setPercentComplete: [value stringValue]];
now = [NSCalendarDate date];
if ([sogoObject isNew])
{

View File

@ -36,11 +36,6 @@
@class iCalTimeZone;
@interface iCalRepeatableEntityObject : iCalEntityObject
// {
// NSMutableArray *rRules;
// NSMutableArray *exRules;
// NSMutableArray *exDates;
// }
- (void)removeAllRecurrenceRules;
- (void)addToRecurrenceRules:(id)_rrule;

View File

@ -160,7 +160,13 @@ static BOOL debugOn = YES;
if (!imap4)
{
sogoCache = [SOGoCache sharedCache];
cacheKey = [[self mailAccountFolder] nameInContainer];
// The cacheKey *MUST* be prefixed by the username here as
// the cache is shared across OpenChange users and not necessarily
// flushed between requests. This could lead us to using the wrong
// IMAP connection.
cacheKey = [NSString stringWithFormat: @"%@+%@",
[[[self context] activeUser] login],
[[self mailAccountFolder] nameInContainer]];
imap4 = [sogoCache imap4ConnectionForKey: cacheKey];
if (!imap4)
{

View File

@ -87,7 +87,9 @@
- (void) setContext: (WOContext *) newContext;
- (WOContext *) context;
- (void) setNameInContainer: (NSString *) theName;
- (NSString *) nameInContainer;
- (NSString *) displayName;
- (id) container;

View File

@ -209,6 +209,11 @@
return context;
}
- (void) setNameInContainer: (NSString *) theName
{
ASSIGN(nameInContainer, theName);
}
- (NSString *) nameInContainer
{
return nameInContainer;