Merge pull request #78 from Zentyal/contribute-back

Fixes for OpenChange integration from Zentyal
pull/80/head
extrafu 2015-04-20 11:43:04 -04:00
commit a94591a365
46 changed files with 2519 additions and 538 deletions

View File

@ -2675,7 +2675,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
parts in this url. We strip the '-' character in case we have
this in the domain part - like foo@bar-zot.com */
ocFSTableName = [NSMutableString stringWithFormat: @"sogo_cache_folder_%@",
[[user loginInDomain] asCSSIdentifier]];
[[user login] asCSSIdentifier]];
[ocFSTableName replaceOccurrencesOfString: @"-"
withString: @"_"
options: 0

View File

@ -0,0 +1,34 @@
/* Codepages.h - this file is part of SOGo
*
* Copyright (C) 2014 Jesús García Sáez
*
* 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/NSDictionary.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSString.h>
@interface Codepages
+ (NSDictionary *) getCodepagesTable;
+ (NSDictionary *) getReverseCodepagesTable;
+ (NSNumber *) getCodepageFromName: (NSString *) name;
+ (NSString *) getNameFromCodepage: (NSNumber *) codepage;
@end

View File

@ -0,0 +1,214 @@
/* Codepages.m - this file is part of SOGo
*
* Copyright (C) 2014 Jesús García Sáez
*
* 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 "Codepages.h"
#import <Foundation/NSArray.h>
@implementation Codepages
+ (NSDictionary *) getCodepagesTable
{
static NSDictionary *table = nil;
if (table == nil)
{
/* http://msdn.microsoft.com/en-us/library/dd317756%28v=vs.85%29.aspx */
table = [[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt: 37], @"ibm037",
[NSNumber numberWithInt: 437], @"ibm437",
[NSNumber numberWithInt: 500], @"ibm500",
[NSNumber numberWithInt: 708], @"asmo-708",
[NSNumber numberWithInt: 720], @"dos-720",
[NSNumber numberWithInt: 737], @"ibm737",
[NSNumber numberWithInt: 775], @"ibm775",
[NSNumber numberWithInt: 850], @"ibm850",
[NSNumber numberWithInt: 852], @"ibm852",
[NSNumber numberWithInt: 855], @"ibm855",
[NSNumber numberWithInt: 857], @"ibm857",
[NSNumber numberWithInt: 858], @"ibm00858",
[NSNumber numberWithInt: 860], @"ibm860",
[NSNumber numberWithInt: 861], @"ibm861",
[NSNumber numberWithInt: 862], @"dos-862",
[NSNumber numberWithInt: 863], @"ibm863",
[NSNumber numberWithInt: 864], @"ibm864",
[NSNumber numberWithInt: 865], @"ibm865",
[NSNumber numberWithInt: 866], @"cp866",
[NSNumber numberWithInt: 869], @"ibm869",
[NSNumber numberWithInt: 870], @"ibm870",
[NSNumber numberWithInt: 874], @"windows-874",
[NSNumber numberWithInt: 875], @"cp875",
[NSNumber numberWithInt: 932], @"shift_jis",
[NSNumber numberWithInt: 936], @"gb2312",
[NSNumber numberWithInt: 949], @"ks_c_5601-1987",
[NSNumber numberWithInt: 950], @"big5",
[NSNumber numberWithInt: 1026], @"ibm1026",
[NSNumber numberWithInt: 1047], @"ibm01047",
[NSNumber numberWithInt: 1140], @"ibm01140",
[NSNumber numberWithInt: 1141], @"ibm01141",
[NSNumber numberWithInt: 1142], @"ibm01142",
[NSNumber numberWithInt: 1143], @"ibm01143",
[NSNumber numberWithInt: 1144], @"ibm01144",
[NSNumber numberWithInt: 1145], @"ibm01145",
[NSNumber numberWithInt: 1146], @"ibm01146",
[NSNumber numberWithInt: 1147], @"ibm01147",
[NSNumber numberWithInt: 1148], @"ibm01148",
[NSNumber numberWithInt: 1149], @"ibm01149",
[NSNumber numberWithInt: 1200], @"utf-16",
[NSNumber numberWithInt: 1201], @"unicodefffe",
[NSNumber numberWithInt: 1250], @"windows-1250",
[NSNumber numberWithInt: 1251], @"windows-1251",
[NSNumber numberWithInt: 1252], @"windows-1252",
[NSNumber numberWithInt: 1253], @"windows-1253",
[NSNumber numberWithInt: 1254], @"windows-1254",
[NSNumber numberWithInt: 1255], @"windows-1255",
[NSNumber numberWithInt: 1256], @"windows-1256",
[NSNumber numberWithInt: 1257], @"windows-1257",
[NSNumber numberWithInt: 1258], @"windows-1258",
[NSNumber numberWithInt: 1361], @"johab",
[NSNumber numberWithInt: 10000], @"macintosh",
[NSNumber numberWithInt: 10001], @"x-mac-japanese",
[NSNumber numberWithInt: 10002], @"x-mac-chinesetrad",
[NSNumber numberWithInt: 10003], @"x-mac-korean",
[NSNumber numberWithInt: 10004], @"x-mac-arabic",
[NSNumber numberWithInt: 10005], @"x-mac-hebrew",
[NSNumber numberWithInt: 10006], @"x-mac-greek",
[NSNumber numberWithInt: 10007], @"x-mac-cyrillic",
[NSNumber numberWithInt: 10008], @"x-mac-chinesesimp",
[NSNumber numberWithInt: 10010], @"x-mac-romanian",
[NSNumber numberWithInt: 10017], @"x-mac-ukrainian",
[NSNumber numberWithInt: 10021], @"x-mac-thai",
[NSNumber numberWithInt: 10029], @"x-mac-ce",
[NSNumber numberWithInt: 10079], @"x-mac-icelandic",
[NSNumber numberWithInt: 10081], @"x-mac-turkish",
[NSNumber numberWithInt: 10082], @"x-mac-croatian",
[NSNumber numberWithInt: 12000], @"utf-32",
[NSNumber numberWithInt: 12001], @"utf-32be",
[NSNumber numberWithInt: 20000], @"x-chinese-cns",
[NSNumber numberWithInt: 20001], @"x-cp20001",
[NSNumber numberWithInt: 20002], @"x-chinese-eten",
[NSNumber numberWithInt: 20003], @"x-cp20003",
[NSNumber numberWithInt: 20004], @"x-cp20004",
[NSNumber numberWithInt: 20005], @"x-cp20005",
[NSNumber numberWithInt: 20105], @"x-ia5",
[NSNumber numberWithInt: 20106], @"x-ia5-german",
[NSNumber numberWithInt: 20107], @"x-ia5-swedish",
[NSNumber numberWithInt: 20108], @"x-ia5-norwegian",
[NSNumber numberWithInt: 20127], @"us-ascii",
[NSNumber numberWithInt: 20261], @"x-cp20261",
[NSNumber numberWithInt: 20269], @"x-cp20269",
[NSNumber numberWithInt: 20273], @"ibm273",
[NSNumber numberWithInt: 20277], @"ibm277",
[NSNumber numberWithInt: 20278], @"ibm278",
[NSNumber numberWithInt: 20280], @"ibm280",
[NSNumber numberWithInt: 20284], @"ibm284",
[NSNumber numberWithInt: 20285], @"ibm285",
[NSNumber numberWithInt: 20290], @"ibm290",
[NSNumber numberWithInt: 20297], @"ibm297",
[NSNumber numberWithInt: 20420], @"ibm420",
[NSNumber numberWithInt: 20423], @"ibm423",
[NSNumber numberWithInt: 20424], @"ibm424",
[NSNumber numberWithInt: 20833], @"x-ebcdic-koreanextended",
[NSNumber numberWithInt: 20838], @"ibm-thai",
[NSNumber numberWithInt: 20866], @"koi8-r",
[NSNumber numberWithInt: 20871], @"ibm871",
[NSNumber numberWithInt: 20880], @"ibm880",
[NSNumber numberWithInt: 20905], @"ibm905",
[NSNumber numberWithInt: 20924], @"ibm00924",
[NSNumber numberWithInt: 20932], @"euc-jp",
[NSNumber numberWithInt: 20936], @"x-cp20936",
[NSNumber numberWithInt: 20949], @"x-cp20949",
[NSNumber numberWithInt: 21025], @"cp1025",
[NSNumber numberWithInt: 21866], @"koi8-u",
[NSNumber numberWithInt: 28591], @"iso-8859-1",
[NSNumber numberWithInt: 28592], @"iso-8859-2",
[NSNumber numberWithInt: 28593], @"iso-8859-3",
[NSNumber numberWithInt: 28594], @"iso-8859-4",
[NSNumber numberWithInt: 28595], @"iso-8859-5",
[NSNumber numberWithInt: 28596], @"iso-8859-6",
[NSNumber numberWithInt: 28597], @"iso-8859-7",
[NSNumber numberWithInt: 28598], @"iso-8859-8",
[NSNumber numberWithInt: 28599], @"iso-8859-9",
[NSNumber numberWithInt: 28603], @"iso-8859-13",
[NSNumber numberWithInt: 28605], @"iso-8859-15",
[NSNumber numberWithInt: 29001], @"x-europa",
[NSNumber numberWithInt: 38598], @"iso-8859-8-i",
[NSNumber numberWithInt: 50220], @"iso-2022-jp",
[NSNumber numberWithInt: 50221], @"csiso2022jp",
[NSNumber numberWithInt: 50222], @"iso-2022-jp",
[NSNumber numberWithInt: 50225], @"iso-2022-kr",
[NSNumber numberWithInt: 50227], @"x-cp50227",
[NSNumber numberWithInt: 51932], @"euc-jp",
[NSNumber numberWithInt: 51936], @"euc-cn",
[NSNumber numberWithInt: 51949], @"euc-kr",
[NSNumber numberWithInt: 52936], @"hz-gb-2312",
[NSNumber numberWithInt: 54936], @"gb18030",
[NSNumber numberWithInt: 57002], @"x-iscii-de",
[NSNumber numberWithInt: 57003], @"x-iscii-be",
[NSNumber numberWithInt: 57004], @"x-iscii-ta",
[NSNumber numberWithInt: 57005], @"x-iscii-te",
[NSNumber numberWithInt: 57006], @"x-iscii-as",
[NSNumber numberWithInt: 57007], @"x-iscii-or",
[NSNumber numberWithInt: 57008], @"x-iscii-ka",
[NSNumber numberWithInt: 57009], @"x-iscii-ma",
[NSNumber numberWithInt: 57010], @"x-iscii-gu",
[NSNumber numberWithInt: 57011], @"x-iscii-pa",
[NSNumber numberWithInt: 65000], @"utf-7",
[NSNumber numberWithInt: 65001], @"utf-8",
nil] retain];
}
return table;
}
+ (NSDictionary *) getReverseCodepagesTable
{
static NSDictionary *table = nil;
if (table == nil)
{
NSDictionary *codepages_table;
NSEnumerator *enumerator;
NSMutableArray *codepages, *names;
id key;
// Build reverse table: (NSNumber) codepage -> (NSString) encoding name
codepages_table = [self getCodepagesTable];
codepages = [NSMutableArray arrayWithCapacity: [codepages_table count]];
names = [NSMutableArray arrayWithCapacity: [codepages_table count]];
enumerator = [codepages_table keyEnumerator];
while ((key = [enumerator nextObject]))
{
[names addObject: key];
[codepages addObject: [codepages_table objectForKey: key]];
}
table = [[NSDictionary dictionaryWithObjects: names forKeys: codepages] retain];
}
return table;
}
+ (NSNumber *) getCodepageFromName: (NSString *) name
{
return [[self getCodepagesTable] objectForKey: [name lowercaseString]];
}
+ (NSString *) getNameFromCodepage: (NSNumber *) codepage
{
return [[self getReverseCodepagesTable] objectForKey: codepage];
}
@end

View File

@ -31,7 +31,7 @@ endif
all::
@echo " Python executable: ${PYTHON}"
SAMBA_PRIVATE_DIR = $(shell $(PYTHON) ./samba-get-config.py "private dir")
SAMBA_PRIVATE_DIR = $(shell $(PYTHON) ./samba-get-config.py 'private dir' || echo /var/lib/samba/private)
$(SOGOBACKEND)_PRINCIPAL_CLASS = MAPIApplication
@ -110,6 +110,8 @@ $(SOGOBACKEND)_OBJC_FILES += \
\
MAPIStoreFallbackContext.m \
\
MAPIStoreSharingMessage.m \
\
NSArray+MAPIStore.m \
NSData+MAPIStore.m \
NSDate+MAPIStore.m \
@ -120,7 +122,9 @@ $(SOGOBACKEND)_OBJC_FILES += \
iCalEvent+MAPIStore.m \
iCalTimeZone+MAPIStore.m \
\
RTFHandler.m
RTFHandler.m \
\
Codepages.m
$(SOGOBACKEND)_RESOURCE_FILES += \

View File

@ -45,6 +45,7 @@
#import "MAPIStoreRecurrenceUtils.h"
#import "MAPIStoreSamDBUtils.h"
#import "MAPIStoreTypes.h"
#import "NSArray+MAPIStore.h"
#import "NSData+MAPIStore.h"
#import "NSDate+MAPIStore.h"
#import "NSObject+MAPIStore.h"
@ -791,11 +792,20 @@ static NSCharacterSet *hexCharacterSet = nil;
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc;
NSCalendarDate *dateValue;
NSCalendarDate *dateValue, *start;
if ([event isRecurrent])
{
dateValue = [[event startDate] hour: 0 minute: 0 second: 0];
/* [MS-OXOCAL] For a recurring series, this property specifies
midnight in the user's machine time zone, on the date of the
first instance, then is persisted in UTC. */
start = [event startDate];
dateValue = [NSCalendarDate dateWithYear: [start yearOfCommonEra]
month: [start monthOfYear]
day: [start dayOfMonth]
hour: 0 minute: 0 second: 0
timeZone: timeZone];
[dateValue setTimeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
@ -894,7 +904,7 @@ static NSCharacterSet *hexCharacterSet = nil;
}
else
dateValue = [NSCalendarDate dateWithYear: 4500 month: 8 day: 31
hour: 23 minute: 59 second: 59
hour: 23 minute: 59 second: 00
timeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
@ -1191,11 +1201,31 @@ static NSCharacterSet *hexCharacterSet = nil;
return [self getYes: data inMemCtx: memCtx];
}
- (int) getPidTagSensitivity: (void **) data // not implemented, depends on CLASS
- (int) getPidTagSensitivity: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
// normal = 0, personal?? = 1, private = 2, confidential = 3
return [self getLongZero: data inMemCtx: memCtx];
/* See [MS-OXCICAL] Section 2.1.3.11.20.4 */
uint32_t v;
NSString *accessClass;
accessClass = [event accessClass];
if (accessClass)
{
if ([accessClass isEqualToString: @"X-PERSONAL"])
v = 0x1;
else if ([accessClass isEqualToString: @"PRIVATE"])
v = 0x2;
else if ([accessClass isEqualToString: @"CONFIDENTIAL"])
v = 0x3;
else
v = 0x0; /* PUBLIC */
}
else
v = 0x0; /* PUBLIC */
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
}
- (int) getPidTagImportance: (void **) data
@ -1214,6 +1244,22 @@ static NSCharacterSet *hexCharacterSet = nil;
return MAPISTORE_SUCCESS;
}
- (int) getPidNameKeywords: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
/* See [MS-OXCICAL] Section 2.1.3.1.1.20.3 */
NSArray *categories;
categories = [event categories];
if (categories)
{
*data = [categories asMVUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
else
return MAPISTORE_ERR_NOT_FOUND;
}
- (int) getPidTagBody: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@ -1231,7 +1277,7 @@ static NSCharacterSet *hexCharacterSet = nil;
/* Avoiding those trail weird characters at event description */
range = [stringValue rangeOfString: trimingString
options: NSBackwardsSearch];
if (range.location > 0)
if (range.location != NSNotFound)
{
stringValue = [stringValue substringToIndex: (NSMaxRange(range) -1)];
}
@ -1826,16 +1872,25 @@ ReservedBlockEE2Size: 00 00 00 00
NSArray *alarms;
NSUInteger count, max;
iCalAlarm *currentAlarm;
NSString *action;
NSString *action, *webstatus;
alarms = [event alarms];
max = [alarms count];
for (count = 0; !alarm && count < max; count++)
{
currentAlarm = [alarms objectAtIndex: count];
action = [[currentAlarm action] lowercaseString];
if (!action || [action isEqualToString: @"display"])
ASSIGN (alarm, currentAlarm);
// Only handle 'display' alarms
action = [currentAlarm action];
if ([action caseInsensitiveCompare: @"display"] != NSOrderedSame)
continue;
// Ignore alarms already triggered
webstatus = [[currentAlarm trigger] value: 0 ofAttribute: @"x-webstatus"];
if ([webstatus caseInsensitiveCompare: @"triggered"] == NSOrderedSame)
continue;
ASSIGN (alarm, currentAlarm);
}
alarmSet = YES;

View File

@ -100,6 +100,14 @@
[roles addObject: SOGoCalendarRole_PrivateViewer];
[roles addObject: SOGoCalendarRole_ConfidentialViewer];
}
if (rights & RightsFreeBusySimple)
{
[roles addObject: SOGoCalendarRole_PublicDAndTViewer];
}
if (rights & RightsFreeBusyDetailed)
{
[roles addObject: SOGoCalendarRole_ConfidentialDAndTViewer];
}
// [self logWithFormat: @"roles for rights %.8x = (%@)", rights, roles];
@ -121,12 +129,21 @@
else if ([roles containsObject: SOGoCalendarRole_PublicViewer]
&& [roles containsObject: SOGoCalendarRole_PrivateViewer]
&& [roles containsObject: SOGoCalendarRole_ConfidentialViewer])
rights |= RightsReadItems | 0x1800;
// We have to set by hand other rights as only the highest role is returned
// See SOGoAppointmentFolder.m:aclsForUser for details
rights |= RightsReadItems | RightsFreeBusySimple | RightsFreeBusyDetailed;
if ([roles containsObject: SOGoCalendarRole_PublicDAndTViewer])
rights |= RightsFreeBusySimple;
if ([roles containsObject: SOGoCalendarRole_ConfidentialDAndTViewer])
rights |= RightsFreeBusyDetailed;
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
// [self logWithFormat: @"rights for roles (%@) = %.8x", roles, rights];
return rights;
}
@ -169,6 +186,14 @@
[(SOGoAppointmentFolder *) sogoObject aclSQLListingFilter]];
}
- (int) getPidTagContainerClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"IPF.Appointment" asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidTagDefaultPostMessageClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{

View File

@ -81,7 +81,7 @@
// extern void ndr_print_AppointmentRecurrencePattern(struct ndr_print *ndr, const char *name, const struct AppointmentRecurrencePattern *r);
static Class NSArrayK;
static Class NSArrayK, MAPIStoreAppointmentWrapperK;
@implementation SOGoAppointmentObject (MAPIStoreExtension)
@ -97,6 +97,7 @@ static Class NSArrayK;
+ (void) initialize
{
NSArrayK = [NSArray class];
MAPIStoreAppointmentWrapperK = [MAPIStoreAppointmentWrapper class];
}
+ (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP
@ -180,6 +181,12 @@ static Class NSArrayK;
else
{
origCalendar = [sogoObject calendar: YES secure: YES];
if (!origCalendar)
{
[self errorWithFormat: @"Incorrect calendar event %@. Empty message is created",
[self url]];
return self;
}
calendar = [origCalendar mutableCopy];
masterEvent = [[calendar events] objectAtIndex: 0];
[self _setupAttachmentParts];
@ -205,13 +212,23 @@ static Class NSArrayK;
[super dealloc];
}
/* getters */
- (int) getPidLidFInvited: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
- (MAPIStoreAppointmentWrapper *) _appointmentWrapper
{
return [self getYes: data inMemCtx: memCtx];
NSUInteger i, max;
id proxy;
max = [proxies count];
for (i = 0; i < max; i++) {
proxy = [proxies objectAtIndex: i];
if ([proxy isKindOfClass: MAPIStoreAppointmentWrapperK])
{
return proxy;
}
}
return nil;
}
/* getters */
- (int) getPidTagMessageClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@ -324,100 +341,63 @@ static Class NSArrayK;
}
else
{
/* HACK: we know the first (and only) proxy is our appointment wrapper
instance, but this might not always be true */
[[proxies objectAtIndex: 0] fillMessageData: msgData
inMemCtx: memCtx];
[[self _appointmentWrapper] fillMessageData: msgData
inMemCtx: memCtx];
}
*dataPtr = msgData;
}
/* sender representing */
// - (int) getPidTagSentRepresentingEmailAddress: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagSenderEmailAddress: data inMemCtx: memCtx];
// }
// - (int) getPidTagSentRepresentingAddressType: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getSMTPAddrType: data inMemCtx: memCtx];
// }
// - (int) getPidTagSentRepresentingName: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagSenderName: data inMemCtx: memCtx];
// }
// - (int) getPidTagSentRepresentingEntryId: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagSenderEntryId: data inMemCtx: memCtx];
// }
/* attendee */
// - (int) getPidTagReceivedByAddressType: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [appointmentWrapper getPidTagReceivedByAddressType: data
// inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedByEmailAddress: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [appointmentWrapper getPidTagReceivedByEmailAddress: data
// inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedByName: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [appointmentWrapper getPidTagReceivedByName: data
// inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedByEntryId: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [appointmentWrapper getPidTagReceivedByEntryId: data
// inMemCtx: memCtx];
// }
// /* attendee representing */
// - (int) getPidTagReceivedRepresentingEmailAddress: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagReceivedByEmailAddress: data inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedRepresentingAddressType: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getSMTPAddrType: data inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedRepresentingName: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagReceivedByName: data inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedRepresentingEntryId: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagReceivedByEntryId: data inMemCtx: memCtx];
// }
- (int) getPidTagResponseRequested: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getYes: data inMemCtx: memCtx];
}
/* This three methods: getPidTagNormalizedSubject,
getPidTagSensitivity and getPidTagImportance are implemented in
MAPIStoreMessage base class, then the proxy method is not reached
(see MAPIStoreObject).
*/
- (int) getPidTagNormalizedSubject: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
MAPIStoreAppointmentWrapper *appointmentWrapper;
appointmentWrapper = [self _appointmentWrapper];
if (appointmentWrapper)
return [appointmentWrapper getPidTagNormalizedSubject: data inMemCtx: memCtx];
return MAPISTORE_ERR_NOT_FOUND;
}
- (int) getPidTagSensitivity: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
MAPIStoreAppointmentWrapper *appointmentWrapper;
appointmentWrapper = [self _appointmentWrapper];
if (appointmentWrapper)
return [appointmentWrapper getPidTagSensitivity: data inMemCtx: memCtx];
return [self getLongZero: data inMemCtx: memCtx];
}
- (int) getPidTagImportance: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
MAPIStoreAppointmentWrapper *appointmentWrapper;
appointmentWrapper = [self _appointmentWrapper];
if (appointmentWrapper)
return [appointmentWrapper getPidTagImportance: data inMemCtx: memCtx];
*data = MAPILongValue (memCtx, 1);
return MAPISTORE_SUCCESS;
}
- (NSString *) _uidFromGlobalObjectId: (TALLOC_CTX *) memCtx
{
NSData *objectId;

View File

@ -170,6 +170,21 @@
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
{
@ -723,6 +738,107 @@
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
//
@ -1133,12 +1249,18 @@ fromProperties: (NSDictionary *) attachmentProps
//
// job title, nickname, company name, deparment, work url, im address/screen name and birthday
// 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];
@ -1173,6 +1295,52 @@ fromProperties: (NSDictionary *) attachmentProps
[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)
{

View File

@ -51,6 +51,7 @@
#import "MAPIStoreContext.h"
#undef DEBUG
#include <dlinklist.h>
#include <stdbool.h>
#include <gen_ndr/exchange.h>
#include <util/attr.h>
@ -276,6 +277,11 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
{
NSString *username;
if (newConnInfo == NULL)
{
return nil;
}
if ((self = [self init]))
{
ASSIGN (contextUrl, newUrl);
@ -367,8 +373,9 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
NSString *objectURL, *url;
// TDB_DATA key, dbuf;
url = [[contextUrl absoluteString]
stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
url = [contextUrl absoluteString];
// FIXME transform percent escapes but not for user part of the url
//stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
objectURL = [[userContext mapping] urlFromID: fmid];
if (objectURL)
{
@ -549,7 +556,7 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
{
uint64_t newVersionNumber;
if (openchangedb_get_new_changeNumber (connInfo->oc_ctx, &newVersionNumber)
if (openchangedb_get_new_changeNumber (connInfo->oc_ctx, connInfo->username, &newVersionNumber)
!= MAPI_E_SUCCESS)
abort ();
@ -566,9 +573,9 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
memCtx = talloc_zero(NULL, TALLOC_CTX);
newChangeNumbers = [NSMutableArray arrayWithCapacity: max];
if (openchangedb_get_new_changeNumbers (connInfo->oc_ctx,
memCtx, max, &numbers)
memCtx, connInfo->username, max, &numbers)
!= MAPI_E_SUCCESS || numbers->cValues != max)
abort ();
for (count = 0; count < max; count++)

View File

@ -138,7 +138,9 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
MAPIStoreMapping *mapping;
NSRange slashRange;
if (isMove && [targetFolder isKindOfClass: MAPIStoreDBFolderK])
pathComponent = nil;
if (isMove && ([targetFolder isKindOfClass: MAPIStoreDBFolderK] || !targetFolder))
{
path = [sogoObject path];
slashRange = [path rangeOfString: @"/" options: NSBackwardsSearch];
@ -147,14 +149,28 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
format: @"db folder path must start with a '/'"];
else
pathComponent = [path substringFromIndex: slashRange.location + 1];
targetPath = [[targetFolder sogoObject] path];
newPath = [NSString stringWithFormat: @"%@/%@",
targetPath, pathComponent];
[dbFolder changePathTo: newPath];
if (targetFolder)
{
targetPath = [[targetFolder sogoObject] path];
newPath = [NSString stringWithFormat: @"%@/%@",
targetPath, pathComponent];
[dbFolder changePathTo: newPath
intoNewContainer: [targetFolder dbFolder]];
}
else
[dbFolder changePathTo: [NSString stringWithFormat: @"/fallback/%@", pathComponent]
intoNewContainer: nil];
mapping = [self mapping];
newURL = [NSString stringWithFormat: @"%@%@/",
[targetFolder url], pathComponent];
if (targetFolder)
newURL = [NSString stringWithFormat: @"%@%@/",
[targetFolder url], pathComponent];
else
newURL = [NSString stringWithFormat: @"sogo://%@@fallback/%@/",
[[self userContext] username], pathComponent];
[mapping updateID: [self objectId]
withURL: newURL];

View File

@ -50,19 +50,22 @@
NSUInteger count;
enum MAPITAGS faiProperties[] = { 0x68350102, 0x683c0102, 0x683e0102,
0x683f0102, 0x68410003, 0x68420102,
0x68450102, 0x68460003 };
0x68450102, 0x68460003,
// PR_VD_NAME_W, PR_VD_FLAGS, PR_VD_VERSION, PR_VIEW_CLSID
0x7006001F, 0x70030003, 0x70070003, 0x68330048 };
size_t faiSize = sizeof(faiProperties) / sizeof(enum MAPITAGS);
properties = talloc_zero (memCtx, struct SPropTagArray);
properties->cValues = MAPIStoreSupportedPropertiesCount + 8;
properties->cValues = MAPIStoreSupportedPropertiesCount + faiSize;
properties->aulPropTag = talloc_array (properties, enum MAPITAGS,
MAPIStoreSupportedPropertiesCount + 8);
MAPIStoreSupportedPropertiesCount + faiSize);
for (count = 0; count < MAPIStoreSupportedPropertiesCount; count++)
properties->aulPropTag[count] = MAPIStoreSupportedProperties[count];
/* FIXME (hack): append a few undocumented properties that can be added to
FAI messages */
for (count = 0; count < 8; count++)
for (count = 0; count < faiSize; count++)
properties->aulPropTag[MAPIStoreSupportedPropertiesCount+count]
= faiProperties[count];

View File

@ -30,6 +30,7 @@
#undef DEBUG
#include <inttypes.h>
#include <dlinklist.h>
#include <mapistore/mapistore.h>
@implementation MAPIStoreFallbackContext
@ -55,7 +56,10 @@
NSString *baseURL, *url, *name;
MAPIStoreUserContext *userContext;
baseURL = [NSString stringWithFormat: @"sogo://%@@fallback/", userName];
baseURL = [NSString stringWithFormat: @"sogo://%@@fallback/",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"]];
context = talloc_zero (memCtx, struct mapistore_contexts_list);
context->url = [baseURL asUnicodeInMemCtx: context];
@ -99,7 +103,10 @@
forUser: (NSString *) userName
{
return [NSString stringWithFormat: @"sogo://%@@fallback/0x%.16"PRIx64"/",
userName, (unsigned long long) fid];
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
(unsigned long long) fid];
}
@end

View File

@ -150,6 +150,7 @@
/* helpers */
- (uint64_t) idForObjectWithKey: (NSString *) childKey;
- (MAPIStoreFolder *) rootContainer;
/* subclasses */
- (MAPIStoreMessage *) createMessage;

View File

@ -29,6 +29,7 @@
#import <Foundation/NSString.h>
#import <Foundation/NSURL.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <SOGo/SOGoContentObject.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoFolder.h>
@ -52,6 +53,7 @@
#import <SOGo/SOGoCacheGCSFolder.h>
#import "SOGoMAPIDBMessage.h"
#import "SOGoCacheGCSObject+MAPIStore.h"
#import <Mailer/SOGoMailObject.h>
#include <gen_ndr/exchange.h>
@ -100,6 +102,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSUInteger lastPartIdx;
MAPIStoreUserContext *userContext;
parts = 0;
lastPartIdx = 0;
folderURL = [NSURL URLWithString: [self url]];
/* note: -[NSURL path] returns an unescaped representation */
path = [folderURL path];
@ -231,9 +235,15 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
SOGoFolder *sogoFolder;
WOContext *woContext;
childFolder = nil;
if ([[self folderKeys] containsObject: folderKey])
{
woContext = [[self userContext] woContext];
/* We activate the user for the context using the root folder
context as there are times where the active user is not
matching with the one stored in the application context
and SOGo object is storing cached data with the wrong user */
[[self userContext] activateWithUser: [woContext activeUser]];
sogoFolder = [sogoObject lookupName: folderKey inContext: woContext
acquire: NO];
if (sogoFolder && ![sogoFolder isKindOfClass: NSExceptionK])
@ -278,6 +288,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
msgObject = [sogoObject lookupName: messageKey
inContext: nil
acquire: NO];
/* If the lookup in the indexing table works, but the IMAP does
not have the message, then the message does not exist in this
folder */
if (msgObject && [msgObject isKindOfClass: [SOGoMailObject class]]
&& ! [(SOGoMailObject *)msgObject doesMailExist])
return nil;
if (msgObject && ![msgObject isKindOfClass: NSExceptionK])
{
[msgObject setContext: [[self userContext] woContext]];
@ -433,16 +449,11 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
return rc;
}
- (void) deleteFolderImpl
- (int) deleteFolder
{
// TODO: raise exception in case underlying delete fails?
// [propsMessage delete];
[dbFolder delete];
}
- (int) deleteFolder
{
[self deleteFolderImpl];
[self cleanupCaches];
@ -503,6 +514,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
else
rc = MAPISTORE_ERR_DENIED;
}
else
{
/* Unregistering from indexing table as the backend says the
object was not found */
[mapping unregisterURLWithID: mid];
}
}
return rc;
@ -568,8 +585,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
struct mapistore_object_notification_parameters *notif_parameters;
int rc;
/* flags that control the behaviour of the operation
(MAPISTORE_SOFT_DELETE or MAPISTORE_PERMANENT_DELETE) */
[self logWithFormat: @"-deleteMessageWithMID: mid: 0x%.16llx flags: %d", mid, flags];
mapping = [self mapping];
childURL = [mapping urlFromID: mid];
if (childURL)
@ -646,7 +665,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
notifyChangesForChild: message];
}
[self logWithFormat: @"successfully deleted object at URL: %@", childURL];
[mapping unregisterURLWithID: mid];
/* Ensure we are respecting flags parameter */
[mapping unregisterURLWithID: mid andFlags: flags];
[self cleanupCaches];
rc = MAPISTORE_SUCCESS;
}
@ -676,6 +696,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
//TALLOC_CTX *memCtx;
struct SRow aRow;
struct SPropValue property;
uint8_t deleteFlags;
[self logWithFormat: @"-moveCopyMessageWithMID: 0x%.16llx .. withMID: 0x%.16llx .. wantCopy: %d", srcMid, targetMid, wantCopy];
@ -706,7 +727,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
}
[destMsg save: memCtx];
if (!wantCopy)
rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: 0];
/* We want to keep mid for restoring/shared data to work if mids are different. */
deleteFlags = (srcMid == targetMid) ? MAPISTORE_PERMANENT_DELETE : MAPISTORE_SOFT_DELETE;
rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: deleteFlags];
end:
//talloc_free (memCtx);
@ -845,7 +868,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (isMove)
{
fmid = [mapping idFromURL: [message url]];
[self deleteMessageWithMID: fmid andFlags: 0];
[self deleteMessageWithMID: fmid andFlags: MAPISTORE_PERMANENT_DELETE];
[mapping registerURL: [targetMessage url]
withID: fmid];
}
@ -866,7 +889,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (isMove)
{
fmid = [mapping idFromURL: [message url]];
[self deleteMessageWithMID: fmid andFlags: 0];
[self deleteMessageWithMID: fmid andFlags: MAPISTORE_PERMANENT_DELETE];
[mapping registerURL: [targetMessage url]
withID: fmid];
}
@ -893,16 +916,23 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
}
if (isMove)
{
fmid = [mapping idFromURL: [self url]];
[mapping unregisterURLWithID: fmid];
[self deleteFolderImpl];
[mapping registerURL: [newFolder url]
withID: fmid];
}
[self deleteFolder];
[targetFolder cleanupCaches];
}
[self cleanupCaches];
/* We perform the mapping operations at the
end as objectId is required to be available
until the caches are cleaned up */
if (isMove && rc == MAPISTORE_SUCCESS)
{
fmid = [mapping idFromURL: [self url]];
[mapping unregisterURLWithID: fmid];
[mapping registerURL: [newFolder url]
withID: fmid];
}
}
else
rc = MAPISTORE_ERR_DENIED;
@ -946,6 +976,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSString *baseURL, *URL, *key;
NSArray *newIDs;
uint64_t idNbr;
bool softDeleted;
baseURL = [self url];
@ -956,8 +987,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
{
key = [keys objectAtIndex: count];
URL = [NSString stringWithFormat: @"%@%@", baseURL, key];
idNbr = [mapping idFromURL: URL];
if (idNbr == NSNotFound)
idNbr = [mapping idFromURL: URL isSoftDeleted: &softDeleted];
if (idNbr == NSNotFound && !softDeleted)
[missingURLs addObject: URL];
}
@ -1088,6 +1119,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
MAPIStoreMapping *mapping;
struct UI8Array_r *fmids;
uint64_t fmid;
bool softDeleted;
keys = [self getDeletedKeysFromChangeNumber: changeNum andCN: &cnNbr
inTableType: tableType];
@ -1114,10 +1146,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
{
url = [NSString stringWithFormat: format,
baseURL, [keys objectAtIndex: count]];
fmid = [mapping idFromURL: url];
fmid = [mapping idFromURL: url isSoftDeleted: &softDeleted];
if (fmid != NSNotFound) /* if no fmid is returned, then the object
"never existed" in the OpenChange
databases */
databases. Soft-deleted messages are returned back */
{
fmids->lpui8[fmids->cValues] = fmid;
fmids->cValues++;
@ -1713,10 +1745,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
aclFolder = [self aclFolder];
users = [aclFolder aclUsers];
users = [[aclFolder aclUsers] copy];
max = [users count];
for (count = 0; count < max; count++)
[aclFolder removeUserFromAcls: [users objectAtIndex: count]];
[users release];
}
- (int) modifyPermissions: (struct PermissionData *) permissions
@ -1864,6 +1898,17 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
inFolderURL: [self url]];
}
- (MAPIStoreFolder *) rootContainer
{
/* Return the oldest ancestor, which does not have
container. If there is not container, it returns itself.
*/
if (container)
return [container rootContainer];
else
return self;
}
- (NSDate *) creationTime
{
return [dbFolder creationDate];

View File

@ -82,7 +82,9 @@
andTDBIndexing: indexing];
parentFolder = [[userContext rootFolders] objectForKey: moduleName];
baseUrl = [NSString stringWithFormat: @"sogo://%@@%@/",
userName, moduleName];
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
moduleName];
subfolders = [parentFolder subFolders];
max = [subfolders count];
@ -127,7 +129,9 @@
if (![parentFolder newFolderWithName: folderName
nameInContainer: &nameInContainer])
mapistoreURI = [NSString stringWithFormat: @"sogo://%@@%@/%@/",
userName, moduleName, nameInContainer];
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
moduleName, nameInContainer];
else
mapistoreURI = nil;
[MAPIApp setUserContext: nil];

View File

@ -163,8 +163,15 @@
- (int) getPidTagDisplayName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [[bodyInfo objectForKey: @"description"]
asUnicodeInMemCtx: memCtx];
NSString *fileName;
fileName = [self _fileName];
if ([fileName isEqualToString: @"sharing_metadata.xml"])
/* Required to disallow user from seeing the attachment by default */
*data = [@"sharing_metadata.xml" asUnicodeInMemCtx: memCtx];
else
*data = [[bodyInfo objectForKey: @"description"]
asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
@ -181,11 +188,17 @@
- (int) getPidTagAttachMimeTag: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *mimeTag;
NSString *mimeTag, *fileName;
fileName = [self _fileName];
if ([fileName isEqualToString: @"sharing_metadata.xml"])
/* Required by [MS-OXWSMSHR] Section 3.1.1 */
mimeTag = [NSString stringWithFormat: @"application/x-sharing-metadata-xml"];
else
mimeTag = [NSString stringWithFormat: @"%@/%@",
[bodyInfo objectForKey: @"type"],
[bodyInfo objectForKey: @"subtype"]];
mimeTag = [NSString stringWithFormat: @"%@/%@",
[bodyInfo objectForKey: @"type"],
[bodyInfo objectForKey: @"subtype"]];
*data = [[mimeTag lowercaseString] asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;

View File

@ -87,7 +87,7 @@ MakeDisplayFolderName (NSString *folderName)
inMemCtx: (TALLOC_CTX *) memCtx
{
struct mapistore_contexts_list *firstContext = NULL, *context;
NSString *urlBase, *stringData, *currentName, *inboxName, *draftsName, *sentName, *trashName;
NSString *urlBase, *stringData, *currentName, *realName, *inboxName, *draftsName, *sentName, *trashName;
NSArray *unprefixedFolders;
NSMutableArray *secondaryFolders;
enum mapistore_context_role role[] = {MAPISTORE_MAIL_ROLE,
@ -126,7 +126,11 @@ MakeDisplayFolderName (NSString *folderName)
trashName = [NSString stringWithFormat: @"folder%@",
[unprefixedFolders componentsJoinedByString: @"/folder"]];
urlBase = [NSString stringWithFormat: @"sogo://%@:%@@mail/", userName, userName];
urlBase = [NSString stringWithFormat: @"sogo://%@:%@@mail/",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"]];
for (count = 0; count < 3; count++)
{
context = talloc_zero (memCtx, struct mapistore_contexts_list);
@ -153,12 +157,23 @@ MakeDisplayFolderName (NSString *folderName)
for (count = 0; count < max; count++)
{
context = talloc_zero (memCtx, struct mapistore_contexts_list);
// secondaryFolders has the names (1) Imap4Encoded and (2) asCSSIdentifier
// e.g.: Probl&AOg-mes_SP_de_SP_synchronisation
currentName = [secondaryFolders objectAtIndex: count];
stringData = [NSString stringWithFormat: @"%@%@",
urlBase, [currentName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
context->url = [stringData asUnicodeInMemCtx: context];
stringData = [[[currentName substringFromIndex: 6] fromCSSIdentifier] stringByDecodingImap4FolderName];
context->name = [stringData asUnicodeInMemCtx: context];
// To get the real name we have to revert that (applying the decode functions)
// in reverse order
// e.g.: Problèmes de synchronisation
realName = [[currentName fromCSSIdentifier]
stringByDecodingImap4FolderName];
// And finally to represent that as URI we have to (1) asCSSIdentifier,
// (2) Imap4Encode and (3) AddPercentEscapes
// e.g.: Probl&AOg-mes_SP_de_SP_synchronisation
// In the example there are no percent escapes added because is already ok
stringData = [[[realName asCSSIdentifier]
stringByEncodingImap4FolderName]
stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
context->url = [[NSString stringWithFormat: @"%@%@", urlBase, stringData] asUnicodeInMemCtx: context];
context->name = [[realName substringFromIndex: 6] asUnicodeInMemCtx: context];
context->main_folder = false;
context->role = MAPISTORE_MAIL_ROLE;
context->tag = "tag";
@ -188,7 +203,10 @@ MakeDisplayFolderName (NSString *folderName)
inContainer: accountFolder];
if ([newFolder create])
mapistoreURI = [NSString stringWithFormat: @"sogo://%@:%@@mail/%@/",
userName, userName,
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
[[folderName stringByEncodingImap4FolderName] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
else
mapistoreURI = nil;
@ -264,8 +282,12 @@ MakeDisplayFolderName (NSString *folderName)
componentsSeparatedByString: @"/"];
folderName = [NSString stringWithFormat: @"folder%@",
[unprefixedFolders componentsJoinedByString: @"/folder"]];
url = [NSString stringWithFormat: @"sogo://%@:%@@outbox/%@", userName,
userName, folderName];
url = [NSString stringWithFormat: @"sogo://%@:%@@outbox/%@",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
folderName];
context = talloc_zero (memCtx, struct mapistore_contexts_list);
context->url = [url asUnicodeInMemCtx: context];

View File

@ -44,6 +44,9 @@
/* synchronisation & versioning */
- (BOOL) synchroniseCache;
- (void) synchronizeUpdatedFolder: (NSNumber *) lastModseq
withMapping: (NSMutableDictionary *) mapping;
- (BOOL) synchroniseCacheForUID: (NSString *) messageUID;
- (NSNumber *) modseqFromMessageChangeNumber: (NSString *) changeNum;
- (NSString *) messageUIDFromMessageKey: (NSString *) messageKey;
- (NSString *) changeNumberForMessageUID: (NSString *) messageUid;
@ -52,6 +55,11 @@
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey;
- (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey;
/* Extra properties from mail messages that already hit the server */
- (void) setExtraProperties: (NSDictionary *) props
forMessage: (NSString *) messageKey;
- (NSDictionary *) extraPropertiesForMessage: (NSString *) messageKey;
@end
/* MAPIStoreOutboxFolder is a special subclass of MAPIStoreMailFolder where

View File

@ -70,6 +70,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
#undef DEBUG
#include <util/attr.h>
#include <libmapi/libmapi.h>
#include <libmapiproxy.h>
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
@ -163,6 +164,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
int i;
nameInContainer = nil;
rc = MAPISTORE_ERROR;
folderName = nil;
for (i = 0; !folderName && i < aRow->cValues; i++)
@ -177,6 +179,12 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
{
nameInContainer = [NSString stringWithFormat: @"folder%@",
[[folderName stringByEncodingImap4FolderName] asCSSIdentifier]];
/* it may be the operation is interleaved with operations
from other users having cached information in the thread
with the other user, so it'd better activate the user again here... */
[[self userContext] activateWithUser: [[[self userContext] woContext] activeUser]];
newFolder = [SOGoMailFolderK objectWithName: nameInContainer
inContainer: sogoObject];
if ([newFolder create])
@ -511,7 +519,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
*nextModseq;
NSString *changeNumber, *uid, *messageKey;
uint64_t lastModseqNbr;
EOQualifier *kvQualifier, *searchQualifier;
EOQualifier *searchQualifier;
NSArray *uids, *changeNumbers;
NSUInteger count, max;
NSArray *fetchResults;
@ -552,14 +560,11 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
{
lastModseqNbr = [lastModseq unsignedLongLongValue];
nextModseq = [NSNumber numberWithUnsignedLongLong: lastModseqNbr + 1];
kvQualifier = [[EOKeyValueQualifier alloc]
searchQualifier = [[EOKeyValueQualifier alloc]
initWithKey: @"modseq"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: nextModseq];
searchQualifier = [[EOAndQualifier alloc]
initWithQualifiers:
kvQualifier, [self nonDeletedQualifier], nil];
[kvQualifier release];
[searchQualifier autorelease];
}
else
@ -587,7 +592,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
fetchResults
= [(NSDictionary *) [sogoObject fetchUIDs: uids
parts: [NSArray arrayWithObject: @"modseq"]]
parts: [NSArray arrayWithObjects: @"modseq", @"flags", nil]]
objectForKey: @"fetch"];
/* NOTE: we sort items manually because Cyrus does not properly sort
@ -623,58 +628,230 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
if (!lastModseq
|| ([lastModseq compare: modseq] == NSOrderedAscending))
lastModseq = modseq;
if ([[result objectForKey: @"flags"] containsObject: @"deleted"])
[currentProperties setObject: changeNumber
forKey: @"SyncLastDeleteChangeNumber"];
}
[currentProperties setObject: lastModseq forKey: @"SyncLastModseq"];
foundChange = YES;
}
/* 2. we synchronise deleted UIDs */
/* 2. we synchronise expunged UIDs */
if (initialLastModseq)
{
fetchResults = [(SOGoMailFolder *) sogoObject
fetchUIDsOfVanishedItems: lastModseqNbr];
max = [fetchResults count];
changeNumbers = [[self context] getNewChangeNumbers: max];
changeNumber = nil;
for (count = 0; count < max; count++)
{
uid = [fetchResults objectAtIndex: count];
uid = [[fetchResults objectAtIndex: count] stringValue];
if ([messages objectForKey: uid])
{
newChangeNum = [[changeNumbers objectAtIndex: count]
unsignedLongLongValue];
changeNumber = [NSString stringWithUnsignedLongLong: newChangeNum];
if (!changeNumber)
{
newChangeNum = [[self context] getNewChangeNumber];
changeNumber = [NSString stringWithUnsignedLongLong: newChangeNum];
}
[messages removeObjectForKey: uid];
[self logWithFormat: @"removed message entry for uid %@", uid];
[self logWithFormat: @"Removed message entry for UID %@", uid];
}
else
{
[self logWithFormat:@"Message entry not found for UID %@", uid];
}
}
if (changeNumber)
{
[currentProperties setObject: changeNumber
forKey: @"SyncLastDeleteChangeNumber"];
[mapping setObject: lastModseq forKey: changeNumber];
foundChange = YES;
}
}
if (foundChange)
{
[self synchronizeUpdatedFolder: lastModseq
withMapping: mapping];
ti = [NSNumber numberWithDouble: [now timeIntervalSince1970]];
[currentProperties setObject: ti
forKey: @"SyncLastSynchronisationDate"];
[versionsMessage save];
}
return rc;
}
- (void) synchronizeUpdatedFolder: (NSNumber *) lastModseq
withMapping: (NSMutableDictionary *) mapping
{
/* This method should be called whenever something has changed on the folder.
Then we will perform two actions:
1 - Update the PidTagChangeNumber property of the root container.
2 - Store relationship PidTagChangenumber with lastModseq value on the
mapping given as parameter for this folder */
uint64_t *current_cn;
struct SRow row;
struct SPropValue prop;
uint64_t fid;
const char *username;
struct openchangedb_context *oc_ctx;
enum MAPISTATUS retval;
TALLOC_CTX *local_mem_ctx = NULL;
row.cValues = 1;
prop.ulPropTag = PidTagChangeNumber;
prop.value.d = 0; // It doesn't matter, it will be autogenerated
row.lpProps = &prop;
/* We are doing a "touch" operation to update change number of the root container.
We get the root container as it has the properties in the OpenChange DB */
username = [[self context] connectionInfo]->username;
oc_ctx = [[self context] connectionInfo]->oc_ctx;
fid = [[self rootContainer] objectId];
retval = openchangedb_set_folder_properties(oc_ctx, username, fid, &row);
if (retval != MAPI_E_SUCCESS)
{
[self errorWithFormat:@"%s: Error setting change number on %"PRIu64,
__PRETTY_FUNCTION__, fid];
return;
}
local_mem_ctx = talloc_named(NULL, 0, __PRETTY_FUNCTION__);
if (local_mem_ctx == NULL)
{
[self errorWithFormat:@"%s: Error with talloc_named, out of memory?",
__PRETTY_FUNCTION__];
return;
}
retval = openchangedb_get_folder_property(local_mem_ctx, oc_ctx, username,
PidTagChangeNumber, fid,
(void **) &current_cn);
if (retval != MAPI_E_SUCCESS)
{
[self errorWithFormat:@"%s: Error getting change number on %"PRIu64,
__PRETTY_FUNCTION__, fid];
talloc_free(local_mem_ctx);
return;
}
[mapping setObject: lastModseq
forKey: [NSString stringWithUnsignedLongLong: *current_cn]];
talloc_free(local_mem_ctx);
}
- (BOOL) synchroniseCacheForUID: (NSString *) messageUID
{
/* Try to synchronise old UIDs in versions.plist cache using an
specific UID. It returns a boolean indicating if the
synchronisation were done.
It should be used as last resort, keeping synchroniseCache to main
sync entry point.
*/
NSMutableDictionary *currentProperties, *messages, *messageEntry, *mapping;
NSArray *fetchResults;
uint64_t changeNumber;
NSDictionary *result;
NSNumber *modseq;
NSString *changeNumberStr;
NSData *changeKey;
[versionsMessage reloadIfNeeded];
currentProperties = [versionsMessage properties];
messages = [currentProperties objectForKey: @"Messages"];
messageEntry = [messages objectForKey: messageUID];
if (!messageEntry)
{
fetchResults = [(NSDictionary *) [sogoObject fetchUIDs: [NSArray arrayWithObject: messageUID]
parts: [NSArray arrayWithObjects: @"modseq", @"flags", nil]]
objectForKey: @"fetch"];
if ([fetchResults count] == 1)
{
result = [fetchResults objectAtIndex: 0];
modseq = [result objectForKey: @"modseq"];
changeNumber = [[self context] getNewChangeNumber];
changeNumberStr = [NSString stringWithUnsignedLongLong: changeNumber];
/* Create new message entry in Messages dict */
messageEntry = [NSMutableDictionary new];
[messages setObject: messageEntry forKey: messageUID];
[messageEntry release];
/* Store the modseq and change number */
[messageEntry setObject: modseq forKey: @"modseq"];
[messageEntry setObject: changeNumberStr forKey: @"version"];
/* Store the change key */
changeKey = [self getReplicaKeyFromGlobCnt: changeNumber >> 16];
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
/* Store the changeNumber -> modseq mapping */
mapping = [currentProperties objectForKey: @"VersionMapping"];
[mapping setObject: modseq forKey: changeNumberStr];
/* Store the last deleted change number if it is soft-deleted */
if ([[result objectForKey: @"flags"] containsObject: @"deleted"])
[currentProperties setObject: changeNumberStr
forKey: @"SyncLastDeleteChangeNumber"];
/* Save the message */
[versionsMessage save];
return YES;
}
else
{
return NO;
}
}
/* If message entry exists, then synchroniseCache did its job */
return YES;
}
- (NSNumber *) modseqFromMessageChangeNumber: (NSString *) changeNum
{
NSDictionary *mapping;
NSNumber *modseq;
NSEnumerator *enumerator;
id key;
uint64_t found, target, current, replica_id, current_cn;
NSString *closestChangeNum;
mapping = [[versionsMessage properties] objectForKey: @"VersionMapping"];
modseq = [mapping objectForKey: changeNum];
if (modseq) return modseq;
// Not found from stored change numbers for this folder.
// Get the closest modseq for the change number given.
// O(n) cost but will be unusual behaviour.
target = exchange_globcnt([changeNum unsignedLongLongValue] >> 16);
replica_id = [changeNum unsignedLongLongValue] & 0xFFFF;
found = 0;
enumerator = [mapping keyEnumerator];
while ((key = [enumerator nextObject]))
{
current_cn = [(NSString *)key unsignedLongLongValue];
if ((current_cn & 0xFFFF) != replica_id)
continue;
current = exchange_globcnt(current_cn >> 16);
if (current < target && current > found)
found = current;
}
if (found)
{
closestChangeNum = [NSString stringWithUnsignedLongLong:
(exchange_globcnt(found) << 16 | replica_id)];
modseq = [mapping objectForKey: closestChangeNum];
}
return modseq;
}
@ -688,7 +865,11 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
if (dotRange.location != NSNotFound)
messageUid = [messageKey substringToIndex: dotRange.location];
else
messageUid = nil;
{
messageUid = nil;
[self errorWithFormat:@"%s: Unexpected messageKey value [%@]",
__PRETTY_FUNCTION__, messageKey];
}
return messageUid;
}
@ -710,12 +891,24 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
{
NSMutableDictionary *messages, *messageEntry;
NSString *messageUid;
BOOL synced;
messageUid = [self messageUIDFromMessageKey: messageKey];
messages = [[versionsMessage properties] objectForKey: @"Messages"];
messageEntry = [messages objectForKey: messageUid];
if (!messageEntry)
abort ();
{
[self warnWithFormat: @"attempting to synchronise to set the change key for "
@"this message %@", messageKey];
synced = [self synchroniseCacheForUID: messageUid];
if (synced)
messageEntry = [[[versionsMessage properties] objectForKey: @"Messages"] objectForKey: messageUid];
if (!messageEntry)
{
[self errorWithFormat: @"still nothing. We crash!"];
abort ();
}
}
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
[versionsMessage save];
@ -784,6 +977,37 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
return list;
}
/* Management for extra properties once they already hit the IMAP server */
- (void) setExtraProperties: (NSDictionary *) props
forMessage: (NSString *) messageKey
{
NSMutableDictionary *extraProps, *currentProperties;
NSString *messageUid;
messageUid = [self messageUIDFromMessageKey: messageKey];
currentProperties = [versionsMessage properties];
extraProps = [currentProperties objectForKey: @"ExtraMessagesProperties"];
if (!extraProps)
{
extraProps = [NSMutableDictionary new];
[currentProperties setObject: extraProps forKey: @"ExtraMessagesProperties"];
[extraProps release];
}
[extraProps setObject: props
forKey: messageUid];
[versionsMessage save];
}
- (NSDictionary *) extraPropertiesForMessage: (NSString *) messageKey
{
NSString *messageUid;
messageUid = [self messageUIDFromMessageKey: messageKey];
return [[[versionsMessage properties] objectForKey: @"ExtraMessagesProperties"]
objectForKey: messageUid];
}
- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum
andCN: (NSNumber **) cnNbr
inTableType: (uint8_t) tableType
@ -792,6 +1016,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
NSString *changeNumber;
uint64_t modseq;
NSDictionary *versionProperties;
EOQualifier *deletedQualifier, *kvQualifier, *searchQualifier;
if (tableType == MAPISTORE_MESSAGE_TABLE)
{
@ -800,8 +1025,33 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
unsignedLongLongValue];
if (modseq > 0)
{
/* Hard deleted items */
deletedUIDs = [(SOGoMailFolder *) sogoObject
fetchUIDsOfVanishedItems: modseq];
/* Soft deleted items */
kvQualifier = [[EOKeyValueQualifier alloc]
initWithKey: @"modseq"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: [NSNumber numberWithUnsignedLongLong: modseq]];
deletedQualifier
= [[EOKeyValueQualifier alloc]
initWithKey: @"FLAGS"
operatorSelector: EOQualifierOperatorContains
value: [NSArray arrayWithObject: @"Deleted"]];
searchQualifier = [[EOAndQualifier alloc]
initWithQualifiers:
kvQualifier, deletedQualifier, nil];
deletedUIDs = [deletedUIDs arrayByAddingObjectsFromArray:
[sogoObject fetchUIDsMatchingQualifier: searchQualifier
sortOrdering: nil]];
[deletedQualifier release];
[kvQualifier release];
[searchQualifier release];
deletedKeys = [deletedUIDs stringsWithFormat: @"%@.eml"];
if ([deletedUIDs count] > 0)
{
@ -857,6 +1107,8 @@ _parseIMAPRange (const unichar *uniString, NSArray **UIDsP)
uint32_t currentUid, rangeMin;
BOOL done = NO, inRange = NO;
rangeMin = 0;
currentUid = 0;
UIDs = [NSMutableArray array];
while (!done)
{
@ -981,13 +1233,20 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
if (![[result objectForKey: @"result"] boolValue])
return MAPISTORE_ERROR;
/* "Move" treatment: Store \Deleted and unregister urls */
/* "Move" treatment: Store \Deleted and unregister urls as soft-deleted */
if (!wantCopy)
{
[client storeFlags: [NSArray arrayWithObject: @"Deleted"] forUIDs: uids
addOrRemove: YES];
for (count = 0; count < midCount; count++)
[mapping unregisterURLWithID: srcMids[count]];
{
/* Using soft-deleted to make deleted fmids to return the
srcMids.
See [MAPIStoreFolder getDeletedFMIDs:andCN:fromChangeNumber:inTableType:inMemCtx]
for details */
[mapping unregisterURLWithID: srcMids[count]
andFlags: MAPISTORE_SOFT_DELETE];
}
}
/* Registration of target messages */
@ -1061,6 +1320,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
struct SRow folderRow;
struct SPropValue nameProperty;
MAPIStoreMailFolder *newFolder;
SOGoMailAccount *accountFolder;
SOGoMailFolder *targetSOGoFolder;
NSMutableArray *uids;
NSArray *childKeys;
@ -1068,12 +1328,12 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
NGImap4Connection *connection;
NGImap4Client *client;
NSString *newURL, *parentDBFolderPath, *childKey, *folderIMAPName,
*urlNamePart, *newFolderIMAPName;
*urlNamePart, *newFolderIMAPName, *newFolderDBName;
NSException *error;
MAPIStoreMapping *mapping;
NSDictionary *result;
if ([targetFolder isKindOfClass: MAPIStoreMailFolderK])
if ([targetFolder isKindOfClass: MAPIStoreMailFolderK] || (!targetFolder && isMove))
{
folderURL = [sogoObject imap4URL];
if (!newFolderName)
@ -1081,9 +1341,23 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
targetSOGoFolder = [targetFolder sogoObject];
if (isMove)
{
urlNamePart = [newFolderName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
newFolderURL = [NSURL URLWithString: urlNamePart
relativeToURL: [targetSOGoFolder imap4URL]];
newFolderDBName = [[newFolderName stringByEncodingImap4FolderName] asCSSIdentifier];
if (targetSOGoFolder)
{
/* Mimetise [SOGoMailFolderK imap4URLString] */
urlNamePart = [[newFolderName stringByEncodingImap4FolderName] stringByEscapingURL];
newFolderURL = [NSURL URLWithString: urlNamePart
relativeToURL: [targetSOGoFolder imap4URL]];
}
else
{
/* Mimetise what createRootSecondaryFolderWithFID does */
accountFolder = [[[self userContext] rootFolders] objectForKey: @"mail"];
targetSOGoFolder = [SOGoMailFolder objectWithName: [NSString stringWithFormat: @"folder%@",
newFolderDBName]
inContainer: accountFolder];
newFolderURL = [targetSOGoFolder imap4URL];
}
error = [[sogoObject imap4Connection]
moveMailboxAtURL: folderURL
toURL: newFolderURL];
@ -1093,16 +1367,29 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
{
rc = MAPISTORE_SUCCESS;
mapping = [self mapping];
newURL = [NSString stringWithFormat: @"%@folder%@/",
[targetFolder url], urlNamePart];
if (targetFolder)
newURL = [NSString stringWithFormat: @"%@folder%@/",
[targetFolder url], newFolderDBName];
else
newURL = [NSString stringWithFormat: @"sogo://%@:%@@mail/folder%@/",
[[self userContext] username], [[self userContext] username],
newFolderDBName];
[mapping updateID: [self objectId] withURL: newURL];
parentDBFolderPath = [[targetFolder dbFolder] path];
if (!parentDBFolderPath)
parentDBFolderPath = @"";
[dbFolder changePathTo: [NSString stringWithFormat:
@"%@/folder%@",
parentDBFolderPath,
newFolderName]];
if (targetFolder)
{
parentDBFolderPath = [[targetFolder dbFolder] path];
if (!parentDBFolderPath)
parentDBFolderPath = @"";
[dbFolder changePathTo: [NSString stringWithFormat:
@"%@/folder%@",
parentDBFolderPath,
newFolderDBName]
intoNewContainer: [targetFolder dbFolder]];
}
else
[dbFolder changePathTo: [NSString stringWithFormat:
@"/mail/folder%@", newFolderDBName]
intoNewContainer: nil];
}
}
else
@ -1290,6 +1577,15 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
{
[bodyPartKeys addObject: bodyPartKey];
messageUid = [self messageUIDFromMessageKey: messageKey];
/* If the bodyPartKey include peek, remove it as it is not returned
as key in the IMAP server response.
IMAP conversation example:
a4 UID FETCH 1 (UID BODY.PEEK[text])
* 1 FETCH (UID 1 BODY[TEXT] {1677}
*/
bodyPartKey = [bodyPartKey stringByReplacingOccurrencesOfString: @"body.peek"
withString: @"body"];
[keyAssoc setObject: bodyPartKey forKey: messageUid];
}
}

View File

@ -35,6 +35,7 @@
{
BOOL headerSetup;
BOOL mailIsEvent;
BOOL mailIsSharingObject;
NSString *mimeKey;
NSString *headerCharset;
NSString *headerEncoding;

View File

@ -32,6 +32,7 @@
#import <NGImap4/NGImap4EnvelopeAddress.h>
#import <NGMail/NGMailAddress.h>
#import <NGMail/NGMailAddressParser.h>
#import <NGMail/NGMimeMessageGenerator.h>
#import <NGCards/iCalCalendar.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSString+Utilities.h>
@ -40,6 +41,7 @@
#import <Mailer/SOGoMailBodyPart.h>
#import <Mailer/SOGoMailObject.h>
#import "Codepages.h"
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
@ -50,6 +52,7 @@
#import "MAPIStoreMailFolder.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreSamDBUtils.h"
#import "MAPIStoreSharingMessage.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
@ -63,7 +66,7 @@
@class iCalCalendar, iCalEvent;
static Class NSExceptionK;
static Class NSExceptionK, MAPIStoreSharingMessageK;
@interface NSString (MAPIStoreMIME)
@ -106,6 +109,7 @@ static Class NSExceptionK;
+ (void) initialize
{
NSExceptionK = [NSException class];
MAPIStoreSharingMessageK = [MAPIStoreSharingMessage class];
}
- (id) init
@ -114,6 +118,7 @@ static Class NSExceptionK;
{
mimeKey = nil;
mailIsEvent = NO;
mailIsSharingObject = NO;
headerCharset = nil;
headerEncoding = nil;
headerMimeType = nil;
@ -132,6 +137,7 @@ static Class NSExceptionK;
[bodyContent release];
[headerMimeType release];
[headerCharset release];
[headerEncoding release];
[appointmentWrapper release];
[super dealloc];
}
@ -151,6 +157,30 @@ static Class NSExceptionK;
return [sogoObject date];
}
- (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP
inMemCtx: (TALLOC_CTX *) memCtx
{
BOOL listedProperties[65536];
NSUInteger count;
uint16_t propId;
if (mailIsSharingObject)
{
memset (listedProperties, NO, 65536 * sizeof (BOOL));
[super getAvailableProperties: propertiesP inMemCtx: memCtx];
for (count = 0; count < (*propertiesP)->cValues; count++)
{
propId = ((*propertiesP)->aulPropTag[count] >> 16) & 0xffff;
listedProperties[propId] = YES;
}
[MAPIStoreSharingMessage fillAvailableProperties: *propertiesP
withExclusions: listedProperties];
return MAPISTORE_SUCCESS;
}
else
return [super getAvailableProperties: propertiesP inMemCtx: memCtx];
}
static NSComparisonResult
_compareBodyKeysByPriority (id entry1, id entry2, void *data)
{
@ -200,9 +230,11 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
- (void) _fetchHeaderData
{
MAPIStoreSharingMessage *sharingMessage;
NSMutableArray *keys;
NSArray *acceptedTypes;
NSDictionary *messageData, *partHeaderData, *parameters;
NSString *sharingHeader;
acceptedTypes = [NSArray arrayWithObjects: @"text/calendar",
@"application/ics",
@ -227,6 +259,22 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if ([headerMimeType isEqualToString: @"text/calendar"]
|| [headerMimeType isEqualToString: @"application/ics"])
mailIsEvent = YES;
else
{
sharingHeader = [[sogoObject mailHeaders] objectForKey: @"x-ms-sharing-localtype"];
if (sharingHeader)
{
mailIsSharingObject = YES;
/* It is difficult to subclass this in folder class, that's why
a sharing object is a proxy in a mail message */
sharingMessage = [[MAPIStoreSharingMessage alloc]
initWithMailHeaders: [sogoObject mailHeaders]
andConnectionInfo: [[self context] connectionInfo]
fromMessage: self];
[self addProxy: sharingMessage];
[sharingMessage release];
}
}
}
headerSetup = YES;
@ -368,6 +416,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
{
uint64_t version = ULLONG_MAX;
NSString *uid, *changeNumber;
BOOL synced;
uid = [(MAPIStoreMailFolder *)
container messageUIDFromMessageKey: [self nameInContainer]];
@ -386,8 +435,19 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
[self logWithFormat: @"got one"];
else
{
[self errorWithFormat: @"still nothing. We crash!"];
abort();
[self warnWithFormat: @"attempting to get change number"
@" by synchronising this specific message..."];
synced = [(MAPIStoreMailFolder *) container synchroniseCacheForUID: uid];
if (synced)
{
changeNumber = [(MAPIStoreMailFolder *) container
changeNumberForMessageUID: uid];
}
else
{
[self errorWithFormat: @"still nothing. We crash!"];
abort();
}
}
}
version = [changeNumber unsignedLongLongValue] >> 16;
@ -504,6 +564,8 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if (mailIsEvent)
[[self _appointmentWrapper] getPidTagMessageClass: data
inMemCtx: memCtx];
else if (mailIsSharingObject)
*data = talloc_strdup (memCtx, "IPM.Sharing");
else
*data = talloc_strdup (memCtx, "IPM.Note");
@ -923,15 +985,17 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
- (int) getPidTagInternetCodepage: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
/* ref:
http://msdn.microsoft.com/en-us/library/dd317756%28v=vs.85%29.aspx
minimal list that should be handled:
us-ascii: 20127
iso-8859-1: 28591
iso-8859-15: 28605
utf-8: 65001 */
*data = MAPILongValue(memCtx, 65001);
NSNumber *codepage;
codepage = [Codepages getCodepageFromName: headerCharset];
if (!codepage)
{
[self warnWithFormat: @"Couldn't find codepage from `%@`. "
@"Using UTF-8 by default", headerCharset];
codepage = [Codepages getCodepageFromName: @"utf-8"];
}
*data = MAPILongValue(memCtx, [codepage intValue]);
return MAPISTORE_SUCCESS;
}
@ -1333,6 +1397,41 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
: MAPISTORE_ERR_NOT_FOUND);
}
- (int) getPidTagTransportMessageHeaders: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSDictionary *mailHeaders;
NSEnumerator *keyEnumerator;
NSMutableArray *headers;
NGMimeMessageGenerator *g;
NSString *headerKey, *fullHeader, *headerGenerated;
id headerValue;
NSData *headerData;
/* Let's encode each mail header and put them on 'headers' array */
mailHeaders = [sogoObject mailHeaders];
headers = [NSMutableArray arrayWithCapacity: [mailHeaders count]];
g = [[NGMimeMessageGenerator alloc] init];
keyEnumerator = [mailHeaders keyEnumerator];
while ((headerKey = [keyEnumerator nextObject]))
{
headerValue = [mailHeaders objectForKey: headerKey];
headerData = [g generateDataForHeaderField: headerKey value: headerValue];
headerGenerated = [[NSString alloc] initWithData: headerData encoding:NSUTF8StringEncoding];
fullHeader = [NSString stringWithFormat:@"%@: %@", headerKey, headerGenerated];
[headerGenerated release];
[headers addObject: fullHeader];
}
[g release];
*data = [[headers componentsJoinedByString:@"\n"] asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (void) getMessageData: (struct mapistore_message **) dataPtr
inMemCtx: (TALLOC_CTX *) memCtx
{
@ -1566,11 +1665,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if (!headerSetup)
[self _fetchHeaderData];
if ([mimeKey hasPrefix: @"body.peek"])
bodyPartKey = [NSString stringWithFormat: @"body[%@]",
[mimeKey _strippedBodyKey]];
else
bodyPartKey = mimeKey;
bodyPartKey = mimeKey;
return bodyPartKey;
}
@ -1584,6 +1679,21 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
bodySetup = YES;
}
- (MAPIStoreSharingMessage *) _sharingObject
{
/* Get the sharing object if available */
NSUInteger i, max;
id proxy;
max = [proxies count];
for (i = 0; i < max; i++) {
proxy = [proxies objectAtIndex: i];
if ([proxy isKindOfClass: MAPIStoreSharingMessageK])
return proxy;
}
return nil;
}
- (void) save: (TALLOC_CTX *) memCtx
{
NSNumber *value;
@ -1597,6 +1707,11 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
else /* 0: unflagged, 1: follow up complete */
[sogoObject removeFlags: @"\\Flagged"];
}
if (mailIsSharingObject)
[[self _sharingObject] saveWithMessage: self
andSOGoObject: sogoObject];
}
@end

View File

@ -28,9 +28,10 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSScanner.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <Foundation/NSValue.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NGHashMap.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+Encoding.h>
@ -43,6 +44,7 @@
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSCalendarDate+SOGo.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoCacheObject.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoMailer.h>
#import <SOGo/SOGoUser.h>
@ -50,6 +52,7 @@
#import <Mailer/SOGoMailFolder.h>
#import <Mailer/NSString+Mail.h>
#import "Codepages.h"
#import "MAPIStoreAttachment.h"
#import "MAPIStoreAttachmentTable.h"
#import "MAPIStoreContext.h"
@ -62,13 +65,13 @@
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import <SOGo/SOGoCacheObject.h>
#import "MAPIStoreMailVolatileMessage.h"
#undef DEBUG
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
#include <mapistore/mapistore_nameid.h>
static Class NSNumberK = Nil;
@ -531,13 +534,112 @@ QuoteSpecials (NSString *address)
return result;
}
static inline void
FillMessageHeadersFromSharingProperties (NGMutableHashMap *headers, NSDictionary *mailProperties)
{
/* Store the *important* properties related with a sharing object as
MIME eXtension headers. See [MS-OXSHARE] Section 2.2 for details
about the properties */
id value;
NSNumber *sharingFlavourNum = nil;
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingCapabilities)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-Capabilities"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingFlavor)];
if (value)
sharingFlavourNum = (NSNumber *)value;
else
{
value = [mailProperties objectForKey: MAPIPropertyKey (PidNameXSharingFlavor)];
if (value)
{
/* Transform the hex string to unsigned int */
NSScanner *scanner;
unsigned int sharingFlavour;
scanner = [NSScanner scannerWithString:value];
if ([scanner scanHexInt:&sharingFlavour])
sharingFlavourNum =[NSNumber numberWithUnsignedInt: sharingFlavour];
}
}
if (sharingFlavourNum)
{
if ([sharingFlavourNum unsignedIntegerValue] == 0x5100)
{
/* 0x5100 sharing flavour is not in standard but it seems to
be a denial of request + invitation message so we store
deny sharing flavour */
sharingFlavourNum = [NSNumber numberWithUnsignedInt: SHARING_DENY_REQUEST];
}
[headers setObject: sharingFlavourNum
forKey: @"X-MS-Sharing-Flavor"];
}
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorEntryId)];
if (value)
[headers setObject: [[value stringByEncodingBase64] stringByReplacingOccurrencesOfString: @"\n"
withString: @""]
forKey: @"X-MS-Sharing-InitiatorEntryId"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorName)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-InitiatorName"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorSmtp)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-InitiatorSmtp"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingLocalType)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-LocalType"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingProviderName)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-ProviderName"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingRemoteName)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-RemoteName"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingRemoteStoreUid)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-RemoteStoreUid"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingRemoteUid)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-RemoteUid"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingResponseTime)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-ResponseTime"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingResponseType)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-ResponseType"];
}
static inline void
FillMessageHeadersFromProperties (NGMutableHashMap *headers,
NSDictionary *mailProperties, BOOL withBcc,
struct mapistore_connection_info *connInfo)
{
BOOL fromResolved = NO;
NSData *senderEntryId;
NSMutableString *subject;
NSString *from, *recId, *messageId, *subjectData;
NSString *from, *recId, *messageId, *subjectData, *recipientsStr, *msgClass;
NSArray *list;
NSCalendarDate *date;
NSDictionary *recipients;
@ -571,10 +673,96 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
list = MakeRecipientsList ([recipients objectForKey: @"orig"]);
if ([list count])
[headers setObjects: list forKey: @"from"];
{
[headers setObjects: list forKey: @"from"];
fromResolved = YES;
}
}
if (!fromResolved)
{
NSLog (@"Message without an orig from, try to guess it from PidTagSenderEntryId");
senderEntryId = [mailProperties objectForKey: MAPIPropertyKey (PR_SENDER_ENTRYID)];
if (senderEntryId)
{
struct Binary_r bin32;
struct AddressBookEntryId *addrBookEntryId;
NSString *username;
NSMutableDictionary *fromRecipient;
fromRecipient = [NSMutableDictionary dictionaryWithCapacity: 2];
bin32.cb = [senderEntryId length];
bin32.lpb = (uint8_t *) [senderEntryId bytes];
addrBookEntryId = get_AddressBookEntryId (connInfo->sam_ctx, &bin32);
if (addrBookEntryId && [[NSString stringWithGUID: &addrBookEntryId->ProviderUID]
hasSuffix: @"08002b2fe182"])
{
/* TODO: better way to distinguish local and other ones */
username = MAPIStoreSamDBUserAttribute (connInfo->sam_ctx, @"legacyExchangeDN",
[NSString stringWithUTF8String: addrBookEntryId->X500DN], @"sAMAccountName");
if (username)
{
SOGoUser *fromUser;
fromUser = [SOGoUser userWithLogin: [username lowercaseString]];
[fromRecipient setObject: [fromUser cn] forKey: @"fullName"];
[fromRecipient setObject: [[fromUser allEmails] objectAtIndex: 0]
forKey: @"email"];
}
else
[fromRecipient setObject: [NSString stringWithUTF8String: addrBookEntryId->X500DN]
forKey: @"email"];
}
else
{
/* Try with One-Off EntryId */
struct OneOffEntryId *oneOffEntryId;
oneOffEntryId = get_OneOffEntryId (connInfo->sam_ctx, &bin32);
if (oneOffEntryId && [[NSString stringWithGUID: &oneOffEntryId->ProviderUID]
hasSuffix: @"00dd010f5402"])
{
[fromRecipient setObject: [NSString stringWithUTF8String: oneOffEntryId->DisplayName.lpszW]
forKey: @"fullName"];
[fromRecipient setObject: [NSString stringWithUTF8String: oneOffEntryId->EmailAddress.lpszW]
forKey: @"email"];
}
talloc_free (oneOffEntryId);
}
talloc_free (addrBookEntryId);
if ([[fromRecipient allKeys] count] > 0)
{
list = MakeRecipientsList ([NSArray arrayWithObjects: fromRecipient, nil]);
if ([list count])
[headers setObjects: list forKey: @"from"];
}
}
}
if (!recipients)
{
NSLog (@"Message without recipients."
@"Guessing recipients from PidTagOriginalDisplayTo and PidTagOriginalCc");
recipientsStr = [mailProperties objectForKey: MAPIPropertyKey (PidTagOriginalDisplayTo)];
if (recipientsStr)
{
list = [recipientsStr componentsSeparatedByString:@", "];
if ([list count])
[headers setObjects: list forKey: @"to"];
}
recipientsStr = [mailProperties objectForKey: MAPIPropertyKey (PidTagOriginalDisplayCc)];
if (recipientsStr)
{
list = [recipientsStr componentsSeparatedByString:@", "];
if ([list count])
[headers setObjects: list forKey: @"cc"];
}
}
else
NSLog (@"message without recipients");
subject = [NSMutableString stringWithCapacity: 128];
subjectData = [mailProperties objectForKey: MAPIPropertyKey (PR_SUBJECT_PREFIX_UNICODE)];
@ -592,8 +780,6 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
date = [mailProperties objectForKey: MAPIPropertyKey (PR_CLIENT_SUBMIT_TIME)];
if (date)
{
date = [date addYear: 0 month: 0 day: 0
hour: 0 minute: 0 second: [[date timeZone] secondsFromGMT]];
[headers addObject: [date rfc822DateString] forKey: @"date"];
}
[headers addObject: @"1.0" forKey: @"MIME-Version"];
@ -612,6 +798,13 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
{
[headers addObject: @"5 (Lowest)" forKey: @"X-Priority"];
}
msgClass = [mailProperties objectForKey: MAPIPropertyKey (PidTagMessageClass)];
if ([msgClass isEqualToString: @"IPM.Sharing"])
{
FillMessageHeadersFromSharingProperties (headers, mailProperties);
}
}
static NSArray *
@ -672,21 +865,9 @@ MakeTextHtmlBody (NSDictionary *mailProperties, NSDictionary *attachmentParts,
{
/* charset */
codePage = [mailProperties objectForKey: MAPIPropertyKey (PR_INTERNET_CPID)];
switch ([codePage intValue])
{
case 20127:
charset = @"us-ascii";
break;
case 28605:
charset = @"iso-8859-15";
break;
case 65001:
charset = @"utf-8";
break;
case 28591:
default:
charset = @"iso-8859-1";
}
charset = [Codepages getNameFromCodepage: codePage];
if (!charset)
charset = @"utf-8";
htmlContentType = [NSString stringWithFormat: @"text/html; charset=%@",
charset];
@ -834,7 +1015,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
messageBody = MakeMessageBody (properties, attachmentParts, &contentType);
if (messageBody)
{
[headers setObject: contentType forKey: @"content-type"];
[message setHeader: contentType forKey: @"content-type"];
[message setBody: messageBody];
}
@ -873,12 +1054,12 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
id <SOGoAuthenticator> authenticator;
msgClass = [properties objectForKey: MAPIPropertyKey (PidTagMessageClass)];
if ([msgClass isEqualToString: @"IPM.Note"]) /* we skip invitation replies */
if ([msgClass isEqualToString: @"IPM.Note"] || [msgClass isEqualToString: @"IPM.Sharing"]) /* we skip invitation replies */
{
/* send mail */
messageData = [self _generateMailDataWithBcc: NO];
recipientEmails = [NSMutableArray arrayWithCapacity: 32];
recipients = [properties objectForKey: @"recipients"];
for (type = MAPI_ORIG; type <= MAPI_BCC; type++)

View File

@ -49,11 +49,15 @@
- (NSString *) urlFromID: (uint64_t) idKey;
- (uint64_t) idFromURL: (NSString *) url;
- (uint64_t) idFromURL: (NSString *) url
isSoftDeleted: (bool *) softDeleted;
- (BOOL) registerURL: (NSString *) urlString
withID: (uint64_t) idNbr;
- (void) registerURLs: (NSArray *) urlString
withIDs: (NSArray *) idNbrs;
- (void) unregisterURLWithID: (uint64_t) idNbr;
- (void) unregisterURLWithID: (uint64_t) idNbr
andFlags: (uint8_t) flags;
- (void) updateID: (uint64_t) idNbr
withURL: (NSString *) urlString;

View File

@ -114,6 +114,9 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
{
ASSIGN (username, newUsername);
indexing = newIndexing;
/* Workaround so all indexing context are valid and won't be freed. */
// TODO refactor indexing interface
talloc_reference(memCtx, indexing);
}
return self;
@ -157,6 +160,21 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
return NSNotFound;
}
- (uint64_t) idFromURL: (NSString *) url
isSoftDeleted: (bool *) softDeleted
{
enum mapistore_error ret;
uint64_t idNbr;
ret = indexing->get_fmid(indexing, [username UTF8String], [url UTF8String],
false, &idNbr, softDeleted);
if (ret != MAPISTORE_SUCCESS)
return NSNotFound;
return idNbr;
}
- (void) _updateFolderWithURL: (NSString *) oldURL
withURL: (NSString *) urlString
{
@ -214,7 +232,7 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
{
NSString *oldURL;
uint64_t oldIdNbr;
bool rc;
bool rc, softDeleted;
oldURL = [self urlFromID: idNbr];
if (oldURL != NULL)
@ -225,13 +243,16 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
return NO;
}
oldIdNbr = [self idFromURL: urlString];
oldIdNbr = [self idFromURL: urlString isSoftDeleted: &softDeleted];
if (oldIdNbr != NSNotFound)
{
[self errorWithFormat:
@"attempt to double register an entry with idNbr ('%@', %lld,"
@" 0x%.16"PRIx64", oldid=0x%.16"PRIx64")",
urlString, idNbr, idNbr, oldIdNbr];
if (softDeleted)
[self logWithFormat: @"Attempt to register a soft-deleted %@", urlString];
else
[self errorWithFormat:
@"attempt to double register an entry with idNbr ('%@', %lld,"
@" 0x%.16"PRIx64", oldid=0x%.16"PRIx64")",
urlString, idNbr, idNbr, oldIdNbr];
return NO;
}
else
@ -275,4 +296,13 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
idNbr, MAPISTORE_PERMANENT_DELETE);
}
- (void) unregisterURLWithID: (uint64_t) idNbr
andFlags: (uint8_t) flags
{
indexing->del_fmid(indexing, [username UTF8String],
idNbr,
(flags == MAPISTORE_SOFT_DELETE) ? MAPISTORE_SOFT_DELETE : MAPISTORE_PERMANENT_DELETE);
}
@end

View File

@ -474,7 +474,9 @@ rtf2html (NSData *compressedRTF)
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];
@ -782,7 +784,7 @@ rtf2html (NSData *compressedRTF)
return [self getLongZero: data inMemCtx: memCtx];
}
- (int) getPidTagSensitivity: (void **) data // TODO -> subclass in calendar
- (int) getPidTagSensitivity: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getLongZero: data inMemCtx: memCtx];
@ -795,7 +797,7 @@ rtf2html (NSData *compressedRTF)
TALLOC_CTX *localMemCtx;
char *prefix, *normalizedSubject;
localMemCtx = talloc_zero (NULL, TALLOC_CTX);
localMemCtx = talloc_zero (memCtx, TALLOC_CTX);
if ([self getProperty: (void **) &prefix
withTag: PidTagSubjectPrefix
inMemCtx: localMemCtx]
@ -807,6 +809,8 @@ rtf2html (NSData *compressedRTF)
if (rc == MAPISTORE_SUCCESS)
*data = talloc_asprintf (memCtx, "%s%s", prefix, normalizedSubject);
talloc_free(localMemCtx);
return rc;
}

View File

@ -45,7 +45,8 @@
context = talloc_zero(memCtx, struct mapistore_contexts_list);
context->url = talloc_asprintf (context, "sogo://%s@notes/",
[userName UTF8String]);
[[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"] UTF8String]);
// context->name = "Notes personnelles";
context->main_folder = true;
context->role = MAPISTORE_NOTES_ROLE;

View File

@ -23,7 +23,6 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSObject+Logs.h>
#import <SOGo/SOGoObject.h>
#import <SOGo/SOGoUser.h>
@ -245,17 +244,16 @@ static Class NSExceptionK, MAPIStoreFolderK;
struct SPropValue *cValue;
NSUInteger counter;
NSMutableDictionary *newProperties;
NSTimeZone *tz;
NSInteger tzOffset;
id value;
tz = nil;
newProperties = [NSMutableDictionary dictionaryWithCapacity: aRow->cValues];
for (counter = 0; counter < aRow->cValues; counter++)
{
cValue = aRow->lpProps + counter;
value = NSObjectFromSPropValue (cValue);
if (value == nil)
continue;
switch (cValue->ulPropTag & 0xffff)
{
case PT_STRING8:
@ -264,16 +262,6 @@ static Class NSExceptionK, MAPIStoreFolderK;
@"attempting to set string property as PR_STRING8: %.8x",
cValue->ulPropTag];
break;
case PT_SYSTIME:
if (!tz)
{
tz = [[self userContext] timeZone];
tzOffset = -[tz secondsFromGMT];
}
value = [value addYear: 0 month: 0 day: 0
hour: 0 minute: 0 second: tzOffset];
[value setTimeZone: tz];
break;
}
[newProperties setObject: value
forKey: MAPIPropertyKey (cValue->ulPropTag)];

View File

@ -25,6 +25,8 @@
#include <talloc.h>
#import <Foundation/NSTimeZone.h>
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalRecurrenceRule.h>
@ -41,7 +43,10 @@
@interface iCalCalendar (MAPIStoreRecurrence)
- (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity
fromRecurrencePattern: (struct RecurrencePattern *) rp;
fromRecurrencePattern: (struct RecurrencePattern *) rp
withExceptions: (struct ExceptionInfo *) exInfos
andExceptionCount: (uint16_t) exInfoCount
inTimeZone: (NSTimeZone *) tz;
@end

View File

@ -24,6 +24,7 @@
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSSet.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NSObject+Logs.h>
@ -48,6 +49,10 @@
- (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity
fromRecurrencePattern: (struct RecurrencePattern *) rp
withExceptions: (struct ExceptionInfo *) exInfos
andExceptionCount: (uint16_t) exInfoCount
inTimeZone: (NSTimeZone *) tz
{
NSCalendarDate *startDate, *olEndDate, *untilDate, *exDate;
NSString *monthDay, *month;
@ -214,34 +219,42 @@
/* exception dates:
- take all deleted instances
- remove all modified instances from the above set
- remove all modified instances available in ExceptionInfo from the above set
- add remaining instances, in chronological order
*/
exceptionDates = [NSMutableSet set];
for (count = 0; count < rp->DeletedInstanceCount; count++)
{
exDate
= [NSDate dateFromMinutesSince1601: rp->DeletedInstanceDates[count]];
exDate = [exDate hour: [startDate hourOfDay]
minute: [startDate minuteOfHour]
second: [startDate secondOfMinute]];
[exceptionDates addObject: exDate];
}
for (count = 0; count < rp->ModifiedInstanceCount; count++)
{
exDate
= [NSDate dateFromMinutesSince1601: rp->ModifiedInstanceDates[count]];
exDate = [exDate hour: [startDate hourOfDay]
minute: [startDate minuteOfHour]
second: [startDate secondOfMinute]];
[exceptionDates removeObject: exDate];
}
realExDates = [[exceptionDates allObjects]
sortedArrayUsingSelector: @selector (compare:)];
max = [realExDates count];
for (count = 0; count < max; count++)
[entity addToExceptionDates: [realExDates objectAtIndex: count]];
/* Heuristic to avoid these loops */
if (rp->DeletedInstanceCount != rp->ModifiedInstanceCount) {
exceptionDates = [NSMutableSet set];
for (count = 0; count < rp->DeletedInstanceCount; count++)
{
exDate
= [NSDate dateFromMinutesSince1601: rp->DeletedInstanceDates[count]];
exDate = [exDate hour: [startDate hourOfDay]
minute: [startDate minuteOfHour]
second: [startDate secondOfMinute]];
[exceptionDates addObject: exDate];
}
/* Read the exceptions to remove the instances that are modified and not deleted */
if (exInfos && exInfoCount > 0)
{
for (count = 0; count < exInfoCount; count++)
{
/* The OriginalStartDate is in local time */
exDate = [NSDate dateFromMinutesSince1601: exInfos[count].OriginalStartDate];
exDate = [exDate dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: - [tz secondsFromGMT]];
[exceptionDates removeObject: exDate];
}
}
realExDates = [[exceptionDates allObjects]
sortedArrayUsingSelector: @selector (compare:)];
max = [realExDates count];
for (count = 0; count < max; count++)
[entity addToExceptionDates: [realExDates objectAtIndex: count]];
}
}
@end
@ -312,15 +325,25 @@
rp->RecurFrequency = RecurFrequency_Weekly;
rp->PatternType = PatternType_Week;
rp->Period = repeatInterval;
dayOfWeek = [startDate dayOfWeek];
mask = 0;
byDayMask = [self byDayMask];
for (count = 0; count < 7; count++)
if ([byDayMask occursOnDay: count])
mask |= 1 << count;
if (byDayMask)
{
for (count = 0; count < 7; count++)
if ([byDayMask occursOnDay: count])
mask |= 1 << count;
}
else
{
/* Set the recurrence pattern using start date */
mask |= 1 << dayOfWeek;
}
rp->PatternTypeSpecific.WeekRecurrencePattern = mask;
/* FirstDateTime */
dayOfWeek = [startDate dayOfWeek];
if (dayOfWeek)
beginOfWeek = [startDate dateByAddingYears: 0 months: 0
days: -dayOfWeek

View File

@ -47,6 +47,7 @@
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
#include <libmapi/libmapi.h>
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
#include <execinfo.h>
@ -58,8 +59,8 @@ static BOOL initialization_done = NO;
#define NS_CURRENT_THREAD_REGISTER() \
BOOL __nsrct_thread_registered = GSRegisterCurrentThread(); \
if (!initialization_done) { \
DEBUG(5, ("[SOGo: %s:%d] You should call sogo_backend_init() first. Current thread: %p, pid: %d\n", \
__FUNCTION__, __LINE__, GSCurrentThread(), getpid())); \
OC_DEBUG(5, "[SOGo] You should call sogo_backend_init() first. Current thread: %p, pid: %d\n", \
GSCurrentThread(), getpid()); \
}
#define NS_CURRENT_THREAD_TRY_UNREGISTER() \
if (__nsrct_thread_registered) { \
@ -144,7 +145,7 @@ sogo_backend_init (void)
GSRegisterCurrentThread();
if (initialization_done) {
DEBUG(0, ("SOGo backend already initialized.\n"));
OC_DEBUG(5, "[SOGo] SOGo backend already initialized.\n");
return MAPISTORE_SUCCESS;
}
@ -189,7 +190,7 @@ sogo_backend_init (void)
[pool release];
DEBUG(0, ("[SOGo: %s:%d] backend init SUCCESS. Current thread: %p, pid: %d\n", __FUNCTION__, __LINE__, GSCurrentThread(), getpid()));
OC_DEBUG(5, "[SOGo] backend init SUCCESS. Current thread: %p, pid: %d\n", GSCurrentThread(), getpid());
initialization_done = YES;
return MAPISTORE_SUCCESS;
@ -213,7 +214,7 @@ sogo_backend_create_context(TALLOC_CTX *mem_ctx,
MAPIStoreContext *context;
int rc;
DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
NS_CURRENT_THREAD_REGISTER();
pool = [NSAutoreleasePool new];
@ -250,7 +251,7 @@ sogo_backend_create_root_folder (const char *username,
NSString *mapistoreUri;
int rc;
DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
NS_CURRENT_THREAD_REGISTER();
pool = [NSAutoreleasePool new];
@ -287,7 +288,7 @@ sogo_backend_list_contexts(const char *username, struct indexing_context *indexi
NSString *userName;
int rc;
DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
NS_CURRENT_THREAD_REGISTER();
pool = [NSAutoreleasePool new];
@ -335,7 +336,7 @@ sogo_context_get_path(void *backend_object, TALLOC_CTX *mem_ctx,
MAPIStoreContext *context;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (backend_object)
{
@ -369,7 +370,7 @@ sogo_context_get_root_folder(void *backend_object, TALLOC_CTX *mem_ctx,
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (backend_object)
{
@ -412,7 +413,7 @@ sogo_folder_open_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid,
MAPIStoreFolder *folder, *childFolder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -456,7 +457,7 @@ sogo_folder_create_folder(void *folder_object, TALLOC_CTX *mem_ctx,
MAPIStoreFolder *folder, *childFolder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -499,7 +500,7 @@ sogo_folder_delete(void *folder_object)
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -531,7 +532,7 @@ sogo_folder_get_child_count(void *folder_object, enum mapistore_table_type table
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -567,7 +568,7 @@ sogo_folder_open_message(void *folder_object,
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -609,7 +610,7 @@ sogo_folder_create_message(void *folder_object,
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -645,7 +646,7 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags)
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -683,7 +684,7 @@ sogo_folder_move_copy_messages(void *folder_object,
struct MAPIStoreTallocWrapper *wrapper;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -727,7 +728,7 @@ sogo_folder_move_folder(void *folder_object, void *target_folder_object,
struct MAPIStoreTallocWrapper *wrapper;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -777,7 +778,7 @@ sogo_folder_copy_folder(void *folder_object, void *target_folder_object, TALLOC_
struct MAPIStoreTallocWrapper *wrapper;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -821,7 +822,7 @@ sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx,
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -860,7 +861,7 @@ sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx,
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -899,7 +900,7 @@ sogo_folder_modify_permissions(void *folder_object, uint8_t flags,
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -933,7 +934,7 @@ sogo_folder_preload_message_bodies(void *folder_object, enum mapistore_table_typ
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@ -968,7 +969,7 @@ sogo_message_get_message_data(void *message_object,
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@ -1003,7 +1004,7 @@ sogo_message_create_attachment (void *message_object, TALLOC_CTX *mem_ctx, void
MAPIStoreAttachment *attachment;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@ -1040,7 +1041,7 @@ sogo_message_open_attachment (void *message_object, TALLOC_CTX *mem_ctx,
MAPIStoreAttachment *attachment;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@ -1076,7 +1077,7 @@ sogo_message_get_attachment_table (void *message_object, TALLOC_CTX *mem_ctx, vo
MAPIStoreAttachmentTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@ -1115,7 +1116,8 @@ sogo_message_modify_recipients (void *message_object,
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@ -1150,7 +1152,8 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@ -1183,7 +1186,8 @@ sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx)
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@ -1216,7 +1220,8 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags)
MAPIStoreMailVolatileMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@ -1254,7 +1259,8 @@ sogo_message_attachment_open_embedded_message (void *attachment_object,
MAPIStoreEmbeddedMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (attachment_object)
{
@ -1295,7 +1301,8 @@ sogo_message_attachment_create_embedded_message (void *attachment_object,
MAPIStoreEmbeddedMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (attachment_object)
{
@ -1331,7 +1338,8 @@ static enum mapistore_error sogo_table_get_available_properties(void *table_obje
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@ -1363,7 +1371,8 @@ sogo_table_set_columns (void *table_object, uint16_t count, enum MAPITAGS *prope
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@ -1396,7 +1405,8 @@ sogo_table_set_restrictions (void *table_object, struct mapi_SRestriction *restr
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@ -1431,7 +1441,8 @@ sogo_table_set_sort_order (void *table_object, struct SSortOrderSet *sort_order,
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@ -1468,7 +1479,8 @@ sogo_table_get_row (void *table_object, TALLOC_CTX *mem_ctx,
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@ -1503,7 +1515,8 @@ sogo_table_get_row_count (void *table_object,
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@ -1536,7 +1549,8 @@ sogo_table_handle_destructor (void *table_object, uint32_t handle_id)
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@ -1570,7 +1584,8 @@ static enum mapistore_error sogo_properties_get_available_properties(void *objec
MAPIStoreObject *propObject;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (object)
{
@ -1605,7 +1620,8 @@ sogo_properties_get_properties (void *object,
MAPIStoreObject *propObject;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (object)
{
@ -1639,7 +1655,8 @@ sogo_properties_set_properties (void *object, struct SRow *aRow)
MAPIStoreObject *propObject;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (object)
{
@ -1674,7 +1691,7 @@ sogo_manager_generate_uri (TALLOC_CTX *mem_ctx,
NSAutoreleasePool *pool;
NSString *partialURLString, *username, *directory;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (uri == NULL) return MAPISTORE_ERR_INVALID_PARAMETER;
@ -1693,7 +1710,10 @@ sogo_manager_generate_uri (TALLOC_CTX *mem_ctx,
username = [NSString stringWithUTF8String: (user ? user : "*")];
/* Do proper directory lookup here */
directory = [NSString stringWithUTF8String: (folder ? folder : "*")];
partialURLString = [NSString stringWithFormat: @"sogo://%@:*@%@", username, directory];
partialURLString = [NSString stringWithFormat: @"sogo://%@:*@%@",
[username stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
directory];
}
if (![partialURLString hasSuffix: @"/"])
partialURLString = [partialURLString stringByAppendingString: @"/"];
@ -1776,7 +1796,7 @@ int mapistore_init_backend(void)
/* Register ourselves with the MAPISTORE subsystem */
ret = mapistore_backend_register (&backend);
if (ret != MAPISTORE_SUCCESS)
DEBUG(0, ("Failed to register the '%s' mapistore backend!\n", backend.backend.name));
OC_DEBUG(0, "[SOGo] Failed to register the '%s' mapistore backend!\n", backend.backend.name);
}
return ret;

View File

@ -0,0 +1,101 @@
/* MAPIStoreSharingMessage.h - this file is part of SOGo-OpenChange
*
* Copyright (C) 2015 Enrique J. Hernández
*
* Author: Enrique J. Hernández <ejhernandez@zentyal.com>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef MAPISTORESHARINGMESSAGE_H
#define MAPISTORESHARINGMESSAGE_H
#import "MAPIStoreMailMessage.h"
#import "MAPIStoreObjectProxy.h"
#define SHARING_SPECIAL_FOLDER 0x40290
@interface MAPIStoreSharingMessage : MAPIStoreObjectProxy
{
struct mapistore_connection_info *connInfo;
NSMutableDictionary *properties;
}
- (id) initWithMailHeaders: (NSDictionary *) mailHeaders
andConnectionInfo: (struct mapistore_connection_info *) newConnInfo
fromMessage: (MAPIStoreMailMessage *) msg;
/* getters */
- (int) getPidLidSharingCapabilities: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingCapabilities: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingConfigurationUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingConfigUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingFlavor: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingFlavor: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingInitiatorEntryId: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingInitiatorName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingInitiatorSmtp: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingLocalType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingLocalType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingProviderGuid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingProviderGuid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingProviderName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingProviderName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingProviderUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingProviderUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingRemoteName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingRemoteName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingRemoteStoreUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingRemoteStoreUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingRemoteType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidTypeXSharingRemoteType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingResponseTime: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingResponseType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameContentClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
/* Save */
- (void) saveWithMessage: (MAPIStoreMailMessage *) msg
andSOGoObject: (SOGoMailObject *) sogoObject;
@end
#endif /* MAPISTORECALENDARWRAPPER_H */

View File

@ -0,0 +1,463 @@
/* MAPIStoreSharingMessage.m - this file is part of SOGo-OpenChange
*
* Copyright (C) 2015 Enrique J. Hernández
*
* Author: Enrique J. Hernández <ejhernandez@zentyal.com>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <talloc.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Mailer/SOGoMailObject.h>
#import <NGExtensions/NGBase64Coding.h>
#import "NSData+MAPIStore.h"
#import "NSDate+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import "NSValue+MAPIStore.h"
#import "MAPIStoreMailFolder.h"
#import "MAPIStoreSharingMessage.h"
#import "MAPIStoreTypes.h"
#include <gen_ndr/property.h>
#include <mapistore/mapistore_errors.h>
#include <mapistore/mapistore_nameid.h>
@implementation MAPIStoreSharingMessage
- (id) init
{
if ((self = [super init]))
{
connInfo = NULL;
properties = nil;
}
return self;
}
- (id) initWithMailHeaders: (NSDictionary *) mailHeaders
andConnectionInfo: (struct mapistore_connection_info *) newConnInfo
fromMessage: (MAPIStoreMailMessage *) msg
{
NSEnumerator *enumerator;
NSString *key;
if ((self = [self init]))
{
connInfo = newConnInfo;
enumerator = [mailHeaders keyEnumerator];
properties = [NSMutableDictionary new];
while ((key = [enumerator nextObject]))
{
if ([key hasPrefix: @"x-ms-sharing-"])
[properties setObject: [mailHeaders objectForKey: key]
forKey: key];
}
/* Set request properties from container folder */
NSDictionary *requestProps = [(MAPIStoreMailFolder *)[msg container]
extraPropertiesForMessage: [msg nameInContainer]];
if (requestProps)
[properties addEntriesFromDictionary: requestProps];
}
return self;
}
- (void) dealloc
{
[properties release];
[super dealloc];
}
- (enum mapistore_error) _getStringProperty: (NSString *) propertyName
inData: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: propertyName];
if (value)
{
*data = [value asUnicodeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidLidSharingCapabilities: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: @"x-ms-sharing-capabilities"];
if (value)
{
*data = MAPILongValue (memCtx, [value intValue]);
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidNameXSharingCapabilities: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: @"x-ms-sharing-capabilities"];
if (value)
{
*data = [[NSString stringWithFormat:@"%X", [value intValue]]
asUnicodeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidLidSharingConfigurationUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"" asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidNameXSharingConfigUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingConfigurationUrl: data inMemCtx: memCtx];
}
- (int) getPidLidSharingFlavor: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
/* See [MS-OXSHARE] Section 2.2.2.5 for details */
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value, auxValue;
value = [properties objectForKey: @"x-ms-sharing-flavor"];
if (value)
{
*data = MAPILongValue (memCtx, [value intValue]);
rc = MAPISTORE_SUCCESS;
}
else
{
/* Guess its value required by old clients based on other properties */
value = [properties objectForKey: @"x-ms-sharing-capabilities"];
if (value)
{
if ([value intValue] == SHARING_SPECIAL_FOLDER)
{
value = [properties objectForKey: @"x-ms-sharing-responsetime"];
auxValue = [properties objectForKey: @"x-ms-sharing-remoteuid"];
if (value) /* A sharing request */
{
if (auxValue)
*data = MAPILongValue (memCtx, SHARING_INVITATION_REQUEST_FOLDER);
else
*data = MAPILongValue (memCtx, SHARING_REQUEST_SPECIAL_FOLDER);
}
else
{
if (auxValue) /* It SHOULD be an invitation or response */
*data = MAPILongValue (memCtx, SHARING_INVITATION_SPECIAL_FOLDER);
else /* No remote info, then denial */
*data = MAPILongValue (memCtx, SHARING_DENY_REQUEST);
}
}
else
{
*data = MAPILongValue (memCtx, SHARING_INVITATION_FOLDER);
}
rc = MAPISTORE_SUCCESS;
}
}
return rc;
}
- (int) getPidNameXSharingFlavor: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: @"x-ms-sharing-flavor"];
if (value)
{
*data = [[NSString stringWithFormat:@"%X", [value intValue]]
asUnicodeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidLidSharingInitiatorEntryId: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
NSData *entryId;
value = [properties objectForKey: @"x-ms-sharing-initiatorentryid"];
if (value)
{
entryId = [value dataByDecodingBase64];
if (entryId)
{
*data = [entryId asBinaryInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
}
return rc;
}
- (int) getPidLidSharingInitiatorName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-initiatorname"
inData: data
inMemCtx: memCtx];
}
- (int) getPidLidSharingInitiatorSmtp: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-initiatorsmtp"
inData: data
inMemCtx: memCtx];
}
- (int) getPidLidSharingLocalType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-localtype"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingLocalType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingLocalType: data inMemCtx: memCtx];
}
- (int) getPidLidSharingProviderGuid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
const unsigned char providerGuidBytes[] = {0xAE, 0xF0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
NSData *providerGuid = [NSData dataWithBytes: providerGuidBytes length: 16];
*data = [providerGuid asBinaryInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidNameXSharingProviderGuid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"AEF0060000000000C000000000000046" asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidLidSharingProviderName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-providername"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingProviderName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingProviderName: data inMemCtx: memCtx];
}
- (int) getPidLidSharingProviderUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-providerurl"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingProviderUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingProviderUrl: data inMemCtx: memCtx];
}
- (int) getPidLidSharingRemoteName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-remotename"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingRemoteName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingRemoteName: data inMemCtx: memCtx];
}
- (int) getPidLidSharingRemoteStoreUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-remotestoreuid"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingRemoteStoreUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingRemoteStoreUid: data inMemCtx: memCtx];
}
- (int) getPidLidSharingRemoteType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-remotetype"
inData: data
inMemCtx: memCtx];
}
- (int) getPidTypeXSharingRemoteType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingRemoteType: data inMemCtx: memCtx];
}
- (int) getPidLidSharingRemoteUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-remoteuid"
inData: data
inMemCtx: memCtx];
}
- (int) getPidUidXSharingRemoteUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingRemoteUid: data inMemCtx: memCtx];
}
- (int) getPidLidSharingResponseTime: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: MAPIPropertyKey (PidLidSharingResponseTime)];
if (!value)
{
value = [properties objectForKey: @"x-ms-sharing-responsetime"];
if (value)
{
/* Here the value is a GSCBufferString */
NSString * responseTime = [NSString stringWithUTF8String: [value UTF8String]];
value = [NSDate dateWithString: responseTime];
}
}
if (value)
{
*data = [value asFileTimeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidLidSharingResponseType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: MAPIPropertyKey (PidLidSharingResponseType)];
if (!value)
value = [properties objectForKey: @"x-ms-sharing-responsetype"];
if (value)
{
*data = MAPILongValue (memCtx, [value intValue]);
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidNameContentClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = talloc_strdup (memCtx, "Sharing");
return MAPISTORE_SUCCESS;
}
- (void) saveWithMessage: (MAPIStoreMailMessage *) msg
andSOGoObject: (SOGoMailObject *) sogoObject
{
/* Store PidLidSharingResponseType and PidLidSharingResponseTime if
required in versions message from the container as I don't see
other straightforward place to put that information */
id response;
NSDictionary *propsToStore;
response = [[msg properties] objectForKey: MAPIPropertyKey (PidLidSharingResponseType)];
if (response)
{
/* FIXME: Is there any better way to increase the modseq? */
[sogoObject addFlags: @"\\Draft"];
[sogoObject removeFlags: @"\\Draft"];
/* Store this modification in container folder along the property values */
propsToStore = [NSDictionary dictionaryWithObjects:
[NSArray arrayWithObjects: response,
[[msg properties] objectForKey: MAPIPropertyKey (PidLidSharingResponseTime)],
nil]
forKeys:
[NSArray arrayWithObjects: MAPIPropertyKey (PidLidSharingResponseType),
MAPIPropertyKey (PidLidSharingResponseTime), nil]];
[(MAPIStoreMailFolder *)[msg container] setExtraProperties: propsToStore
forMessage: [msg nameInContainer]];
}
}
@end

View File

@ -367,13 +367,15 @@
NSString *status, *priority, *tzName;
NSCalendarDate *now;
NSInteger tzOffset;
NSTimeZone *userTZ;
double doubleValue;
vToDo = [sogoObject component: YES secure: NO];
vCalendar = [vToDo parent];
[vCalendar setProdID: @"-//Inverse inc.//OpenChange+SOGo//EN"];
tzName = [[[self userContext] timeZone] name];
userTZ = [[self userContext] timeZone];
tzName = [userTZ name];
tz = [iCalTimeZone timeZoneForName: tzName];
[vCalendar addTimeZone: tz];
@ -428,6 +430,13 @@
{
date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"dtstart"];
[date setTimeZone: tz];
/* The property is set to user's local time zone.
See: [MS-OXOTASK] 2.2.2.2.4
TODO: Ignore when the PT_SYSTIME is 0x5AE980E0*/
tzOffset = [userTZ secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];
[date setDateTime: value];
}
@ -437,6 +446,13 @@
{
date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"due"];
[date setTimeZone: tz];
/* The property is set to user's local time zone.
See: [MS-OXOTASK] 2.2.2.2.5
TODO: Ignore when the PT_SYSTIME is 0x5AE980E0*/
tzOffset = [userTZ secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];
[date setDateTime: value];
}
@ -445,7 +461,9 @@
if (value)
{
date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"completed"];
tzOffset = [[value timeZone] secondsFromGMTForDate: value];
/* The property is set to midnight in local time zone converted to UTC:
See: [MS-OXOTASK] 2.2.2.2.9 */
tzOffset = [userTZ secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];

View File

@ -119,6 +119,7 @@ NSObjectFromMAPISPropValue (const struct mapi_SPropValue *value)
break;
case PT_SYSTIME:
result = [NSCalendarDate dateFromFileTime: &(value->value.ft)];
[result setTimeZone: utcTZ];
break;
case PT_BINARY:
case PT_SVREID:
@ -154,8 +155,7 @@ NSObjectFromMAPISPropValue (const struct mapi_SPropValue *value)
// #define PT_I8 0x14
// #define PT_SRESTRICT 0xFD
// #define PT_ACTIONS 0xFE
result = [NSNull null];
abort();
result = nil;
NSLog (@"%s: object type not handled: %d (0x%.4x)",
__PRETTY_FUNCTION__, valueType, valueType);
}
@ -250,8 +250,7 @@ NSObjectFromSPropValue (const struct SPropValue *value)
// #define PT_I8 0x14
// #define PT_SRESTRICT 0xFD
// #define PT_ACTIONS 0xFE
result = [NSNull null];
abort();
result = nil;
NSLog (@"%s: object type not handled: %d (0x%.4x)",
__PRETTY_FUNCTION__, valueType, valueType);
}

View File

@ -311,9 +311,9 @@ static NSMapTable *contextsTable = nil;
parts in this url. We strip the '-' character in case we have
this in the domain part - like foo@bar-zot.com */
ocFSTableName = [NSString stringWithFormat: @"sogo_cache_folder_%@",
[[[user loginInDomain] asCSSIdentifier]
stringByReplacingOccurrencesOfString: @"-"
withString: @"_"]];
[[[user login] asCSSIdentifier]
stringByReplacingOccurrencesOfString: @"-"
withString: @"_"]];
[parts replaceObjectAtIndex: 4 withObject: ocFSTableName];
folderTableURL
= [NSURL URLWithString: [parts componentsJoinedByString: @"/"]];

View File

@ -26,6 +26,7 @@
// Useful macros
//
#define ADVANCE _bytes++; _current_pos++;
#define ADVANCE_N(N) _bytes += (N); _current_pos += (N);
#define REWIND _bytes--; _current_pos--;
@ -412,16 +413,46 @@ const unsigned short ansicpg874[256] = {
- (const char *) parseControlWord: (unsigned int *) len
{
const char *start, *end;
start = ADVANCE;
while (isalnum(*_bytes) || *_bytes == '-')
/*
A control word is defined by:
\<ASCII Letter Sequence><Delimiter>
*/
while (isalpha(*_bytes))
{
ADVANCE;
}
/*
The <Delimiter> can be one of the following:
- A space. This serves only to delimit a control word and is
ignored in subsequent processing.
- A numeric digit or an ASCII minus sign (-), which indicates
that a numeric parameter is associated with the control word.
Only this case requires to include it in the control word.
- Any character other than a letter or a digit
*/
if (*_bytes == '-' || isdigit(*_bytes))
{
ADVANCE;
while (isdigit(*_bytes)) // TODO: Allow up to 10 digits
{
ADVANCE;
}
}
/* In this case, the delimiting character terminates the control
word and is not part of the control word. */
end = _bytes;
*len = end-start-1;
return start+1;
}
@ -508,6 +539,7 @@ const unsigned short ansicpg874[256] = {
fontTable = [[[RTFFontTable alloc] init] autorelease];
fontName = nil;
fontInfo = nil;
count = 0;
do
@ -543,7 +575,7 @@ const unsigned short ansicpg874[256] = {
// Skip our control word
if (strncmp((const char*)cw, "fonttbl", len) == 0)
continue;
// We must at least parse <fontnum><fontfamily><fcharset>
s = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1
length: len-1
@ -558,12 +590,18 @@ const unsigned short ansicpg874[256] = {
// We now parse <fontfamily><fcharset>
cw = [self parseControlWord: &len];
if (len == 0) // Possibly parsing a space
cw = [self parseControlWord: &len];
fontInfo->family = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1
length: len-1
encoding: NSASCIIStringEncoding
freeWhenDone: NO];
cw = [self parseControlWord: &len];
if (len == 0) // Possibly parsing a space
cw = [self parseControlWord: &len];
fontInfo->charset = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1
length: len-1
encoding: NSASCIIStringEncoding
@ -622,13 +660,44 @@ const unsigned short ansicpg874[256] = {
} while (count != 0);
}
- (void) parseIgnoringEverything
{
unsigned int count = 1;
// Ignore everything. But we cannot parse it blindly because it could have
// binary data with '}' and '{' bytes, so disasters can happen and they will
do
{
if (*_bytes == '\\')
{
unsigned int binary_size, len = 0, cw_len;
const char *cw = [self parseControlWord: &len];
cw_len = strlen("bin");
if (strncmp(cw, "bin", cw_len) == 0 && len > cw_len)
{
NSString *s;
s = [[NSString alloc] initWithBytesNoCopy: (void *) cw + cw_len
length: len - cw_len
encoding: NSASCIIStringEncoding
freeWhenDone: NO];
[s autorelease];
binary_size = [s intValue];
ADVANCE_N(binary_size);
}
}
if (*_bytes == '{') count++;
if (*_bytes == '}') count--;
ADVANCE;
}
while (count > 0);
}
//
//
//
- (void) parsePicture
{
// Do the same as -parseStyleSheet for now, that is, ignore everything.
[self parseStyleSheet];
[self parseIgnoringEverything];
}
//
@ -648,6 +717,7 @@ const unsigned short ansicpg874[256] = {
fontTable = nil;
colorTable = nil;
charset = NULL;
formattingOptions = nil;
_html = [[NSMutableData alloc] init];
[_html appendBytes: "<html><meta charset='utf-8'><body>" length: 34];
@ -694,19 +764,7 @@ const unsigned short ansicpg874[256] = {
}
else if (*(_bytes+1) == '*')
{
int cc = 1;
do
{
if (*_bytes == '{')
cc++;
if (*_bytes == '}')
cc--;
ADVANCE;
}
while (cc != 0);
[self parseIgnoringEverything];
continue;
}
@ -726,16 +784,16 @@ const unsigned short ansicpg874[256] = {
{
// We rewind our buffer so we start at the beginning of {\fonttbl...
_bytes = cw-2;
_current_pos -= 10;
_current_pos -= 9; // Length: {\fonttbl
fontTable = [self parseFontTable];
// We go back 1 byte in order to end our section properly ('}' character
// We go back 1 byte in order to end our section properly ('}' character)
REWIND;
}
else if (strncmp(cw, "stylesheet", 10) == 0)
{
_bytes = cw-2;
_current_pos -= 13;
_current_pos -= 12; // Length: {\stylesheet
[self parseStyleSheet];
REWIND;
}
@ -746,7 +804,7 @@ const unsigned short ansicpg874[256] = {
else if (strncmp(cw, "pict", 4) == 0)
{
_bytes = cw-2;
_current_pos -= 7;
_current_pos -= 6; // Length: {\pict
[self parsePicture];
REWIND;
}
@ -766,19 +824,19 @@ const unsigned short ansicpg874[256] = {
int color_index;
char *v;
if (!formattingOptions) continue;
color_index = [[s substringFromIndex: 2] intValue];
if (!formattingOptions)
continue;
if (formattingOptions->color_index >= 0) // && color_index != formattingOptions->color_index)
colorDef = [colorTable colorDefAtIndex: color_index];
if (!colorDef) continue;
if (formattingOptions->color_index >= 0)
{
[_html appendBytes: "</font>" length: 7];
}
formattingOptions->color_index = color_index;
colorDef = [colorTable colorDefAtIndex: color_index];
formattingOptions->color_index = color_index;
v = malloc(23*sizeof(char));
memset(v, 0, 23);
sprintf(v, "<font color=\"#%02x%02x%02x\">", colorDef->red, colorDef->green, colorDef->blue);
@ -814,20 +872,41 @@ const unsigned short ansicpg874[256] = {
if (!formattingOptions)
continue;
if (formattingOptions->font_index >= 0 &&
font_index != formattingOptions->font_index)
{
[_html appendBytes: "</font>" length: 7];
}
formattingOptions->font_index = font_index;
fontInfo = [fontTable fontInfoAtIndex: font_index];
char *v = malloc(128*sizeof(char));
memset(v, 0, 128);
sprintf(v, "<font face=\"%s\">", [fontInfo->name UTF8String]);
char *v = NULL;
if (fontInfo && fontInfo->name)
{
if (fontInfo->name.length < 128)
{
int tag_size = 15 + fontInfo->name.length;
v = calloc(tag_size, sizeof(char));
snprintf(v, tag_size, "<font face=\"%s\">", [fontInfo->name UTF8String]);
}
else
{
NSLog(@"RTFHandler: Font %u has %d chars length, parse error? "
"Ignored", font_index, fontInfo->name.length);
v = calloc(7, sizeof(char));
sprintf(v, "<font>");
}
}
else
{
// RTF badformed? We don't know about that font (font_index).
// Anyhow, we still open the html tag because in the future
// we will close it (e.g. when new font is used).
v = calloc(7, sizeof(char));
sprintf(v, "<font>");
}
[_html appendBytes: v length: strlen(v)];
free(v);
}

View File

@ -39,7 +39,7 @@
#import <SOGo/BSONCodec.h>
#import "NSObject+PropertyList.h"
Class MAPIStoreUserContextK, SOGoMAPIDBObjectK;
Class MAPIStoreUserContextK, SOGoCacheGCSObjectK;
static void
DumpBSONData(NSData *data)
@ -60,7 +60,7 @@ DbDumpObject (NSString *username, NSString *path)
ctx = [MAPIStoreUserContextK userContextWithUsername: username
andTDBIndexing: NULL];
dbobject = [SOGoMAPIDBObjectK new];
dbobject = [SOGoCacheGCSObjectK new];
[dbobject setTableUrl: [ctx folderTableURL]];
record = [dbobject lookupRecord: path newerThanVersion: -1];
if (record)
@ -107,7 +107,7 @@ int main (int argc, char *argv[], char *envp[])
[loader loadProducts: [NSArray arrayWithObject: BACKEND_BUNDLE_NAME]];
MAPIStoreUserContextK = NSClassFromString (@"MAPIStoreUserContext");
SOGoMAPIDBObjectK = NSClassFromString (@"SOGoMAPIDBObject");
SOGoCacheGCSObjectK = NSClassFromString (@"SOGoCacheGCSObject");
arguments = [[NSProcessInfo processInfo] arguments];
if ([arguments count] > 2) {

View File

@ -74,6 +74,7 @@
@implementation iCalEvent (MAPIStoreProperties)
- (void) _setupEventRecurrence: (NSData *) mapiRecurrenceData
inTimeZone: (NSTimeZone *) tz
inMemCtx: (TALLOC_CTX *) memCtx
{
struct Binary_r *blob;
@ -81,9 +82,18 @@
blob = [mapiRecurrenceData asBinaryInMemCtx: memCtx];
pattern = get_AppointmentRecurrencePattern (memCtx, blob);
[(iCalCalendar *) parent
setupRecurrenceWithMasterEntity: self
fromRecurrencePattern: &pattern->RecurrencePattern];
if (pattern == NULL) {
[self logWithFormat: @"Error parsing recurrence pattern. No changes in event recurrence will be done"];
return;
}
[(iCalCalendar *) parent setupRecurrenceWithMasterEntity: self
fromRecurrencePattern: &pattern->RecurrencePattern
withExceptions: pattern->ExceptionInfo
andExceptionCount: pattern->ExceptionCount
inTimeZone: tz
];
//talloc_free (blob);
}
@ -131,6 +141,107 @@
}
}
- (int) _updateFromAttendeeMAPIProperties: (NSArray *) recipients
withRole: (NSString *) role
outParam: (BOOL *) organizerIsSet
{
NSDictionary *dict;
NSString *attEmail;
iCalPerson *person;
iCalPersonPartStat newPartStat;
NSNumber *flags, *trackStatus;
int i, effective;
effective = 0;
for (i = 0; i < [recipients count]; i++)
{
dict = [recipients objectAtIndex: i];
person = [iCalPerson new];
[person setCn: [dict objectForKey: @"fullName"]];
attEmail = [dict objectForKey: @"email"];
[person setEmail: attEmail];
flags = [dict objectForKey: MAPIPropertyKey (PR_RECIPIENT_FLAGS)];
if (!flags)
{
[self logWithFormat:
@"no recipient flags specified: skipping recipient"];
continue;
}
if (([flags unsignedIntValue] & 0x0002)) /* recipOrganizer */
{
[self setOrganizer: person];
*organizerIsSet = YES;
[self logWithFormat: @"organizer set via recipient flags"];
}
else
{
BOOL isOrganizer = NO;
// /* Work-around: it happens that Outlook still passes the
// organizer as a recipient, maybe because of a feature
// documented in a pre-mesozoic PDF still buried in a
// cavern... In that case we remove it, and we keep the
// number of effective recipients in "effective". If the
// total is 0, we remove the "ORGANIZER" too. */
// if ([attEmail isEqualToString: orgEmail])
// {
// [self logWithFormat:
// @"avoiding setting organizer as recipient"];
// continue;
// }
trackStatus = [dict objectForKey: MAPIPropertyKey (PidTagRecipientTrackStatus)];
if (trackStatus)
{
/* FIXME: we should provide a data converter between OL
partstats and SOGo */
switch ([trackStatus unsignedIntValue])
{
case 0x01: /* respOrganized */
isOrganizer = YES;
break;
case 0x02: /* respTentative */
newPartStat = iCalPersonPartStatTentative;
break;
case 0x03: /* respAccepted */
newPartStat = iCalPersonPartStatAccepted;
break;
case 0x04: /* respDeclined */
newPartStat = iCalPersonPartStatDeclined;
break;
default:
newPartStat = iCalPersonPartStatNeedsAction;
}
if (isOrganizer)
{
[self setOrganizer: person];
*organizerIsSet = YES;
[self logWithFormat: @"organizer set via track status"];
}
else
{
[person setParticipationStatus: newPartStat];
[person setRsvp: @"TRUE"];
[person setRole: role];
[self addToAttendees: person];
effective++;
}
}
else
[self errorWithFormat: @"skipped recipient due"
@" to missing track status"];
}
[person release];
}
return effective;
}
- (void) updateFromMAPIProperties: (NSDictionary *) properties
inUserContext: (MAPIStoreUserContext *) userContext
withActiveUser: (SOGoUser *) activeUser
@ -140,7 +251,7 @@
iCalDateTime *start, *end;
iCalTimeZone *tz;
NSTimeZone *userTimeZone;
NSString *priority;
NSString *priority, *class = nil;
NSUInteger responseStatus = 0;
NSInteger tzOffset;
SOGoUser *ownerUser;
@ -207,16 +318,7 @@
value
= [properties objectForKey: MAPIPropertyKey (PidLidExceptionReplaceTime)];
if (value)
{
if (!isAllDay)
{
tzOffset = [userTimeZone secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
}
[self setRecurrenceId: value];
}
[self setRecurrenceId: value];
// start
value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentStartWhole)];
@ -241,13 +343,7 @@
[start setTimeZone: nil];
}
else
{
tzOffset = [userTimeZone secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[start setDateTime: value];
}
}
/* end */
@ -273,13 +369,7 @@
[end setTimeZone: nil];
}
else
{
tzOffset = [[value timeZone] secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[end setDateTime: value];
}
}
/* priority */
@ -302,6 +392,36 @@
priority = @"0"; // None
[self setPriority: priority];
/* class */
/* See [MS-OXCICAL] Section 2.1.3.11.20.4 */
value = [properties objectForKey: MAPIPropertyKey(PR_SENSITIVITY)];
if (value)
{
switch ([value intValue])
{
case 1:
class = @"X-PERSONAL";
break;
case 2:
class = @"PRIVATE";
break;
case 3:
class = @"CONFIDENTIAL";
break;
default: /* 0 as well */
class = @"PUBLIC";
}
}
if (class)
[self setAccessClass: class];
/* Categories */
/* See [MS-OXCICAL] Section 2.1.3.1.1.20.3 */
value = [properties objectForKey: MAPIPropertyKey (PidNameKeywords)];
if (value)
[self setCategories: value];
/* show time as free/busy/tentative/out of office. Possible values are:
0x00000000 - olFree
0x00000001 - olTentative
@ -347,7 +467,7 @@
value = [properties
objectForKey: MAPIPropertyKey (PidLidAppointmentRecur)];
if (value)
[self _setupEventRecurrence: value inMemCtx: memCtx];
[self _setupEventRecurrence: value inTimeZone: userTimeZone inMemCtx: memCtx];
/* alarm */
[self _setupEventAlarmFromProperties: properties];
@ -356,106 +476,28 @@
value = [properties objectForKey: @"recipients"];
if (value)
{
NSArray *recipients;
NSDictionary *dict;
NSString *orgEmail, *sentBy, *attEmail;
NSString *orgEmail, *sentBy;
iCalPerson *person;
iCalPersonPartStat newPartStat;
NSNumber *flags, *trackStatus;
int i, effective;
int effective;
BOOL organizerIsSet = NO;
[self setOrganizer: nil];
[self removeAllAttendees];
recipients = [value objectForKey: @"to"];
effective = 0;
for (i = 0; i < [recipients count]; i++)
{
dict = [recipients objectAtIndex: i];
person = [iCalPerson new];
[person setCn: [dict objectForKey: @"fullName"]];
attEmail = [dict objectForKey: @"email"];
[person setEmail: attEmail];
flags = [dict objectForKey: MAPIPropertyKey (PR_RECIPIENT_FLAGS)];
if (!flags)
{
[self logWithFormat:
@"no recipient flags specified: skipping recipient"];
continue;
}
/* In [MS-OXOCAL] Section 2.2.4.10.7 says the recipient type is 0x01 as Required
and 0x02 as Optional and other documents such [MS-OXCMSG] 2.2.3.1.2 indicates
that MAPI_TO is 0x01 and MAPI_CC is 0x02, that's why in SOGo is in 'to' and 'cc'
respectively. */
effective = [self _updateFromAttendeeMAPIProperties: [value objectForKey: @"to"]
withRole: @"REQ-PARTICIPANT"
outParam: &organizerIsSet];
effective += [self _updateFromAttendeeMAPIProperties: [value objectForKey: @"cc"]
withRole: @"OPT-PARTICIPANT"
outParam: &organizerIsSet];
if (([flags unsignedIntValue] & 0x0002)) /* recipOrganizer */
{
[self setOrganizer: person];
organizerIsSet = YES;
[self logWithFormat: @"organizer set via recipient flags"];
}
else
{
BOOL isOrganizer = NO;
// /* Work-around: it happens that Outlook still passes the
// organizer as a recipient, maybe because of a feature
// documented in a pre-mesozoic PDF still buried in a
// cavern... In that case we remove it, and we keep the
// number of effective recipients in "effective". If the
// total is 0, we remove the "ORGANIZER" too. */
// if ([attEmail isEqualToString: orgEmail])
// {
// [self logWithFormat:
// @"avoiding setting organizer as recipient"];
// continue;
// }
trackStatus = [dict objectForKey: MAPIPropertyKey (PidTagRecipientTrackStatus)];
if (trackStatus)
{
/* FIXME: we should provide a data converter between OL
partstats and SOGo */
switch ([trackStatus unsignedIntValue])
{
case 0x01: /* respOrganized */
isOrganizer = YES;
break;
case 0x02: /* respTentative */
newPartStat = iCalPersonPartStatTentative;
break;
case 0x03: /* respAccepted */
newPartStat = iCalPersonPartStatAccepted;
break;
case 0x04: /* respDeclined */
newPartStat = iCalPersonPartStatDeclined;
break;
default:
newPartStat = iCalPersonPartStatNeedsAction;
}
if (isOrganizer)
{
[self setOrganizer: person];
organizerIsSet = YES;
[self logWithFormat: @"organizer set via track status"];
}
else
{
[person setParticipationStatus: newPartStat];
[person setRsvp: @"TRUE"];
[person setRole: @"REQ-PARTICIPANT"];
[self addToAttendees: person];
effective++;
}
}
else
[self errorWithFormat: @"skipped recipient due"
@" to missing track status"];
}
[person release];
}
if (effective == 0) /* See work-around above */
if (effective == 0) /* See work-around inside _updateFromAttendeeMAPIProperties */
[self setOrganizer: nil];
else
{
@ -481,7 +523,7 @@
= [properties objectForKey: MAPIPropertyKey (PidLidResponseStatus)];
if (value)
responseStatus = [value unsignedLongValue];
/* FIXME: we should provide a data converter between OL partstats and
SOGo */
switch (responseStatus)
@ -503,23 +545,6 @@
value = [properties objectForKey: MAPIPropertyKey (PidLidAttendeeCriticalChange)];
if (value && ![value isNever])
[self setTimeStampAsDate: value];
// if (newPartStat // != iCalPersonPartStatUndefined
// )
// {
// // iCalPerson *participant;
// // participant = [self userAsAttendee: ownerUser];
// // [participant setParticipationStatus: newPartStat];
// // [sogoObject saveComponent: self];
// [sogoObject changeParticipationStatus: newPartStat
// withDelegate: nil];
// // [[self context] tearDownRequest];
// }
// // }1005
// // else
// // {
}
}
else
@ -534,7 +559,7 @@
[person setCn: [dict objectForKey: @"fullName"]];
orgEmail = [dict objectForKey: @"email"];
[person setEmail: orgEmail];
if (![activeUser isEqual: ownerUser])
{
dict = [activeUser primaryIdentity];

View File

@ -51,6 +51,7 @@
NSArray *byMonth;
iCalByDayMask *mask;
NSCalendarDate *dateValue;
int16_t wDay;
rrule = [self recurrenceRule];
byMonth = [rrule byMonth];
@ -59,7 +60,14 @@
tzData->wMonth = [[byMonth objectAtIndex: 0] intValue];
mask = [rrule byDayMask];
tzData->wDayOfWeek = [mask firstDay];
tzData->wDay = [mask firstOccurrence];
wDay = [mask firstOccurrence];
if (wDay < 0)
/* [MS-OXOCAL] the wDay field is set to indicate the
occurrence of the day of the week within the month (1 to
5, where 5 indicates the final occurrence during the
month if that day of the week does not occur 5 times). */
wDay += 6;
tzData->wDay = (uint16_t) wDay;
dateValue = [self startDate];
tzData->wHour = [dateValue hourOfDay];

View File

@ -4,5 +4,6 @@ import sys
import samba.param
a = samba.param.LoadParm()
a.set('debug level', '0')
a.load_default()
print a.get(sys.argv[1])

View File

@ -55,8 +55,6 @@ static NSArray *privilegedTagNames = nil;
- (void) dealloc
{
if (content)
free (content);
[self reset];
[cards release];
[currentGroup release];

View File

@ -560,9 +560,9 @@ static int cssEscapingCount;
- (id) objectFromJSONString
{
SBJsonParser *parser;
NSObject *object;
NSArray *object;
NSError *error;
NSString *unescaped;
NSString *unescaped, *json;
object = nil;
@ -571,13 +571,16 @@ static int cssEscapingCount;
parser = [SBJsonParser new];
[parser autorelease];
error = nil;
object = [parser objectWithString: self
/* Parse it this way so we can parse simple values, like "null" */
json = [NSString stringWithFormat: @"[%@]", self];
object = [parser objectWithString: json
error: &error];
if (error)
{
[self errorWithFormat: @"json parser: %@,"
@" attempting once more after unescaping...", error];
unescaped = [self stringByReplacingString: @"\\\\"
unescaped = [json stringByReplacingString: @"\\\\"
withString: @"\\"];
object = [parser objectWithString: unescaped
error: &error];
@ -591,7 +594,7 @@ static int cssEscapingCount;
}
}
return object;
return [object objectAtIndex: 0];
}
- (NSString *) asSafeSQLString

View File

@ -49,6 +49,8 @@
andSortOrderings: (NSArray *) sortOrderings;
- (void) changePathTo: (NSString *) newPath;
- (void) changePathTo: (NSString *) newPath
intoNewContainer: (id) newContainer;
@end

View File

@ -308,6 +308,14 @@ Class SOGoCacheGCSObjectK = Nil;
[super changePathTo: newPath];
}
- (void) changePathTo: (NSString *) newPath intoNewContainer: (id) newContainer
{
[self changePathTo: newPath];
container = newContainer;
if ([self doesRetainContainer])
[container retain];
}
// - (NSArray *) toOneRelationshipKeysMatchingQualifier: (EOQualifier *) qualifier
// andSortOrderings: (NSArray *) sortOrderings
// {

View File

@ -83,6 +83,8 @@
- (BOOL) isInPublicZone;
- (BOOL) doesRetainContainer;
/* accessors */
- (void) setContext: (WOContext *) newContext;

View File

@ -142,7 +142,7 @@ typedef enum
parts in this url. We strip the '-' character in case we have
this in the domain part - like foo@bar-zot.com */
ocFSTableName = [NSMutableString stringWithFormat: @"sogo_cache_folder_%@",
[[user loginInDomain] asCSSIdentifier]];
[[user login] asCSSIdentifier]];
[ocFSTableName replaceOccurrencesOfString: @"-"
withString: @"_"
options: 0