Merge pull request #78 from Zentyal/contribute-back
Fixes for OpenChange integration from Zentyalpull/80/head
commit
a94591a365
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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 += \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -150,6 +150,7 @@
|
|||
|
||||
/* helpers */
|
||||
- (uint64_t) idForObjectWithKey: (NSString *) childKey;
|
||||
- (MAPIStoreFolder *) rootContainer;
|
||||
|
||||
/* subclasses */
|
||||
- (MAPIStoreMessage *) createMessage;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = ∝
|
||||
|
||||
/* 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 **) ¤t_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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
{
|
||||
BOOL headerSetup;
|
||||
BOOL mailIsEvent;
|
||||
BOOL mailIsSharingObject;
|
||||
NSString *mimeKey;
|
||||
NSString *headerCharset;
|
||||
NSString *headerEncoding;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)];
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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: @"/"]];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -55,8 +55,6 @@ static NSArray *privilegedTagNames = nil;
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
if (content)
|
||||
free (content);
|
||||
[self reset];
|
||||
[cards release];
|
||||
[currentGroup release];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -49,6 +49,8 @@
|
|||
andSortOrderings: (NSArray *) sortOrderings;
|
||||
|
||||
- (void) changePathTo: (NSString *) newPath;
|
||||
- (void) changePathTo: (NSString *) newPath
|
||||
intoNewContainer: (id) newContainer;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -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
|
||||
// {
|
||||
|
|
|
@ -83,6 +83,8 @@
|
|||
|
||||
- (BOOL) isInPublicZone;
|
||||
|
||||
- (BOOL) doesRetainContainer;
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (void) setContext: (WOContext *) newContext;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue