(feat) applied all changes as a patch coming from PR #180

pull/186/head
Ludovic Marcotte 2015-12-30 09:22:08 -05:00
parent d05fd407bd
commit ae6ed0c055
55 changed files with 2397 additions and 1243 deletions

View File

@ -145,7 +145,8 @@ $(DBMSGREADER_TOOL)_LIB_DIRS += \
-L../SoObjects/SOGo/SOGo.framework/sogo -lSOGo \ -L../SoObjects/SOGo/SOGo.framework/sogo -lSOGo \
-L../SOPE/GDLContentStore/obj/ -lGDLContentStore \ -L../SOPE/GDLContentStore/obj/ -lGDLContentStore \
-L../SOPE/NGCards/obj/ -lNGCards \ -L../SOPE/NGCards/obj/ -lNGCards \
-lNGObjWeb -lNGObjWeb \
$(LIBMAPI_LIBS)
TEST_TOOL_NAME += $(PLREADER_TOOL) $(DBMSGREADER_TOOL) TEST_TOOL_NAME += $(PLREADER_TOOL) $(DBMSGREADER_TOOL)

View File

@ -24,6 +24,7 @@
#define MAPISTORECALENDARWRAPPER_H #define MAPISTORECALENDARWRAPPER_H
#import <NGCards/iCalPerson.h> #import <NGCards/iCalPerson.h>
#import <NGCards/iCalTimeZone.h>
#import <Appointments/iCalEntityObject+SOGo.h> #import <Appointments/iCalEntityObject+SOGo.h>
#import "MAPIStoreObjectProxy.h" #import "MAPIStoreObjectProxy.h"
@ -42,7 +43,7 @@
iCalCalendar *calendar; iCalCalendar *calendar;
iCalEvent *firstEvent; iCalEvent *firstEvent;
iCalEvent *event; iCalEvent *event;
NSTimeZone *timeZone; iCalTimeZone *timeZone;
SOGoUser *user; SOGoUser *user;
NSString *senderEmail; NSString *senderEmail;
NSData *globalObjectId; NSData *globalObjectId;
@ -57,12 +58,10 @@
+ (id) wrapperWithICalEvent: (iCalEvent *) newEvent + (id) wrapperWithICalEvent: (iCalEvent *) newEvent
andUser: (SOGoUser *) newUser andUser: (SOGoUser *) newUser
andSenderEmail: (NSString *) newSenderEmail andSenderEmail: (NSString *) newSenderEmail
inTimeZone: (NSTimeZone *) newTimeZone
withConnectionInfo: (struct mapistore_connection_info *) newConnInfo; withConnectionInfo: (struct mapistore_connection_info *) newConnInfo;
- (id) initWithICalEvent: (iCalEvent *) newEvent - (id) initWithICalEvent: (iCalEvent *) newEvent
andUser: (SOGoUser *) newUser andUser: (SOGoUser *) newUser
andSenderEmail: (NSString *) newSenderEmail andSenderEmail: (NSString *) newSenderEmail
inTimeZone: (NSTimeZone *) newTimeZone
withConnectionInfo: (struct mapistore_connection_info *) newConnInfo; withConnectionInfo: (struct mapistore_connection_info *) newConnInfo;
/* getters */ /* getters */

View File

@ -37,7 +37,9 @@
#import <NGCards/iCalEventChanges.h> #import <NGCards/iCalEventChanges.h>
#import <NGCards/iCalPerson.h> #import <NGCards/iCalPerson.h>
#import <NGCards/iCalTrigger.h> #import <NGCards/iCalTrigger.h>
#import <NGCards/iCalTimeZonePeriod.h>
#import <NGCards/NSString+NGCards.h> #import <NGCards/NSString+NGCards.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoUser.h> #import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserManager.h> #import <SOGo/SOGoUserManager.h>
@ -80,7 +82,6 @@ static NSCharacterSet *hexCharacterSet = nil;
+ (id) wrapperWithICalEvent: (iCalEvent *) newEvent + (id) wrapperWithICalEvent: (iCalEvent *) newEvent
andUser: (SOGoUser *) newUser andUser: (SOGoUser *) newUser
andSenderEmail: (NSString *) newSenderEmail andSenderEmail: (NSString *) newSenderEmail
inTimeZone: (NSTimeZone *) newTimeZone
withConnectionInfo: (struct mapistore_connection_info *) newConnInfo withConnectionInfo: (struct mapistore_connection_info *) newConnInfo
{ {
MAPIStoreAppointmentWrapper *wrapper; MAPIStoreAppointmentWrapper *wrapper;
@ -88,7 +89,6 @@ static NSCharacterSet *hexCharacterSet = nil;
wrapper = [[self alloc] initWithICalEvent: newEvent wrapper = [[self alloc] initWithICalEvent: newEvent
andUser: newUser andUser: newUser
andSenderEmail: newSenderEmail andSenderEmail: newSenderEmail
inTimeZone: newTimeZone
withConnectionInfo: newConnInfo]; withConnectionInfo: newConnInfo];
[wrapper autorelease]; [wrapper autorelease];
@ -182,10 +182,10 @@ static NSCharacterSet *hexCharacterSet = nil;
- (id) initWithICalEvent: (iCalEvent *) newEvent - (id) initWithICalEvent: (iCalEvent *) newEvent
andUser: (SOGoUser *) newUser andUser: (SOGoUser *) newUser
andSenderEmail: (NSString *) newSenderEmail andSenderEmail: (NSString *) newSenderEmail
inTimeZone: (NSTimeZone *) newTimeZone
withConnectionInfo: (struct mapistore_connection_info *) newConnInfo withConnectionInfo: (struct mapistore_connection_info *) newConnInfo
{ {
NSArray *events; NSArray *events;
iCalTimeZone *tz;
if ((self = [self init])) if ((self = [self init]))
{ {
@ -194,9 +194,20 @@ static NSCharacterSet *hexCharacterSet = nil;
event = newEvent; event = newEvent;
events = [calendar events]; events = [calendar events];
firstEvent = [events objectAtIndex: 0]; firstEvent = [events objectAtIndex: 0];
ASSIGN (timeZone, newTimeZone);
ASSIGN (user, newUser); ASSIGN (user, newUser);
ASSIGN (senderEmail, newSenderEmail); ASSIGN (senderEmail, newSenderEmail);
/* If newEvent comes from the client, we set its time zone in
updateFromMAPIProperties. If it is not present, we use the
time zone of the user */
tz = (iCalTimeZone *) [calendar firstChildWithTag: @"vtimezone"];
if (!tz)
{
tz = [iCalTimeZone timeZoneForName: [[[user userDefaults] timeZone] name]];
if (!tz)
[self logWithFormat: @"no time zone could be set"];
}
ASSIGN (timeZone, tz);
[self _setupITIPContext]; [self _setupITIPContext];
} }
@ -266,7 +277,7 @@ static NSCharacterSet *hexCharacterSet = nil;
{ {
username = [contactInfos objectForKey: @"sAMAccountName"]; username = [contactInfos objectForKey: @"sAMAccountName"];
recipient->username = [username asUnicodeInMemCtx: msgData]; recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username); entryId = MAPIStoreInternalEntryId (connInfo, username);
} }
else else
{ {
@ -367,7 +378,7 @@ static NSCharacterSet *hexCharacterSet = nil;
{ {
username = [contactInfos objectForKey: @"sAMAccountName"]; username = [contactInfos objectForKey: @"sAMAccountName"];
recipient->username = [username asUnicodeInMemCtx: msgData]; recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username); entryId = MAPIStoreInternalEntryId (connInfo, username);
} }
else else
{ {
@ -721,22 +732,15 @@ static NSCharacterSet *hexCharacterSet = nil;
inMemCtx: (TALLOC_CTX *) memCtx inMemCtx: (TALLOC_CTX *) memCtx
{ {
NSCalendarDate *dateValue; NSCalendarDate *dateValue;
NSInteger offset;
// if ([event isRecurrent]) // if ([event isRecurrent])
// dateValue = [event firstRecurrenceStartDate]; // dateValue = [event firstRecurrenceStartDate];
// else // else
dateValue = [event startDate]; dateValue = [event startDate];
if ([event isAllDay]) if ([event isAllDay])
{ dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
offset = -[timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
}
[dateValue setTimeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx]; *data = [dateValue asFileTimeInMemCtx: memCtx];
return MAPISTORE_SUCCESS; return MAPISTORE_SUCCESS;
} }
@ -749,22 +753,14 @@ static NSCharacterSet *hexCharacterSet = nil;
exceptions, where it is the normal start date for the day of the exceptions, where it is the normal start date for the day of the
exception. */ exception. */
NSCalendarDate *dateValue; NSCalendarDate *dateValue;
NSInteger offset;
dateValue = [event recurrenceId]; dateValue = [event recurrenceId];
if (!dateValue) if (!dateValue)
dateValue = [event startDate]; dateValue = [event startDate];
[dateValue setTimeZone: timeZone];
if ([event isAllDay]) if ([event isAllDay])
{ dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
offset = -[timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
}
[dateValue setTimeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx]; *data = [dateValue asFileTimeInMemCtx: memCtx];
return MAPISTORE_SUCCESS; return MAPISTORE_SUCCESS;
} }
@ -772,19 +768,12 @@ static NSCharacterSet *hexCharacterSet = nil;
inMemCtx: (TALLOC_CTX *) memCtx inMemCtx: (TALLOC_CTX *) memCtx
{ {
NSCalendarDate *dateValue; NSCalendarDate *dateValue;
NSInteger offset;
dateValue = [firstEvent startDate]; dateValue = [firstEvent startDate];
if ([firstEvent isAllDay]) if ([firstEvent isAllDay])
{ dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
offset = -[timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
}
[dateValue setTimeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx]; *data = [dateValue asFileTimeInMemCtx: memCtx];
return MAPISTORE_SUCCESS; return MAPISTORE_SUCCESS;
} }
@ -804,8 +793,8 @@ static NSCharacterSet *hexCharacterSet = nil;
month: [start monthOfYear] month: [start monthOfYear]
day: [start dayOfMonth] day: [start dayOfMonth]
hour: 0 minute: 0 second: 0 hour: 0 minute: 0 second: 0
timeZone: timeZone]; timeZone: utcTZ];
[dateValue setTimeZone: utcTZ]; dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
*data = [dateValue asFileTimeInMemCtx: memCtx]; *data = [dateValue asFileTimeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS; rc = MAPISTORE_SUCCESS;
} }
@ -829,7 +818,7 @@ static NSCharacterSet *hexCharacterSet = nil;
dateValue = [event startDate]; dateValue = [event startDate];
offset = [event durationAsTimeInterval]; offset = [event durationAsTimeInterval];
if ([event isAllDay]) if ([event isAllDay])
offset -= [timeZone secondsFromGMTForDate: dateValue]; offset -= [[timeZone periodForDate: dateValue] secondsOffsetFromGMT];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0 hours: 0 minutes: 0
seconds: offset]; seconds: offset];
@ -847,15 +836,14 @@ static NSCharacterSet *hexCharacterSet = nil;
dateValue = [event recurrenceId]; dateValue = [event recurrenceId];
if (!dateValue) if (!dateValue)
dateValue = [event startDate]; dateValue = [event startDate];
[dateValue setTimeZone: timeZone];
offset = [firstEvent durationAsTimeInterval]; offset = [firstEvent durationAsTimeInterval];
if ([firstEvent isAllDay]) if ([firstEvent isAllDay])
offset -= [timeZone secondsFromGMTForDate: dateValue]; offset -= [[timeZone periodForDate: dateValue] secondsOffsetFromGMT];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0 hours: 0 minutes: 0
seconds: offset]; seconds: offset];
*data = [dateValue asFileTimeInMemCtx: memCtx]; *data = [dateValue asFileTimeInMemCtx: memCtx];
return MAPISTORE_SUCCESS; return MAPISTORE_SUCCESS;
} }
@ -871,7 +859,7 @@ static NSCharacterSet *hexCharacterSet = nil;
dateValue = [firstEvent startDate]; dateValue = [firstEvent startDate];
offset = [firstEvent durationAsTimeInterval]; offset = [firstEvent durationAsTimeInterval];
if ([event isAllDay]) if ([event isAllDay])
offset -= [timeZone secondsFromGMTForDate: dateValue]; offset -= [[timeZone periodForDate: dateValue] secondsOffsetFromGMT];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0 hours: 0 minutes: 0
seconds: offset]; seconds: offset];
@ -885,23 +873,14 @@ static NSCharacterSet *hexCharacterSet = nil;
{ {
enum mapistore_error rc; enum mapistore_error rc;
NSCalendarDate *dateValue; NSCalendarDate *dateValue;
NSInteger offset;
iCalRecurrenceRule *rrule; iCalRecurrenceRule *rrule;
if ([event isRecurrent]) if ([event isRecurrent])
{ {
rrule = [[event recurrenceRules] objectAtIndex: 0]; rrule = [[event recurrenceRules] objectAtIndex: 0];
dateValue = [rrule untilDate]; dateValue = [rrule untilDate];
if (dateValue) if (dateValue && [event isAllDay])
{ dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
if ([event isAllDay])
offset = -[timeZone secondsFromGMTForDate: dateValue];
else
offset = 0;
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
}
else else
dateValue = [NSCalendarDate dateWithYear: 4500 month: 8 day: 31 dateValue = [NSCalendarDate dateWithYear: 4500 month: 8 day: 31
hour: 23 minute: 59 second: 00 hour: 23 minute: 59 second: 00
@ -932,7 +911,7 @@ static NSCharacterSet *hexCharacterSet = nil;
if (contactInfos) if (contactInfos)
{ {
username = [contactInfos objectForKey: @"sAMAccountName"]; username = [contactInfos objectForKey: @"sAMAccountName"];
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username); entryId = MAPIStoreInternalEntryId (connInfo, username);
} }
else else
entryId = MAPIStoreExternalEntryId (cn, email); entryId = MAPIStoreExternalEntryId (cn, email);
@ -1338,21 +1317,14 @@ static NSCharacterSet *hexCharacterSet = nil;
{ {
enum mapistore_error rc; enum mapistore_error rc;
NSCalendarDate *dateValue; NSCalendarDate *dateValue;
NSInteger offset;
dateValue = [event recurrenceId]; dateValue = [event recurrenceId];
if (dateValue) if (dateValue)
{ {
rc = MAPISTORE_SUCCESS; rc = MAPISTORE_SUCCESS;
if ([event isAllDay]) if ([event isAllDay])
{ dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
offset = -[timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
}
[dateValue setTimeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx]; *data = [dateValue asFileTimeInMemCtx: memCtx];
} }
else else
@ -1377,7 +1349,6 @@ static NSCharacterSet *hexCharacterSet = nil;
iCalEventChanges *changes; iCalEventChanges *changes;
NSArray *changedProperties; NSArray *changedProperties;
NSCalendarDate *dateValue; NSCalendarDate *dateValue;
NSInteger offset;
changes = [iCalEventChanges changesFromEvent: event toEvent: exceptionEvent]; changes = [iCalEventChanges changesFromEvent: event toEvent: exceptionEvent];
@ -1385,28 +1356,17 @@ static NSCharacterSet *hexCharacterSet = nil;
memset (extendedException, 0, sizeof (struct ExtendedException)); memset (extendedException, 0, sizeof (struct ExtendedException));
extendedException->ChangeHighlight.Size = sizeof (uint32_t); extendedException->ChangeHighlight.Size = sizeof (uint32_t);
dateValue = [exceptionEvent startDate]; dateValue = [timeZone computedDateForDate: [exceptionEvent startDate]];
offset = [timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
exceptionInfo->StartDateTime = [dateValue asMinutesSince1601]; exceptionInfo->StartDateTime = [dateValue asMinutesSince1601];
extendedException->ChangeHighlight.Value = BIT_CH_START; extendedException->ChangeHighlight.Value = BIT_CH_START;
extendedException->StartDateTime = exceptionInfo->StartDateTime; extendedException->StartDateTime = exceptionInfo->StartDateTime;
dateValue = [exceptionEvent endDate]; dateValue = [timeZone computedDateForDate: [exceptionEvent endDate]];
offset = [timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
exceptionInfo->EndDateTime = [dateValue asMinutesSince1601]; exceptionInfo->EndDateTime = [dateValue asMinutesSince1601];
extendedException->ChangeHighlight.Value |= BIT_CH_END; extendedException->ChangeHighlight.Value |= BIT_CH_END;
extendedException->EndDateTime = exceptionInfo->EndDateTime; extendedException->EndDateTime = exceptionInfo->EndDateTime;
dateValue = [[exceptionEvent recurrenceId] dateValue = [timeZone computedDateForDate: [exceptionEvent recurrenceId]];
dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
exceptionInfo->OriginalStartDate = [dateValue asMinutesSince1601]; exceptionInfo->OriginalStartDate = [dateValue asMinutesSince1601];
extendedException->OriginalStartDate = exceptionInfo->OriginalStartDate; extendedException->OriginalStartDate = exceptionInfo->OriginalStartDate;
@ -1464,7 +1424,6 @@ static NSCharacterSet *hexCharacterSet = nil;
arp = talloc_zero (NULL, struct AppointmentRecurrencePattern); arp = talloc_zero (NULL, struct AppointmentRecurrencePattern);
[rule fillRecurrencePattern: &arp->RecurrencePattern [rule fillRecurrencePattern: &arp->RecurrencePattern
withEvent: event withEvent: event
inTimeZone: timeZone
inMemCtx: arp]; inMemCtx: arp];
arp->ReaderVersion2 = 0x00003006; arp->ReaderVersion2 = 0x00003006;
arp->WriterVersion2 = 0x00003008; /* 0x3008 for compatibility with arp->WriterVersion2 = 0x00003008; /* 0x3008 for compatibility with
@ -1475,7 +1434,7 @@ static NSCharacterSet *hexCharacterSet = nil;
fields are relative to midnight of those days ([MS-OXOCAL] 2.2.1.44.5), fields are relative to midnight of those days ([MS-OXOCAL] 2.2.1.44.5),
so no time zone adjustment is needed */ so no time zone adjustment is needed */
if (![event isAllDay]) if (![event isAllDay])
[firstStartDate setTimeZone: timeZone]; firstStartDate = [timeZone computedDateForDate: firstStartDate];
startMinutes = ([firstStartDate hourOfDay] * 60 startMinutes = ([firstStartDate hourOfDay] * 60
+ [firstStartDate minuteOfHour]); + [firstStartDate minuteOfHour]);
arp->StartTimeOffset = startMinutes; arp->StartTimeOffset = startMinutes;
@ -1701,15 +1660,16 @@ ReservedBlockEE2Size: 00 00 00 00
fromDate: (NSCalendarDate *) instanceDate; fromDate: (NSCalendarDate *) instanceDate;
{ {
uint16_t year; uint16_t year;
NSCalendarDate *dateValue;
if (instanceDate) if (instanceDate)
{ {
[instanceDate setTimeZone: timeZone]; dateValue = [timeZone computedDateForDate: instanceDate];
year = [instanceDate yearOfCommonEra]; year = [dateValue yearOfCommonEra];
newGlobalId->YH = year >> 8; newGlobalId->YH = year >> 8;
newGlobalId->YL = year & 0xff; newGlobalId->YL = year & 0xff;
newGlobalId->Month = [instanceDate monthOfYear]; newGlobalId->Month = [dateValue monthOfYear];
newGlobalId->D = [instanceDate dayOfMonth]; newGlobalId->D = [dateValue dayOfMonth];
} }
} }
@ -1974,7 +1934,6 @@ ReservedBlockEE2Size: 00 00 00 00
if (alarm) if (alarm)
{ {
alarmDate = [alarm nextAlarmDate]; alarmDate = [alarm nextAlarmDate];
[alarmDate setTimeZone: utcTZ];
*data = [alarmDate asFileTimeInMemCtx: memCtx]; *data = [alarmDate asFileTimeInMemCtx: memCtx];
} }
else else
@ -2036,8 +1995,7 @@ ReservedBlockEE2Size: 00 00 00 00
enum mapistore_error rc; enum mapistore_error rc;
NSString *tzid; NSString *tzid;
tzid = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] tzid = [timeZone tzId];
value: 0 ofAttribute: @"tzid"];
if ([tzid length] > 0) if ([tzid length] > 0)
{ {
*data = [tzid asUnicodeInMemCtx: memCtx]; *data = [tzid asUnicodeInMemCtx: memCtx];
@ -2053,16 +2011,9 @@ ReservedBlockEE2Size: 00 00 00 00
inMemCtx: (TALLOC_CTX *) memCtx inMemCtx: (TALLOC_CTX *) memCtx
{ {
enum mapistore_error rc; enum mapistore_error rc;
iCalTimeZone *icalTZ;
icalTZ = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] timeZone]; *data = [timeZone asTimeZoneStructInMemCtx: memCtx];
if (icalTZ) rc = MAPISTORE_SUCCESS;
{
*data = [icalTZ asTimeZoneStructInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc; return rc;
} }
@ -2071,24 +2022,16 @@ ReservedBlockEE2Size: 00 00 00 00
inMemCtx: (TALLOC_CTX *) memCtx inMemCtx: (TALLOC_CTX *) memCtx
{ {
enum mapistore_error rc; enum mapistore_error rc;
iCalTimeZone *icalTZ;
/* [MS-OXOCAL] 3.1.5.5.1: This property is used in floating (all-day) events, /* [MS-OXOCAL] 3.1.5.5.1: This property is used in floating (all-day) events,
specified in floating time, to convert the start date from UTC to the user's specified in floating time, to convert the start date from UTC to the user's
time zone */ time zone */
if ([event isAllDay]) if ([event isAllDay] | [event isRecurrent])
icalTZ = [iCalTimeZone timeZoneForName: [timeZone timeZoneName]];
else if ([event isRecurrent])
icalTZ = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] timeZone];
else
icalTZ = nil;
if (icalTZ)
{ {
/* [MS-OXOCAL] 2.2.1.42: This property can only have the E flag set in the /* [MS-OXOCAL] 2.2.1.42: This property can only have the E flag set in the
TimeZoneDefinition struct */ TimeZoneDefinition struct */
*data = [icalTZ asZoneTimeDefinitionWithFlags: TZRULE_FLAG_EFFECTIVE_TZREG *data = [timeZone asZoneTimeDefinitionWithFlags: TZRULE_FLAG_EFFECTIVE_TZREG
inMemCtx: memCtx]; inMemCtx: memCtx];
rc = MAPISTORE_SUCCESS; rc = MAPISTORE_SUCCESS;
} }
else else

View File

@ -58,7 +58,6 @@
wrapperWithICalEvent: [newContainer event] wrapperWithICalEvent: [newContainer event]
andUser: [userContext sogoUser] andUser: [userContext sogoUser]
andSenderEmail: nil andSenderEmail: nil
inTimeZone: [userContext timeZone]
withConnectionInfo: [context connectionInfo]]; withConnectionInfo: [context connectionInfo]];
[self addProxy: appointmentWrapper]; [self addProxy: appointmentWrapper];
} }

View File

@ -117,11 +117,11 @@
if ([roles containsObject: SOGoRole_ObjectCreator]) if ([roles containsObject: SOGoRole_ObjectCreator])
rights |= RightsCreateItems; rights |= RightsCreateItems;
if ([roles containsObject: SOGoRole_ObjectEraser]) if ([roles containsObject: SOGoRole_ObjectEraser])
rights |= RightsDeleteAll; rights |= RightsDeleteAll | RightsDeleteOwn;
if ([roles containsObject: SOGoCalendarRole_PublicModifier] if ([roles containsObject: SOGoCalendarRole_PublicModifier]
&& [roles containsObject: SOGoCalendarRole_PrivateModifier] && [roles containsObject: SOGoCalendarRole_PrivateModifier]
&& [roles containsObject: SOGoCalendarRole_ConfidentialModifier]) && [roles containsObject: SOGoCalendarRole_ConfidentialModifier])
rights |= RightsReadItems | RightsEditAll; rights |= RightsReadItems | RightsEditAll | RightsEditOwn;
else if ([roles containsObject: SOGoCalendarRole_PublicViewer] else if ([roles containsObject: SOGoCalendarRole_PublicViewer]
&& [roles containsObject: SOGoCalendarRole_PrivateViewer] && [roles containsObject: SOGoCalendarRole_PrivateViewer]
&& [roles containsObject: SOGoCalendarRole_ConfidentialViewer]) && [roles containsObject: SOGoCalendarRole_ConfidentialViewer])

View File

@ -197,7 +197,6 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
= [MAPIStoreAppointmentWrapper wrapperWithICalEvent: masterEvent = [MAPIStoreAppointmentWrapper wrapperWithICalEvent: masterEvent
andUser: [userContext sogoUser] andUser: [userContext sogoUser]
andSenderEmail: nil andSenderEmail: nil
inTimeZone: [userContext timeZone]
withConnectionInfo: [context connectionInfo]]; withConnectionInfo: [context connectionInfo]];
[self addProxy: appointmentWrapper]; [self addProxy: appointmentWrapper];
} }

View File

@ -96,9 +96,9 @@
if ([roles containsObject: SOGoRole_ObjectCreator]) if ([roles containsObject: SOGoRole_ObjectCreator])
rights |= RightsCreateItems; rights |= RightsCreateItems;
if ([roles containsObject: SOGoRole_ObjectEraser]) if ([roles containsObject: SOGoRole_ObjectEraser])
rights |= RightsDeleteAll; rights |= RightsDeleteAll | RightsDeleteOwn;
if ([roles containsObject: SOGoRole_ObjectEditor]) if ([roles containsObject: SOGoRole_ObjectEditor])
rights |= RightsEditAll; rights |= RightsEditAll | RightsEditOwn;
if ([roles containsObject: SOGoRole_ObjectViewer]) if ([roles containsObject: SOGoRole_ObjectViewer])
rights |= RightsReadItems; rights |= RightsReadItems;
if (rights != 0) if (rights != 0)

File diff suppressed because it is too large Load Diff

View File

@ -102,7 +102,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
{ {
value = get_SPropValue_SRow (aRow, PidTagDisplayName_string8); value = get_SPropValue_SRow (aRow, PidTagDisplayName_string8);
if (value) if (value)
folderName = [NSString stringWithUTF8String: value->value.lpszA]; folderName = [NSString stringWithUTF8String: (const char *) value->value.lpszA];
else else
folderName = nil; folderName = nil;
} }
@ -321,9 +321,9 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
if ([roles containsObject: MAPIStoreRightDeleteOwn]) if ([roles containsObject: MAPIStoreRightDeleteOwn])
rights |= RightsDeleteOwn; rights |= RightsDeleteOwn;
if ([roles containsObject: MAPIStoreRightEditAll]) if ([roles containsObject: MAPIStoreRightEditAll])
rights |= RightsEditAll; rights |= RightsEditAll | RightsEditOwn;
if ([roles containsObject: MAPIStoreRightDeleteAll]) if ([roles containsObject: MAPIStoreRightDeleteAll])
rights |= RightsDeleteAll; rights |= RightsDeleteAll | RightsDeleteOwn;
if ([roles containsObject: MAPIStoreRightCreateSubfolders]) if ([roles containsObject: MAPIStoreRightCreateSubfolders])
rights |= RightsCreateSubfolders; rights |= RightsCreateSubfolders;
if ([roles containsObject: MAPIStoreRightFolderOwner]) if ([roles containsObject: MAPIStoreRightFolderOwner])

View File

@ -109,18 +109,70 @@
return self; return self;
} }
- (NSString *) description
{
id key, value;
NSEnumerator *propEnumerator;
NSMutableString *description;
description = [NSMutableString stringWithFormat: @"%@ %@. Properties: {", NSStringFromClass ([self class]),
[self url]];
propEnumerator = [properties keyEnumerator];
while ((key = [propEnumerator nextObject]))
{
uint32_t proptag = 0;
if ([key isKindOfClass: [NSString class]] && [(NSString *)key intValue] > 0)
proptag = [(NSString *)key intValue];
else if ([key isKindOfClass: [NSNumber class]])
proptag = [key unsignedLongValue];
if (proptag > 0)
{
const char *propTagName = get_proptag_name ([key unsignedLongValue]);
NSString *propName;
if (propTagName)
propName = [NSString stringWithCString: propTagName
encoding: NSUTF8StringEncoding];
else
propName = [NSString stringWithFormat: @"0x%.4x", [key unsignedLongValue]];
[description appendFormat: @"'%@': ", propName];
}
else
[description appendFormat: @"'%@': ", key];
value = [properties objectForKey: key];
[description appendFormat: @"%@ (%@), ", value, NSStringFromClass ([value class])];
}
[description appendString: @"}\n"];
return description;
}
- (uint64_t) objectVersion - (uint64_t) objectVersion
{ {
NSNumber *versionNbr; /* Return the global counter from CN structure.
See [MS-OXCFXICS] Section 2.2.2.1 */
NSNumber *versionNbr, *cn;
uint64_t objectVersion; uint64_t objectVersion;
[(SOGoMAPIDBMessage *) sogoObject reloadIfNeeded]; [(SOGoMAPIDBMessage *) sogoObject reloadIfNeeded];
versionNbr = [properties objectForKey: @"version"]; versionNbr = [properties objectForKey: @"version_number"];
if (versionNbr) if (versionNbr)
objectVersion = (([versionNbr unsignedLongLongValue] >> 16) objectVersion = exchange_globcnt ([versionNbr unsignedLongLongValue]);
& 0x0000ffffffffffffLL);
else else
objectVersion = ULLONG_MAX; {
/* Old version which stored the CN structure not useful for searching */
cn = [properties objectForKey: @"version"];
if (cn)
objectVersion = (([cn unsignedLongLongValue] >> 16)
& 0x0000ffffffffffffLL);
else
objectVersion = ULLONG_MAX;
}
return objectVersion; return objectVersion;
} }
@ -283,13 +335,19 @@
[properties setObject: attachmentParts forKey: @"attachments"]; [properties setObject: attachmentParts forKey: @"attachments"];
newVersion = [[self context] getNewChangeNumber]; newVersion = [[self context] getNewChangeNumber];
newVersion = exchange_globcnt ((newVersion >> 16) & 0x0000ffffffffffffLL);
[properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion] [properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion]
forKey: @"version"]; forKey: @"version_number"];
/* Remove old version */
[properties removeObjectForKey: @"version"];
/* Update PredecessorChangeList accordingly */ /* Update PredecessorChangeList accordingly */
[self _updatePredecessorChangeList]; [self _updatePredecessorChangeList];
[self logWithFormat: @"%d props in dict", [properties count]]; // [self logWithFormat: @"Saving %@", [self description]];
// [self logWithFormat: @"%d props in dict", [properties count]];
[sogoObject save]; [sogoObject save];
} }

View File

@ -61,14 +61,15 @@ static Class MAPIStoreDBMessageK = Nil;
if ((uint32_t) res->ulPropTag == PidTagChangeNumber) if ((uint32_t) res->ulPropTag == PidTagChangeNumber)
{ {
SEL operator;
value = NSObjectFromMAPISPropValue (&res->lpProp); value = NSObjectFromMAPISPropValue (&res->lpProp);
cVersion = exchange_globcnt (([value unsignedLongLongValue] >> 16) cVersion = exchange_globcnt (([value unsignedLongLongValue] >> 16)
& 0x0000ffffffffffffLL); & 0x0000ffffffffffffLL);
version = [NSNumber numberWithUnsignedLongLong: cVersion]; version = [NSNumber numberWithUnsignedLongLong: cVersion];
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]]; operator = [self operatorFromRestrictionOperator: res->relop];
[self logWithFormat: @" version: %.16lx", cVersion]; *qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"version_number"
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"version" operatorSelector: operator
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: version]; value: version];
[*qualifier autorelease]; [*qualifier autorelease];
rc = MAPIRestrictionStateNeedsEval; rc = MAPIRestrictionStateNeedsEval;

View File

@ -1549,7 +1549,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
struct Binary_r bin32; struct Binary_r bin32;
struct AddressBookEntryId *entryId; struct AddressBookEntryId *entryId;
NSString *username; NSString *username;
struct ldb_context *samCtx;
if (bin && bin->cb) if (bin && bin->cb)
{ {
@ -1559,8 +1558,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
entryId = get_AddressBookEntryId (NULL, &bin32); entryId = get_AddressBookEntryId (NULL, &bin32);
if (entryId) if (entryId)
{ {
samCtx = [[self context] connectionInfo]->sam_ctx; username = MAPIStoreSamDBUserAttribute ([[self context] connectionInfo],
username = MAPIStoreSamDBUserAttribute (samCtx, @"legacyExchangeDN", @"legacyExchangeDN",
[NSString stringWithUTF8String: entryId->X500DN], [NSString stringWithUTF8String: entryId->X500DN],
@"sAMAccountName"); @"sAMAccountName");
} }

View File

@ -681,12 +681,12 @@ static Class NSNumberK;
- (NSNumber *) lastModifiedFromMessageChangeNumber: (NSString *) changeNumber - (NSNumber *) lastModifiedFromMessageChangeNumber: (NSString *) changeNumber
{ {
NSDictionary *mapping; NSDictionary *mapping;
NSNumber *modseq; NSNumber *lastModified;
mapping = [[versionsMessage properties] objectForKey: @"VersionMapping"]; mapping = [[versionsMessage properties] objectForKey: @"VersionMapping"];
modseq = [mapping objectForKey: changeNumber]; lastModified = [mapping objectForKey: changeNumber];
return modseq; return lastModified;
} }
- (NSString *) changeNumberForMessageWithKey: (NSString *) messageKey - (NSString *) changeNumberForMessageWithKey: (NSString *) messageKey

View File

@ -140,9 +140,16 @@
[parentFolder synchroniseCache]; [parentFolder synchroniseCache];
changeKey = [parentFolder changeKeyForMessageWithKey: nameInContainer]; changeKey = [parentFolder changeKeyForMessageWithKey: nameInContainer];
} }
if (!changeKey) if (changeKey)
abort (); *data = [changeKey asBinaryInMemCtx: memCtx];
*data = [changeKey asBinaryInMemCtx: memCtx]; else
{
[self warnWithFormat: @"No change key for %@ in folder %@",
nameInContainer,
[parentFolder url]
];
rc = MAPISTORE_ERR_NOT_FOUND;
}
} }
return rc; return rc;

View File

@ -27,6 +27,7 @@
#import <Foundation/NSString.h> #import <Foundation/NSString.h>
#import <NGExtensions/NSObject+Logs.h> #import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSObject+Values.h>
#import <EOControl/EOFetchSpecification.h> #import <EOControl/EOFetchSpecification.h>
#import <EOControl/EOQualifier.h> #import <EOControl/EOQualifier.h>
@ -38,7 +39,6 @@
#import "MAPIStoreTypes.h" #import "MAPIStoreTypes.h"
#import "MAPIStoreGCSFolder.h" #import "MAPIStoreGCSFolder.h"
#import "MAPIStoreGCSMessageTable.h" #import "MAPIStoreGCSMessageTable.h"
#undef DEBUG #undef DEBUG
@ -89,21 +89,31 @@
if (res->ulPropTag == PidTagChangeNumber) if (res->ulPropTag == PidTagChangeNumber)
{ {
NSString *changeNumber;
value = NSObjectFromMAPISPropValue (&res->lpProp); value = NSObjectFromMAPISPropValue (&res->lpProp);
changeNumber = [NSString stringWithUnsignedLongLong: [(NSNumber *)value unsignedLongLongValue]];
lastModified = [(MAPIStoreGCSFolder *) lastModified = [(MAPIStoreGCSFolder *)
container lastModifiedFromMessageChangeNumber: value]; container lastModifiedFromMessageChangeNumber: changeNumber];
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]]; //[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
//[self logWithFormat: @" c_lastmodified: %@", lastModified]; //[self logWithFormat: @" c_lastmodified: %@", lastModified];
if (lastModified) if (lastModified)
{ {
SEL operator;
operator = [self operatorFromRestrictionOperator: res->relop];
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_lastmodified" *qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_lastmodified"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo operatorSelector: operator
value: lastModified]; value: lastModified];
[*qualifier autorelease]; [*qualifier autorelease];
rc = MAPIRestrictionStateNeedsEval; rc = MAPIRestrictionStateNeedsEval;
} }
else else
rc = MAPIRestrictionStateAlwaysTrue; {
[self logWithFormat: @"No last modified found for: 0x%.16"PRIx64". Then no restriction applied",
[value unsignedLongLongValue]];
rc = MAPIRestrictionStateAlwaysTrue;
}
} }
else else
{ {

View File

@ -74,6 +74,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
#include <util/attr.h> #include <util/attr.h>
#include <libmapi/libmapi.h> #include <libmapi/libmapi.h>
#include <libmapiproxy.h> #include <libmapiproxy.h>
#include <limits.h>
#include <mapistore/mapistore.h> #include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h> #include <mapistore/mapistore_errors.h>
@ -181,7 +182,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
if (aRow->lpProps[i].ulPropTag == PR_DISPLAY_NAME_UNICODE) if (aRow->lpProps[i].ulPropTag == PR_DISPLAY_NAME_UNICODE)
folderName = [NSString stringWithUTF8String: aRow->lpProps[i].value.lpszW]; folderName = [NSString stringWithUTF8String: aRow->lpProps[i].value.lpszW];
else if (aRow->lpProps[i].ulPropTag == PR_DISPLAY_NAME) else if (aRow->lpProps[i].ulPropTag == PR_DISPLAY_NAME)
folderName = [NSString stringWithUTF8String: aRow->lpProps[i].value.lpszA]; folderName = [NSString stringWithUTF8String: (const char *) aRow->lpProps[i].value.lpszA];
} }
if (folderName) if (folderName)
@ -257,6 +258,67 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
return MAPISTORE_SUCCESS; return MAPISTORE_SUCCESS;
} }
- (EOQualifier *) simplifyQualifier: (EOQualifier *) qualifier
{
/* Hack: Reduce the number of MODSEQ constraints to a single one as
we assume the difference among MODSEQs will be small enough to
return a small number of UIDs.
This is the only case we do simplify:
MODSEQ >= x | MODSEQ >= y | MODSEQ >= z => MODSEQ >= min(x,y,z)
*/
if (qualifier && [qualifier isKindOfClass: [EOOrQualifier class]])
{
EOQualifier *simplifiedQualifier;
NSArray *quals;
NSNumber *minModseq;
NSUInteger i, count;
quals = [(EOOrQualifier *)qualifier qualifiers];
count = [quals count];
if (count < 2)
return qualifier;
minModseq = [NSNumber numberWithUnsignedLongLong: ULLONG_MAX];
for (i = 0; i < count; i++)
{
EOQualifier *subQualifier;
subQualifier = [quals objectAtIndex: i];
if ([subQualifier isKindOfClass: [EOAndQualifier class]]
&& [[(EOAndQualifier *)subQualifier qualifiers] count] == 1)
subQualifier = [[(EOAndQualifier *)subQualifier qualifiers] objectAtIndex: 0];
if ([subQualifier isKindOfClass: [EOKeyValueQualifier class]]
&& [[(EOKeyValueQualifier *)subQualifier key] isEqualToString: @"MODSEQ"])
{
NSNumber *value;
value = (NSNumber *)[(EOKeyValueQualifier *)subQualifier value];
if ([minModseq compare: value] == NSOrderedDescending
&& [value unsignedLongLongValue] > 0)
minModseq = (NSNumber *)[(EOKeyValueQualifier *)subQualifier value];
}
else
return qualifier;
}
if ([minModseq unsignedLongLongValue] > 0 && [minModseq unsignedLongLongValue] < ULLONG_MAX)
{
simplifiedQualifier = [[EOKeyValueQualifier alloc]
initWithKey: @"MODSEQ"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: minModseq];
[simplifiedQualifier autorelease];
return simplifiedQualifier;
}
}
return qualifier;
}
- (EOQualifier *) nonDeletedQualifier - (EOQualifier *) nonDeletedQualifier
{ {
static EOQualifier *nonDeletedQualifier = nil; static EOQualifier *nonDeletedQualifier = nil;
@ -281,7 +343,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
andSortOrderings: (NSArray *) sortOrderings andSortOrderings: (NSArray *) sortOrderings
{ {
NSArray *uidKeys; NSArray *uidKeys;
EOQualifier *fetchQualifier; EOQualifier *fetchQualifier, *simplifiedQualifier;
if ([self ensureFolderExists]) if ([self ensureFolderExists])
{ {
@ -290,9 +352,10 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
if (qualifier) if (qualifier)
{ {
simplifiedQualifier = [self simplifyQualifier: qualifier];
fetchQualifier fetchQualifier
= [[EOAndQualifier alloc] initWithQualifiers: = [[EOAndQualifier alloc] initWithQualifiers:
[self nonDeletedQualifier], qualifier, [self nonDeletedQualifier], simplifiedQualifier,
nil]; nil];
[fetchQualifier autorelease]; [fetchQualifier autorelease];
} }
@ -599,7 +662,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
uint64_t lastModseqNbr; uint64_t lastModseqNbr;
EOQualifier *searchQualifier; EOQualifier *searchQualifier;
NSArray *uids, *changeNumbers; NSArray *uids, *changeNumbers;
NSUInteger count, max; NSUInteger count, max, nFetched;
NSArray *fetchResults; NSArray *fetchResults;
NSDictionary *result; NSDictionary *result;
NSData *changeKey; NSData *changeKey;
@ -678,6 +741,13 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
= [fetchResults sortedArrayUsingFunction: _compareFetchResultsByMODSEQ = [fetchResults sortedArrayUsingFunction: _compareFetchResultsByMODSEQ
context: NULL]; context: NULL];
nFetched = [fetchResults count];
if (nFetched != max) {
[self errorWithFormat: @"Error fetching UIDs. Asked: %d Received: %d."
@"Check the IMAP conversation for details", max, nFetched];
return NO;
}
for (count = 0; count < max; count++) for (count = 0; count < max; count++)
{ {
result = [fetchResults objectAtIndex: count]; result = [fetchResults objectAtIndex: count];
@ -1641,10 +1711,10 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
rights |= RightsCreateItems; rights |= RightsCreateItems;
if ([roles containsObject: SOGoRole_ObjectEraser] if ([roles containsObject: SOGoRole_ObjectEraser]
&& [roles containsObject: SOGoRole_FolderEraser]) && [roles containsObject: SOGoRole_FolderEraser])
rights |= RightsDeleteAll; rights |= RightsDeleteAll | RightsDeleteOwn;
if ([roles containsObject: SOGoRole_ObjectEditor]) if ([roles containsObject: SOGoRole_ObjectEditor])
rights |= RightsEditAll; rights |= RightsEditAll | RightsEditOwn;
if ([roles containsObject: SOGoRole_ObjectViewer]) if ([roles containsObject: SOGoRole_ObjectViewer])
rights |= RightsReadItems; rights |= RightsReadItems;
if ([roles containsObject: SOGoRole_FolderCreator]) if ([roles containsObject: SOGoRole_FolderCreator])

View File

@ -340,7 +340,6 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
wrapperWithICalEvent: event wrapperWithICalEvent: event
andUser: [context activeUser] andUser: [context activeUser]
andSenderEmail: senderEmail andSenderEmail: senderEmail
inTimeZone: [[self userContext] timeZone]
withConnectionInfo: [context connectionInfo]]; withConnectionInfo: [context connectionInfo]];
[appointmentWrapper retain]; [appointmentWrapper retain];
} }
@ -522,6 +521,9 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
NSUInteger colIdx; NSUInteger colIdx;
NSString *stringValue; NSString *stringValue;
/* As specified in [MS-OXCMAIL] 2.2.3.2.6.1, if there are three
or less characters followed by a colon at the beginning of
the subject, we can assume that's the subject prefix */
subject = [self subject]; subject = [self subject];
colIdx = [subject rangeOfString: @":"].location; colIdx = [subject rangeOfString: @":"].location;
if (colIdx != NSNotFound && colIdx < 4) if (colIdx != NSNotFound && colIdx < 4)
@ -537,17 +539,45 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
- (int) getPidTagNormalizedSubject: (void **) data - (int) getPidTagNormalizedSubject: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx inMemCtx: (TALLOC_CTX *) memCtx
{ {
NSString *subject; NSString *stringValue, *subject;
NSUInteger colIdx; NSUInteger quoteStartIdx, quoteEndIdx, colIdx;
NSString *stringValue; NSRange quoteRange;
if (!headerSetup)
[self _fetchHeaderData];
subject = [self subject]; subject = [self subject];
colIdx = [subject rangeOfString: @":"].location; if (mailIsMeetingRequest)
if (colIdx != NSNotFound && colIdx < 4) {
stringValue = [[subject substringFromIndex: colIdx + 1]
stringByTrimmingLeadSpaces]; /* SOGo "spices up" the invitation/update mail's subject, but
the client uses it to name the attendee's event, so we keep
only what's inside the quotes */
quoteStartIdx = [subject rangeOfString: @"\""].location;
quoteEndIdx = [subject rangeOfString: @"\""
options: NSBackwardsSearch].location;
if (quoteStartIdx != NSNotFound
&& quoteEndIdx != NSNotFound
&& quoteStartIdx != quoteEndIdx)
{
quoteRange = NSMakeRange(quoteStartIdx + 1, quoteEndIdx - quoteStartIdx - 1);
stringValue = [subject substringWithRange: quoteRange];
}
else stringValue = subject;
}
else else
stringValue = subject; {
/* As specified in [MS-OXCMAIL] 2.2.3.2.6.1, if there are three
or less characters followed by a colon at the beginning of
the subject, we can assume that's the subject prefix */
colIdx = [subject rangeOfString: @":"].location;
if (colIdx != NSNotFound && colIdx < 4)
stringValue = [[subject substringFromIndex: colIdx + 1]
stringByTrimmingLeadSpaces];
else
stringValue = subject;
}
if (!stringValue) if (!stringValue)
stringValue = @""; stringValue = @"";
*data = [stringValue asUnicodeInMemCtx: memCtx]; *data = [stringValue asUnicodeInMemCtx: memCtx];
@ -780,7 +810,6 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
NSDictionary *contactInfos; NSDictionary *contactInfos;
NGMailAddress *ngAddress; NGMailAddress *ngAddress;
NSData *entryId; NSData *entryId;
struct ldb_context *samCtx;
int rc; int rc;
if (fullMail) if (fullMail)
@ -803,8 +832,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if (contactInfos) if (contactInfos)
{ {
username = [contactInfos objectForKey: @"sAMAccountName"]; username = [contactInfos objectForKey: @"sAMAccountName"];
samCtx = [[self context] connectionInfo]->sam_ctx; entryId = MAPIStoreInternalEntryId([[self context] connectionInfo], username);
entryId = MAPIStoreInternalEntryId (samCtx, username);
} }
else else
entryId = MAPIStoreExternalEntryId (cn, email); entryId = MAPIStoreExternalEntryId (cn, email);
@ -1447,11 +1475,9 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
NSData *entryId; NSData *entryId;
NSDictionary *contactInfos; NSDictionary *contactInfos;
SOGoUserManager *mgr; SOGoUserManager *mgr;
struct ldb_context *samCtx;
struct mapistore_message *msgData; struct mapistore_message *msgData;
struct mapistore_message_recipient *recipient; struct mapistore_message_recipient *recipient;
samCtx = [[self context] connectionInfo]->sam_ctx;
[super getMessageData: &msgData inMemCtx: memCtx]; [super getMessageData: &msgData inMemCtx: memCtx];
if (!headerSetup) if (!headerSetup)
@ -1505,7 +1531,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
{ {
username = [contactInfos objectForKey: @"sAMAccountName"]; username = [contactInfos objectForKey: @"sAMAccountName"];
recipient->username = [username asUnicodeInMemCtx: msgData]; recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (samCtx, username); entryId = MAPIStoreInternalEntryId ([[self context] connectionInfo], username);
} }
else else
{ {

View File

@ -181,8 +181,8 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK;
else else
{ {
/* Ignore other operations as IMAP only support MODSEQ >= X */ /* Ignore other operations as IMAP only support MODSEQ >= X */
[self warnWithFormat: @"Ignoring %@ as only supported operators are > and >=", [self warnWithFormat: @"Ignoring '%@' as only supported operators are > and >=",
[self operatorFromRestrictionOperator: res->relop]]; NSStringFromSelector ([self operatorFromRestrictionOperator: res->relop])];
rc = MAPIRestrictionStateAlwaysTrue; rc = MAPIRestrictionStateAlwaysTrue;
} }
} }

View File

@ -338,13 +338,10 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
NSData *entryId; NSData *entryId;
NSDictionary *allRecipients, *dict, *contactInfos; NSDictionary *allRecipients, *dict, *contactInfos;
SOGoUserManager *mgr; SOGoUserManager *mgr;
struct ldb_context *samCtx;
struct mapistore_message *msgData; struct mapistore_message *msgData;
struct mapistore_message_recipient *recipient; struct mapistore_message_recipient *recipient;
enum ulRecipClass type; enum ulRecipClass type;
samCtx = [[self context] connectionInfo]->sam_ctx;
// [super getMessageData: &msgData inMemCtx: memCtx]; // [super getMessageData: &msgData inMemCtx: memCtx];
msgData = talloc_zero (memCtx, struct mapistore_message); msgData = talloc_zero (memCtx, struct mapistore_message);
@ -389,7 +386,7 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
{ {
username = [contactInfos objectForKey: @"sAMAccountName"]; username = [contactInfos objectForKey: @"sAMAccountName"];
recipient->username = [username asUnicodeInMemCtx: msgData]; recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (samCtx, username); entryId = MAPIStoreInternalEntryId ([[self context] connectionInfo], username);
} }
else else
{ {
@ -682,6 +679,14 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
if (!fromResolved) if (!fromResolved)
{ {
TALLOC_CTX *local_mem_ctx;
local_mem_ctx = talloc_new(NULL);
if (!local_mem_ctx)
{
NSLog (@"%s: Out of memory", __PRETTY_FUNCTION__);
return;
}
NSLog (@"Message without an orig from, try to guess it from PidTagSenderEntryId"); NSLog (@"Message without an orig from, try to guess it from PidTagSenderEntryId");
senderEntryId = [mailProperties objectForKey: MAPIPropertyKey (PR_SENDER_ENTRYID)]; senderEntryId = [mailProperties objectForKey: MAPIPropertyKey (PR_SENDER_ENTRYID)];
if (senderEntryId) if (senderEntryId)
@ -695,12 +700,12 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
bin32.cb = [senderEntryId length]; bin32.cb = [senderEntryId length];
bin32.lpb = (uint8_t *) [senderEntryId bytes]; bin32.lpb = (uint8_t *) [senderEntryId bytes];
addrBookEntryId = get_AddressBookEntryId (connInfo->sam_ctx, &bin32); addrBookEntryId = get_AddressBookEntryId (local_mem_ctx, &bin32);
if (addrBookEntryId && [[NSString stringWithGUID: &addrBookEntryId->ProviderUID] if (addrBookEntryId && [[NSString stringWithGUID: &addrBookEntryId->ProviderUID]
hasSuffix: @"08002b2fe182"]) hasSuffix: @"08002b2fe182"])
{ {
/* TODO: better way to distinguish local and other ones */ /* TODO: better way to distinguish local and other ones */
username = MAPIStoreSamDBUserAttribute (connInfo->sam_ctx, @"legacyExchangeDN", username = MAPIStoreSamDBUserAttribute (connInfo, @"legacyExchangeDN",
[NSString stringWithUTF8String: addrBookEntryId->X500DN], @"sAMAccountName"); [NSString stringWithUTF8String: addrBookEntryId->X500DN], @"sAMAccountName");
if (username) if (username)
{ {
@ -721,7 +726,7 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
/* Try with One-Off EntryId */ /* Try with One-Off EntryId */
struct OneOffEntryId *oneOffEntryId; struct OneOffEntryId *oneOffEntryId;
oneOffEntryId = get_OneOffEntryId (connInfo->sam_ctx, &bin32); oneOffEntryId = get_OneOffEntryId (local_mem_ctx, &bin32);
if (oneOffEntryId && [[NSString stringWithGUID: &oneOffEntryId->ProviderUID] if (oneOffEntryId && [[NSString stringWithGUID: &oneOffEntryId->ProviderUID]
hasSuffix: @"00dd010f5402"]) hasSuffix: @"00dd010f5402"])
{ {
@ -730,9 +735,7 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
[fromRecipient setObject: [NSString stringWithUTF8String: oneOffEntryId->EmailAddress.lpszW] [fromRecipient setObject: [NSString stringWithUTF8String: oneOffEntryId->EmailAddress.lpszW]
forKey: @"email"]; forKey: @"email"];
} }
talloc_free (oneOffEntryId);
} }
talloc_free (addrBookEntryId);
if ([[fromRecipient allKeys] count] > 0) if ([[fromRecipient allKeys] count] > 0)
{ {
@ -742,6 +745,8 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
} }
} }
/* Free entryId */
talloc_free(local_mem_ctx);
} }
if (!recipients) if (!recipients)
@ -1008,7 +1013,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
- (NGMimeMessage *) _generateMessageWithBcc: (BOOL) withBcc - (NGMimeMessage *) _generateMessageWithBcc: (BOOL) withBcc
{ {
NSString *contentType; NSString *contentType;
NGMimeMessage *message; NGMimeMessage *message;
NGMutableHashMap *headers; NGMutableHashMap *headers;
id messageBody; id messageBody;
@ -1048,6 +1053,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
- (int) submitWithFlags: (enum SubmitFlags) flags - (int) submitWithFlags: (enum SubmitFlags) flags
{ {
enum mapistore_error rc = MAPISTORE_SUCCESS;
NSDictionary *recipients; NSDictionary *recipients;
NSData *messageData; NSData *messageData;
NSMutableArray *recipientEmails; NSMutableArray *recipientEmails;
@ -1094,7 +1100,10 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
withAuthenticator: authenticator withAuthenticator: authenticator
inContext: woContext]; inContext: woContext];
if (error) if (error)
[self logWithFormat: @"an error occurred: '%@'", error]; {
[self errorWithFormat: @"an error occurred: '%@'", error];
rc = MAPISTORE_ERR_MSG_SEND;
}
// mapping = [self mapping]; // mapping = [self mapping];
// [mapping unregisterURLWithID: [self objectId]]; // [mapping unregisterURLWithID: [self objectId]];
@ -1106,7 +1115,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
[self logWithFormat: @"skipping submit of message with class '%@'", [self logWithFormat: @"skipping submit of message with class '%@'",
msgClass]; msgClass];
return MAPISTORE_SUCCESS; return rc;
} }
- (void) save: (TALLOC_CTX *) memCtx - (void) save: (TALLOC_CTX *) memCtx

View File

@ -103,7 +103,7 @@
else else
{ {
connInfo = [(MAPIStoreContext *) [container context] connectionInfo]; connInfo = [(MAPIStoreContext *) [container context] connectionInfo];
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, userId); entryId = MAPIStoreInternalEntryId (connInfo, userId);
} }
*data = [entryId asBinaryInMemCtx: memCtx]; *data = [entryId asBinaryInMemCtx: memCtx];

View File

@ -25,12 +25,9 @@
#include <talloc.h> #include <talloc.h>
#import <Foundation/NSTimeZone.h>
#import <NGCards/iCalCalendar.h> #import <NGCards/iCalCalendar.h>
#import <NGCards/iCalRecurrenceRule.h> #import <NGCards/iCalRecurrenceRule.h>
#import <NGCards/iCalTimeZone.h>
@class NSTimeZone;
@class iCalEvent; @class iCalEvent;
@class iCalRepeatableEntityObject; @class iCalRepeatableEntityObject;
@ -46,7 +43,7 @@
fromRecurrencePattern: (struct RecurrencePattern *) rp fromRecurrencePattern: (struct RecurrencePattern *) rp
withExceptions: (struct ExceptionInfo *) exInfos withExceptions: (struct ExceptionInfo *) exInfos
andExceptionCount: (uint16_t) exInfoCount andExceptionCount: (uint16_t) exInfoCount
inTimeZone: (NSTimeZone *) tz; inTimeZone: (iCalTimeZone *) tz;
@end @end
@ -54,7 +51,6 @@
- (void) fillRecurrencePattern: (struct RecurrencePattern *) rp - (void) fillRecurrencePattern: (struct RecurrencePattern *) rp
withEvent: (iCalEvent *) event withEvent: (iCalEvent *) event
inTimeZone: (NSTimeZone *) timeZone
inMemCtx: (TALLOC_CTX *) memCtx; inMemCtx: (TALLOC_CTX *) memCtx;
@end @end

View File

@ -24,7 +24,6 @@
#import <Foundation/NSCalendarDate.h> #import <Foundation/NSCalendarDate.h>
#import <Foundation/NSSet.h> #import <Foundation/NSSet.h>
#import <Foundation/NSString.h> #import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSCalendarDate+misc.h> #import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NSObject+Logs.h> #import <NGExtensions/NSObject+Logs.h>
@ -35,6 +34,7 @@
#import <NGCards/iCalRepeatableEntityObject.h> #import <NGCards/iCalRepeatableEntityObject.h>
#import <NGCards/iCalRecurrenceRule.h> #import <NGCards/iCalRecurrenceRule.h>
#import <NGCards/iCalTimeZone.h> #import <NGCards/iCalTimeZone.h>
#import <NGCards/iCalTimeZonePeriod.h>
#import "NSDate+MAPIStore.h" #import "NSDate+MAPIStore.h"
#import "MAPIStoreRecurrenceUtils.h" #import "MAPIStoreRecurrenceUtils.h"
@ -51,7 +51,7 @@
fromRecurrencePattern: (struct RecurrencePattern *) rp fromRecurrencePattern: (struct RecurrencePattern *) rp
withExceptions: (struct ExceptionInfo *) exInfos withExceptions: (struct ExceptionInfo *) exInfos
andExceptionCount: (uint16_t) exInfoCount andExceptionCount: (uint16_t) exInfoCount
inTimeZone: (NSTimeZone *) tz inTimeZone: (iCalTimeZone *) tz
{ {
NSCalendarDate *startDate, *olEndDate, *untilDate, *exDate; NSCalendarDate *startDate, *olEndDate, *untilDate, *exDate;
@ -63,7 +63,7 @@
iCalWeekOccurrence weekOccurrence; iCalWeekOccurrence weekOccurrence;
iCalWeekOccurrences dayMaskDays; iCalWeekOccurrences dayMaskDays;
NSUInteger count, max; NSUInteger count, max;
NSInteger bySetPos; NSInteger bySetPos, tzOffset;
unsigned char maskValue; unsigned char maskValue;
[entity removeAllRecurrenceRules]; [entity removeAllRecurrenceRules];
@ -242,9 +242,10 @@
{ {
/* The OriginalStartDate is in local time */ /* The OriginalStartDate is in local time */
exDate = [NSDate dateFromMinutesSince1601: exInfos[count].OriginalStartDate]; exDate = [NSDate dateFromMinutesSince1601: exInfos[count].OriginalStartDate];
tzOffset = -[[tz periodForDate: exDate] secondsOffsetFromGMT];
exDate = [exDate dateByAddingYears: 0 months: 0 days: 0 exDate = [exDate dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0 hours: 0 minutes: 0
seconds: - [tz secondsFromGMT]]; seconds: tzOffset];
[exceptionDates removeObject: exDate]; [exceptionDates removeObject: exDate];
} }
} }
@ -263,7 +264,6 @@
- (void) fillRecurrencePattern: (struct RecurrencePattern *) rp - (void) fillRecurrencePattern: (struct RecurrencePattern *) rp
withEvent: (iCalEvent *) event withEvent: (iCalEvent *) event
inTimeZone: (NSTimeZone *) timeZone
inMemCtx: (TALLOC_CTX *) memCtx inMemCtx: (TALLOC_CTX *) memCtx
{ {
iCalRecurrenceFrequency freq; iCalRecurrenceFrequency freq;
@ -279,10 +279,8 @@
NSMutableArray *deletedDates, *modifiedDates; NSMutableArray *deletedDates, *modifiedDates;
startDate = [event firstRecurrenceStartDate]; startDate = [event firstRecurrenceStartDate];
[startDate setTimeZone: timeZone];
endDate = [event lastPossibleRecurrenceStartDate]; endDate = [event lastPossibleRecurrenceStartDate];
[endDate setTimeZone: timeZone];
rp->ReaderVersion = 0x3004; rp->ReaderVersion = 0x3004;
rp->WriterVersion = 0x3004; rp->WriterVersion = 0x3004;

View File

@ -197,6 +197,7 @@ static Class MAPIStoreFolderK;
inMemCtx: (TALLOC_CTX *) memCtx inMemCtx: (TALLOC_CTX *) memCtx
{ {
int rc; int rc;
struct mapistore_connection_info *connInfo;
uint64_t obVersion; uint64_t obVersion;
obVersion = [self objectVersion]; obVersion = [self objectVersion];
@ -204,8 +205,9 @@ static Class MAPIStoreFolderK;
rc = MAPISTORE_ERR_NOT_FOUND; rc = MAPISTORE_ERR_NOT_FOUND;
else else
{ {
connInfo = [[self context] connectionInfo];
*data = MAPILongLongValue (memCtx, ((obVersion << 16) *data = MAPILongLongValue (memCtx, ((obVersion << 16)
| 0x0001)); | connInfo->repl_id));
rc = MAPISTORE_SUCCESS; rc = MAPISTORE_SUCCESS;
} }

View File

@ -25,13 +25,13 @@
@class NSString; @class NSString;
struct ldb_context; #include <mapistore/mapistore.h>
NSString *MAPIStoreSamDBUserAttribute (struct ldb_context *samCtx, NSString *MAPIStoreSamDBUserAttribute (struct mapistore_connection_info *connInfo,
NSString *userKey, NSString *userKey,
NSString *value, NSString *value,
NSString *attributeName); NSString *attributeName);
NSData *MAPIStoreInternalEntryId (struct ldb_context *, NSString *username); NSData *MAPIStoreInternalEntryId (struct mapistore_connection_info *connInfo, NSString *username);
NSData *MAPIStoreExternalEntryId (NSString *cn, NSString *email); NSData *MAPIStoreExternalEntryId (NSString *cn, NSString *email);
#endif /* MAPISTORESAMDBUTILS_H */ #endif /* MAPISTORESAMDBUTILS_H */

View File

@ -24,13 +24,18 @@
#import <Foundation/NSString.h> #import <Foundation/NSString.h>
#include <talloc.h> #include <talloc.h>
#include <ldb.h> #include <ldb.h>
#include <libmapiproxy.h>
#include <samba/version.h>
#import "NSData+MAPIStore.h" #import "NSData+MAPIStore.h"
#import "MAPIStoreSamDBUtils.h" #import "MAPIStoreSamDBUtils.h"
NSString * NSString *
MAPIStoreSamDBUserAttribute (struct ldb_context *samCtx, MAPIStoreSamDBUserAttribute (struct mapistore_connection_info *connInfo,
NSString *userKey, NSString *userKey,
NSString *value, NSString *value,
NSString *attributeName) NSString *attributeName)
@ -48,10 +53,20 @@ MAPIStoreSamDBUserAttribute (struct ldb_context *samCtx,
attrs[0] = [attributeName UTF8String]; attrs[0] = [attributeName UTF8String];
searchFormat searchFormat
= [NSString stringWithFormat: @"(&(objectClass=user)(%@=%%s))", userKey]; = [NSString stringWithFormat: @"(&(objectClass=user)(%@=%%s))", userKey];
ret = ldb_search (samCtx, memCtx, &res, ldb_get_default_basedn(samCtx), #if SAMBA_VERSION_MAJOR <= 4 && SAMBA_VERSION_MINOR < 3
ret = ldb_search (connInfo->sam_ctx, memCtx, &res,
ldb_get_default_basedn(connInfo->sam_ctx),
LDB_SCOPE_SUBTREE, attrs, LDB_SCOPE_SUBTREE, attrs,
[searchFormat UTF8String], [searchFormat UTF8String],
[value UTF8String]); [value UTF8String]);
#else
ret = safe_ldb_search (&connInfo->sam_ctx, memCtx, &res,
ldb_get_default_basedn(connInfo->sam_ctx),
LDB_SCOPE_SUBTREE, attrs,
[searchFormat UTF8String],
[value UTF8String]);
#endif
if (ret == LDB_SUCCESS && res->count == 1) if (ret == LDB_SUCCESS && res->count == 1)
{ {
result = ldb_msg_find_attr_as_string (res->msgs[0], attrs[0], NULL); result = ldb_msg_find_attr_as_string (res->msgs[0], attrs[0], NULL);
@ -65,7 +80,7 @@ MAPIStoreSamDBUserAttribute (struct ldb_context *samCtx,
} }
NSData * NSData *
MAPIStoreInternalEntryId (struct ldb_context *samCtx, NSString *username) MAPIStoreInternalEntryId (struct mapistore_connection_info *connInfo, NSString *username)
{ {
static const uint8_t const providerUid[] = { 0xdc, 0xa7, 0x40, 0xc8, static const uint8_t const providerUid[] = { 0xdc, 0xa7, 0x40, 0xc8,
0xc0, 0x42, 0x10, 0x1a, 0xc0, 0x42, 0x10, 0x1a,
@ -82,7 +97,7 @@ MAPIStoreInternalEntryId (struct ldb_context *samCtx, NSString *username)
type: 32 type: 32
X500DN: variable */ X500DN: variable */
legacyDN = MAPIStoreSamDBUserAttribute (samCtx, @"sAMAccountName", username, legacyDN = MAPIStoreSamDBUserAttribute (connInfo, @"sAMAccountName", username,
@"legacyExchangeDN"); @"legacyExchangeDN");
if (legacyDN) if (legacyDN)
{ {

View File

@ -107,11 +107,11 @@
if ([roles containsObject: SOGoRole_ObjectCreator]) if ([roles containsObject: SOGoRole_ObjectCreator])
rights |= RightsCreateItems; rights |= RightsCreateItems;
if ([roles containsObject: SOGoRole_ObjectEraser]) if ([roles containsObject: SOGoRole_ObjectEraser])
rights |= RightsDeleteAll; rights |= RightsDeleteAll | RightsDeleteOwn;
if ([roles containsObject: SOGoCalendarRole_PublicModifier] if ([roles containsObject: SOGoCalendarRole_PublicModifier]
&& [roles containsObject: SOGoCalendarRole_PrivateModifier] && [roles containsObject: SOGoCalendarRole_PrivateModifier]
&& [roles containsObject: SOGoCalendarRole_ConfidentialModifier]) && [roles containsObject: SOGoCalendarRole_ConfidentialModifier])
rights |= RightsReadItems | RightsEditAll; rights |= RightsReadItems | RightsEditAll | RightsEditOwn;
else if ([roles containsObject: SOGoCalendarRole_PublicViewer] else if ([roles containsObject: SOGoCalendarRole_PublicViewer]
&& [roles containsObject: SOGoCalendarRole_PrivateViewer] && [roles containsObject: SOGoCalendarRole_PrivateViewer]
&& [roles containsObject: SOGoCalendarRole_ConfidentialViewer]) && [roles containsObject: SOGoCalendarRole_ConfidentialViewer])

View File

@ -198,7 +198,7 @@ NSObjectFromSPropValue (const struct SPropValue *value)
break; break;
case PT_STRING8: case PT_STRING8:
result = (value->value.lpszA result = (value->value.lpszA
? [NSString stringWithUTF8String: value->value.lpszA] ? [NSString stringWithUTF8String: (const char *) value->value.lpszA]
: (id) @""); : (id) @"");
break; break;
case PT_SYSTIME: case PT_SYSTIME:

View File

@ -73,6 +73,8 @@ static NSMapTable *contextsTable = nil;
[userContext autorelease]; [userContext autorelease];
[contextsTable setObject: userContext forKey: username]; [contextsTable setObject: userContext forKey: username];
} }
else
[userContext activate];
return userContext; return userContext;
} }

View File

@ -228,7 +228,7 @@
mvResult = [NSMutableArray arrayWithCapacity: mvString->cValues]; mvResult = [NSMutableArray arrayWithCapacity: mvString->cValues];
for (count = 0; count < mvString->cValues; count++) for (count = 0; count < mvString->cValues; count++)
{ {
subObject = [NSString stringWithUTF8String: mvString->lppszA[count]]; subObject = [NSString stringWithUTF8String: (const char *) mvString->lppszA[count]];
[mvResult addObject: subObject]; [mvResult addObject: subObject];
} }

View File

@ -37,6 +37,8 @@
- (BOOL) isNever; /* occurs on 4500-12-31 */ - (BOOL) isNever; /* occurs on 4500-12-31 */
+ (NSCalendarDate *) dateFromSystemTime: (struct SYSTEMTIME) date
andRuleYear: (uint16_t) rYear;
@end @end
NSComparisonResult NSDateCompare (id date1, id date2, void *); NSComparisonResult NSDateCompare (id date1, id date2, void *);

View File

@ -24,6 +24,7 @@
#import <Foundation/NSString.h> #import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h> #import <Foundation/NSTimeZone.h>
#import "MAPIStoreTypes.h"
#import "NSDate+MAPIStore.h" #import "NSDate+MAPIStore.h"
#undef DEBUG #undef DEBUG
@ -48,7 +49,7 @@ _setupRefDate ()
refDate = [[NSCalendarDate alloc] refDate = [[NSCalendarDate alloc]
initWithYear: 1601 month: 1 day: 1 initWithYear: 1601 month: 1 day: 1
hour: 0 minute: 0 second: 0 hour: 0 minute: 0 second: 0
timeZone: [NSTimeZone timeZoneWithName: @"UTC"]]; timeZone: utcTZ];
} }
+ (NSCalendarDate *) dateFromMinutesSince1601: (uint32_t) minutes + (NSCalendarDate *) dateFromMinutesSince1601: (uint32_t) minutes
@ -128,6 +129,64 @@ _setupRefDate ()
return [calDate yearOfCommonEra] == 4500; return [calDate yearOfCommonEra] == 4500;
} }
+ (NSCalendarDate *) dateFromSystemTime: (struct SYSTEMTIME) date
andRuleYear: (uint16_t) rYear
{
NSCalendarDate *result;
NSInteger daysToDate;
NSUInteger firstDayOfWeek, year;
/* ([MS-OXOCAL] 2.2.1.41.1) When we're provided an absolute date (i.e., it
happens once), the SYSTEMTIME structure is enough to fill the date.
When we're parsing a SYSTEMTIME field from a time zone rule, however, a
relative date can be provided for the peroidicity of its periods. In this
scenario, the wYear field is empty and we have to use the wYear field in
the parent rule */
if (date.wYear != 0)
year = date.wYear;
else
year = rYear;
/* The wDay field indicates the occurrence of the wDayOfWeek within the month.
The 5th occurrence means the last one, even if it is the 4th. */
if (date.wDay < 5)
{
result = [[NSCalendarDate alloc] initWithYear: year month: date.wMonth day: 1
hour: date.wHour minute: date.wMinute second: date.wSecond
timeZone: utcTZ];
[result autorelease];
firstDayOfWeek = [result dayOfWeek];
daysToDate = 7 * (date.wDay - 1) + date.wDayOfWeek - firstDayOfWeek;
if (date.wDayOfWeek < firstDayOfWeek)
daysToDate += 7;
result = [result dateByAddingYears: 0 months: 0 days: daysToDate
hours: 0 minutes: 0
seconds: 0];
}
else
{
result = [[NSCalendarDate alloc] initWithYear: year month: date.wMonth + 1 day: 1
hour: date.wHour minute: date.wMinute second: date.wSecond
timeZone: utcTZ];
[result autorelease];
firstDayOfWeek = [result dayOfWeek];
daysToDate = date.wDayOfWeek - firstDayOfWeek;
if (date.wDayOfWeek >= firstDayOfWeek)
daysToDate -= 7;
result = [result dateByAddingYears: 0 months: 0 days: daysToDate
hours: 0 minutes: 0
seconds: 0];
}
return result;
}
@end @end
NSComparisonResult NSComparisonResult

View File

@ -67,6 +67,7 @@
int font_index; int font_index;
int color_index; int color_index;
int start_pos; int start_pos;
const unsigned short *charset;
} }
@end @end
@ -77,7 +78,7 @@
{ {
@public @public
NSString *family; NSString *family;
NSString *charset; unsigned char charset;
NSString *name; NSString *name;
unsigned int pitch; unsigned int pitch;
unsigned int index; unsigned int index;

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
/* dbmsgreader.m - this file is part of SOGo /* dbmsgreader.m - this file is part of SOGo
* *
* Copyright (C) 2011-2012 Inverse inc * Copyright (C) 2011-2012 Inverse inc
* 2015 Enrique J. Hernandez
* *
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* *
* This file is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -33,21 +33,58 @@
#import <SOGo/SOGoProductLoader.h> #import <SOGo/SOGoProductLoader.h>
#import <SOGo/SOGoSystemDefaults.h> #import <SOGo/SOGoSystemDefaults.h>
#import <libmapi/libmapi.h>
#import "MAPIStoreUserContext.h" #import "MAPIStoreUserContext.h"
#import <SOGo/SOGoCacheGCSObject.h> #import <SOGo/SOGoCacheGCSObject.h>
#import <SOGo/BSONCodec.h> #import <SOGo/BSONCodec.h>
#import "NSObject+PropertyList.h" #import "NSObject+PropertyList.h"
Class MAPIStoreUserContextK, SOGoCacheGCSObjectK;
Class MAPIStoreUserContextK, SOGoCacheGCSObjectK, NSStringK;
static void static void
DumpBSONData(NSData *data) DumpBSONData(NSData *data)
{ {
id key, value;
NSEnumerator *dictEnum;
NSDictionary *dvalue; NSDictionary *dvalue;
NSMutableString *outStr;
NSUInteger max;
dvalue = [data BSONValue]; dvalue = [data BSONValue];
[dvalue displayWithIndentation:0]; max = [dvalue count];
printf("\n"); dictEnum = [dvalue keyEnumerator];
NSStringK = [NSString class];
outStr = [NSMutableString stringWithFormat: @"{ %d items\n", max];
while ((key = [dictEnum nextObject]))
{
uint32_t proptag = 0;
if ([key isKindOfClass: NSStringK] && [(NSString *)key intValue] > 0)
proptag = [(NSString *)key intValue];
if (proptag > 0)
{
const char *propTagName = get_proptag_name (proptag);
NSString *propName;
if (propTagName)
propName = [NSString stringWithCString: propTagName
encoding: NSUTF8StringEncoding];
else
propName = [NSString stringWithFormat: @"0x%.4x", [key unsignedLongValue]];
[outStr appendFormat: @" %@ = ", propName];
}
else
[outStr appendFormat: @" %@ = ", key];
value = [dvalue objectForKey: key];
[outStr appendFormat: @"(%@) %@,\n", NSStringFromClass ([value class]), value];
}
[outStr appendFormat: @"}\n"];
printf ("%s\n", [outStr UTF8String]);
} }
static void static void
@ -67,7 +104,7 @@ DbDumpObject (NSString *username, NSString *path)
{ {
printf("record found: %p\n", record); printf("record found: %p\n", record);
content = [[record objectForKey: @"c_content"] dataByDecodingBase64]; content = [[record objectForKey: @"c_content"] dataByDecodingBase64];
DumpBSONData(content); DumpBSONData (content);
} }
else else
NSLog (@"record not found"); NSLog (@"record not found");

View File

@ -36,6 +36,7 @@
#import <NGCards/iCalDateTime.h> #import <NGCards/iCalDateTime.h>
#import <NGCards/iCalPerson.h> #import <NGCards/iCalPerson.h>
#import <NGCards/iCalTimeZone.h> #import <NGCards/iCalTimeZone.h>
#import <NGCards/iCalTimeZonePeriod.h>
#import <NGCards/iCalTrigger.h> #import <NGCards/iCalTrigger.h>
#import <SOGo/SOGoPermissions.h> #import <SOGo/SOGoPermissions.h>
#import <SOGo/SOGoUser.h> #import <SOGo/SOGoUser.h>
@ -70,11 +71,12 @@
#include <mapistore/mapistore_nameid.h> #include <mapistore/mapistore_nameid.h>
#import "iCalEvent+MAPIStore.h" #import "iCalEvent+MAPIStore.h"
#import "iCalTimeZone+MAPIStore.h"
@implementation iCalEvent (MAPIStoreProperties) @implementation iCalEvent (MAPIStoreProperties)
- (void) _setupEventRecurrence: (NSData *) mapiRecurrenceData - (void) _setupEventRecurrence: (NSData *) mapiRecurrenceData
inTimeZone: (NSTimeZone *) tz inTimeZone: (iCalTimeZone *) tz
inMemCtx: (TALLOC_CTX *) memCtx inMemCtx: (TALLOC_CTX *) memCtx
{ {
struct Binary_r *blob; struct Binary_r *blob;
@ -250,10 +252,8 @@
BOOL isAllDay; BOOL isAllDay;
iCalDateTime *start, *end; iCalDateTime *start, *end;
iCalTimeZone *tz; iCalTimeZone *tz;
NSTimeZone *userTimeZone; NSString *priority, *class = nil, *tzDescription = nil;
NSString *priority, *class = nil;
NSUInteger responseStatus = 0; NSUInteger responseStatus = 0;
NSInteger tzOffset;
SOGoUser *ownerUser; SOGoUser *ownerUser;
id value; id value;
@ -274,7 +274,31 @@
[self setAccessClass: @"PUBLIC"]; [self setAccessClass: @"PUBLIC"];
} }
userTimeZone = [userContext timeZone]; /* Time zone = PidLidAppointmentTimeZoneDefinitionRecur
or PidLidAppointmentTimeZoneDefinition[Start|End]Display */
value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentTimeZoneDefinitionStartDisplay)];
if (!value)
{
value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentTimeZoneDefinitionEndDisplay)];
if (!value)
{
/* If PidLidtimeZoneStruct, TZID SHOULD come from PidLidTimeZoneDescription,
if PidLidAppointmentTimeZoneDefinition[Start|End]Display it MUST be derived from KeyName
(MS-OXCICAL] 2.1.3.1.1.19.1) */
value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentTimeZoneDefinitionRecur)];
tzDescription = [properties objectForKey: MAPIPropertyKey (PidLidTimeZoneDescription)];
}
}
if (value)
{
tz = [[iCalTimeZone alloc] iCalTimeZoneFromDefinition: value
withDescription: tzDescription
inMemCtx: memCtx];
}
else
/* The client is more likely to have the webmail's time zone than any other */
tz = [iCalTimeZone timeZoneForName: [[userContext timeZone] name]];
[(iCalCalendar *) parent addTimeZone: tz];
/* CREATED */ /* CREATED */
value = [properties objectForKey: MAPIPropertyKey (PidTagCreationTime)]; value = [properties objectForKey: MAPIPropertyKey (PidTagCreationTime)];
@ -306,20 +330,13 @@
objectForKey: MAPIPropertyKey (PidLidAppointmentSubType)]; objectForKey: MAPIPropertyKey (PidLidAppointmentSubType)];
if (value) if (value)
isAllDay = [value boolValue]; isAllDay = [value boolValue];
if (!isAllDay)
{
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
[(iCalCalendar *) parent addTimeZone: tz];
}
else
tz = nil;
// recurrence-id // recurrence-id
value value
= [properties objectForKey: MAPIPropertyKey (PidLidExceptionReplaceTime)]; = [properties objectForKey: MAPIPropertyKey (PidLidExceptionReplaceTime)];
if (value) if (value)
[self setRecurrenceId: value]; [self setRecurrenceId: value];
// start // start
value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentStartWhole)]; value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentStartWhole)];
if (!value) if (!value)
@ -330,15 +347,7 @@
[start setTimeZone: tz]; [start setTimeZone: tz];
if (isAllDay) if (isAllDay)
{ {
/* when user TZ is positive (East) all-day events were not /* All-day events are set in floating time ([MS-OXCICAL] 2.1.3.1.1.20.8) */
shown properly in SOGo UI. This day delay fixes it */
tzOffset = [userTimeZone secondsFromGMTForDate: value];
if (tzOffset > 0)
{
value = [value dateByAddingYears: 0 months: 0 days: 1
hours: 0 minutes: 0
seconds: 0];
}
[start setDate: value]; [start setDate: value];
[start setTimeZone: nil]; [start setTimeZone: nil];
} }
@ -356,15 +365,7 @@
[end setTimeZone: tz]; [end setTimeZone: tz];
if (isAllDay) if (isAllDay)
{ {
/* when user TZ is positive (East) all-day events were not /* All-day events are set in floating time ([MS-OXCICAL] 2.1.3.1.1.20.8) */
shown properly in SOGo UI. This day delay fixes it */
tzOffset = [userTimeZone secondsFromGMTForDate: value];
if (tzOffset > 0)
{
value = [value dateByAddingYears: 0 months: 0 days: 1
hours: 0 minutes: 0
seconds: 0];
}
[end setDate: value]; [end setDate: value];
[end setTimeZone: nil]; [end setTimeZone: nil];
} }
@ -467,7 +468,7 @@
value = [properties value = [properties
objectForKey: MAPIPropertyKey (PidLidAppointmentRecur)]; objectForKey: MAPIPropertyKey (PidLidAppointmentRecur)];
if (value) if (value)
[self _setupEventRecurrence: value inTimeZone: userTimeZone inMemCtx: memCtx]; [self _setupEventRecurrence: value inTimeZone: tz inMemCtx: memCtx];
/* alarm */ /* alarm */
[self _setupEventAlarmFromProperties: properties]; [self _setupEventAlarmFromProperties: properties];

View File

@ -30,6 +30,11 @@
- (struct Binary_r *) asTimeZoneStructInMemCtx: (TALLOC_CTX *) memCtx; - (struct Binary_r *) asTimeZoneStructInMemCtx: (TALLOC_CTX *) memCtx;
- (struct Binary_r *) asZoneTimeDefinitionWithFlags: (enum TZRuleFlag) flags - (struct Binary_r *) asZoneTimeDefinitionWithFlags: (enum TZRuleFlag) flags
inMemCtx: (TALLOC_CTX *) memCtx; inMemCtx: (TALLOC_CTX *) memCtx;
- (iCalTimeZone *) iCalTimeZoneFromDefinition: (NSData *) value
withDescription: (NSString *) description
inMemCtx: (TALLOC_CTX *) memCtx;
- (NSCalendarDate *) shiftedCalendarDateForDate: (NSCalendarDate *) date;
@end @end

View File

@ -23,11 +23,15 @@
#import <Foundation/NSArray.h> #import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h> #import <Foundation/NSCalendarDate.h>
#import <Foundation/NSString.h> #import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGCards/iCalByDayMask.h> #import <NGCards/iCalByDayMask.h>
#import <NGCards/iCalDateTime.h>
#import <NGCards/iCalTimeZonePeriod.h> #import <NGCards/iCalTimeZonePeriod.h>
#import <NGCards/iCalRecurrenceRule.h> #import <NGCards/iCalRecurrenceRule.h>
#import "NSString+MAPIStore.h" #import "NSString+MAPIStore.h"
#import "NSData+MAPIStore.h"
#import "NSDate+MAPIStore.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -36,6 +40,7 @@
#include <libmapi/libmapi.h> #include <libmapi/libmapi.h>
#import "iCalTimeZone+MAPIStore.h" #import "iCalTimeZone+MAPIStore.h"
#import "MAPIStoreTypes.h"
@interface iCalTimeZonePeriod (MAPIStorePropertiesPrivate) @interface iCalTimeZonePeriod (MAPIStorePropertiesPrivate)
@ -103,18 +108,18 @@
{ {
iCalTimeZonePeriod *period; iCalTimeZonePeriod *period;
struct TimeZoneStruct tz; struct TimeZoneStruct tz;
int lBias, dlBias; int32_t lBias, dlBias;
memset (&tz, 0, sizeof (struct TimeZoneStruct)); memset (&tz, 0, sizeof (struct TimeZoneStruct));
period = [self _mostRecentPeriodWithName: @"STANDARD"]; period = [self _mostRecentPeriodWithName: @"STANDARD"];
lBias = -[period secondsOffsetFromGMT] / 60; lBias = -[period secondsOffsetFromGMT] / 60;
tz.lBias = (uint32_t) lBias; tz.lBias = lBias;
[period _fillTZDate: &tz.stStandardDate]; [period _fillTZDate: &tz.stStandardDate];
period = [self _mostRecentPeriodWithName: @"DAYLIGHT"]; period = [self _mostRecentPeriodWithName: @"DAYLIGHT"];
if (!period) if (!period)
tz.stStandardDate.wMonth = 0; tz.stStandardDate.wMonth = 0;
dlBias = -([period secondsOffsetFromGMT] / 60) - lBias; dlBias = -([period secondsOffsetFromGMT] / 60) - lBias;
tz.lDaylightBias = (uint32_t) (dlBias); tz.lDaylightBias = dlBias;
[period _fillTZDate: &tz.stDaylightDate]; [period _fillTZDate: &tz.stDaylightDate];
tz.wStandardYear = tz.stStandardDate.wYear; tz.wStandardYear = tz.stStandardDate.wYear;
tz.wDaylightYear = tz.stDaylightDate.wYear; tz.wDaylightYear = tz.stDaylightDate.wYear;
@ -153,18 +158,220 @@
period = [self _mostRecentPeriodWithName: @"STANDARD"]; period = [self _mostRecentPeriodWithName: @"STANDARD"];
rule.wYear = [[period startDate] yearOfCommonEra]; rule.wYear = [[period startDate] yearOfCommonEra];
lBias = -[period secondsOffsetFromGMT] / 60; lBias = -[period secondsOffsetFromGMT] / 60;
rule.lBias = (uint32_t) lBias; rule.lBias = lBias;
[period _fillTZDate: &rule.stStandardDate]; [period _fillTZDate: &rule.stStandardDate];
period = [self _mostRecentPeriodWithName: @"DAYLIGHT"]; period = [self _mostRecentPeriodWithName: @"DAYLIGHT"];
if (!period) if (!period)
rule.stStandardDate.wMonth = 0; rule.stStandardDate.wMonth = 0;
dlBias = -([period secondsOffsetFromGMT] / 60) - lBias; dlBias = -([period secondsOffsetFromGMT] / 60) - lBias;
rule.lDaylightBias = (uint32_t) (dlBias); rule.lDaylightBias = dlBias;
[period _fillTZDate: &rule.stDaylightDate]; [period _fillTZDate: &rule.stDaylightDate];
return set_TimeZoneDefinition (memCtx, &definition); return set_TimeZoneDefinition (memCtx, &definition);
} }
- (NSString *) _offsetStringFromOffset: (NSInteger) offset
{
NSInteger offsetHours, offsetMins;
NSString *offsetSign;
/* The offset format is, eg, "+0200" for 2 hours 0 minutes ahead */
if (offset < 0)
offsetSign = @"-";
else
offsetSign = @"+";
offsetHours = abs (offset) / 60;
offsetMins = abs (offset) % 60;
return [NSString stringWithFormat: @"%@%d%d%d%d",
offsetSign, offsetHours / 10, offsetHours % 10,
offsetMins / 10, offsetMins % 10];
}
- (NSString *) _rRuleStringFromSystemTime: (struct SYSTEMTIME) date
{
NSString *result, *byDay;
/* The conversion tables between the SYSTEMTIME fields and the RRULE ones
can be found at [MS-OXCICAL] 2.1.3.2.1 */
if (date.wDay == 5)
byDay = @"-1";
else
byDay = [NSString stringWithFormat: @"%d", date.wDay];
switch (date.wDayOfWeek)
{
case iCalWeekDaySunday:
byDay = [byDay stringByAppendingString: @"SU"];
break;
case iCalWeekDayMonday:
byDay = [byDay stringByAppendingString: @"MO"];
break;
case iCalWeekDayTuesday:
byDay = [byDay stringByAppendingString: @"TU"];
break;
case iCalWeekDayWednesday:
byDay = [byDay stringByAppendingString: @"WE"];
break;
case iCalWeekDayThursday:
byDay = [byDay stringByAppendingString: @"TH"];
break;
case iCalWeekDayFriday:
byDay = [byDay stringByAppendingString: @"FR"];
break;
case iCalWeekDaySaturday:
byDay = [byDay stringByAppendingString: @"SA"];
break;
}
result = [NSString stringWithFormat: @"FREQ=YEARLY;BYDAY=%@;BYMONTH=%d", byDay, date.wMonth];
return result;
}
- (iCalTimeZone *) iCalTimeZoneFromDefinition: (NSData *) value
withDescription: (NSString *) description
inMemCtx: (TALLOC_CTX *) memCtx
{
BOOL daylightDefined = NO, ruleFound = NO;
iCalDateTime *daylightStart, *standardStart;
iCalRecurrenceRule *daylightRRule, *standardRRule;
iCalTimeZone *tz = nil;
iCalTimeZonePeriod *daylight, *standard;
NSCalendarDate *dlStartValue, *stStartValue;
NSString *strOffsetFrom, *strOffsetTo, *tzID;
char *keyName;
struct Binary_r *binValue;
struct SYSTEMTIME initDate;
struct TimeZoneDefinition *definition;
struct TZRule rule;
uint16_t count;
binValue = [value asBinaryInMemCtx: memCtx];
definition = get_TimeZoneDefinition (memCtx, binValue);
if (!definition)
return nil;
if (!definition->cRules)
goto end;
for (count = 0; count < definition->cRules; count++)
{
/* ([MS-OXCICAL] 2.1.3.1.1.19) The TZRule with the
TZRULE_FLAG_EFFECTIVE_TZREG bit set in the TZRule flags field
is the one that MUST be exported */
if (definition->TZRules[count].flags & TZRULE_FLAG_EFFECTIVE_TZREG)
{
rule = definition->TZRules[count];
ruleFound = YES;
break;
}
}
if (!ruleFound)
goto end;
if (!description)
{
/* The cbHeader field contains the size, in bytes of the Reserved (2b),
cchKeyName (2b) keyName (variable Unicode string) and cRules (2b)
([MS-OXOCAL] 2.2.1.41). The keyName field is a non-NULL-terminated
char array. */
keyName = talloc_strndup (memCtx, definition->keyName, (definition->cbHeader - 6) / 2);
tzID = [NSString stringWithCString: keyName
encoding: [NSString defaultCStringEncoding]];
talloc_free (keyName);
}
else
tzID = [NSString stringWithString: description];
tz = [iCalTimeZone groupWithTag: @"vtimezone"];
[tz addChild: [CardElement simpleElementWithTag: @"tzid"
value: tzID]];
if (rule.stStandardDate.wMonth != 0)
daylightDefined = YES;
/* STANDARD TIME ([MS-OXCICAL] 2.1.3.1.1.19.2) */
standard = [iCalTimeZonePeriod groupWithTag: @"standard"];
/* TZOFFSETFROM = -1 * (PidLidTimeZoneStruct.lBias + PidLidTimeZoneStruct.lDaylightBias) */
strOffsetFrom = [self _offsetStringFromOffset: -1 * (rule.lBias + rule.lDaylightBias)];
[standard addChild: [CardElement simpleElementWithTag: @"tzoffsetfrom"
value: strOffsetFrom]];
/* TZOFFSETTO = -1 * (PidLidTimeZoneStruct.lBias + PidLidTimeZoneStruct.lStandardBias) */
strOffsetTo = [self _offsetStringFromOffset: -1 * (rule.lBias + rule.lStandardBias)];
[standard addChild: [CardElement simpleElementWithTag: @"tzoffsetto"
value: strOffsetTo]];
/* DTSTART & RRULE are derived from the stStandardDate and wYear properties */
standardStart = [iCalDateTime elementWithTag: @"dtstart"];
initDate = rule.stStandardDate;
stStartValue = [NSCalendarDate dateFromSystemTime: initDate
andRuleYear: rule.wYear];
[standardStart setDateTime: stStartValue];
[standard addChild: standardStart];
if (daylightDefined)
{
standardRRule = [[iCalRecurrenceRule alloc] initWithString: [self _rRuleStringFromSystemTime: initDate]];
[standard addChild: standardRRule];
/* DAYLIGHT SAVING TIME ([MS-OXCICAL] 2.1.3.1.1.19.3) */
daylight = [iCalTimeZonePeriod groupWithTag: @"daylight"];
/* TZOFFSETFROM = -1 * (PidLidTimeZoneStruct.lBias + PidLidTimeZoneStruct.lStandardBias) */
[daylight addChild: [CardElement simpleElementWithTag: @"tzoffsetfrom"
value: strOffsetTo]];
/* TZOFFSETTO = -1 * (PidLidTimeZoneStruct.lBias + PidLidTimeZoneStruct.lDaylightBias) */
[daylight addChild: [CardElement simpleElementWithTag: @"tzoffsetto"
value: strOffsetFrom]];
/* DTSTART & RRULE are derived from the stDaylightDate and wYear properties */
daylightStart = [iCalDateTime elementWithTag: @"dtstart"];
initDate = rule.stDaylightDate;
dlStartValue = [NSCalendarDate dateFromSystemTime: initDate
andRuleYear: rule.wYear];
[daylightStart setDateTime: dlStartValue];
[daylight addChild: daylightStart];
daylightRRule = [[iCalRecurrenceRule alloc] initWithString: [self _rRuleStringFromSystemTime: initDate]];
[daylight addChild: daylightRRule];
[tz addChild: daylight];
}
[tz addChild: standard];
end:
talloc_free (definition);
return tz;
}
/**
* Adjust a date in this vTimeZone to its representation in UTC
* Example: Timezone is +0001, the date is 2015-12-15 00:00:00 +0000
* it returns 2015-12-14 23:00:00 +0000
* @param date the date to adjust to the timezone.
* @return a new GMT date adjusted with the offset of the timezone.
*/
- (NSCalendarDate *) shiftedCalendarDateForDate: (NSCalendarDate *) date
{
NSCalendarDate *tmpDate;
tmpDate = [date copy];
[tmpDate autorelease];
[tmpDate setTimeZone: utcTZ];
return [tmpDate addYear: 0 month: 0 day: 0
hour: 0 minute: 0
second: -[[self periodForDate: tmpDate] secondsOffsetFromGMT]];
}
@end @end

View File

@ -609,8 +609,16 @@ static Class iCalEventK = nil;
NSNumber *classNumber; NSNumber *classNumber;
unsigned int grantedCount; unsigned int grantedCount;
iCalAccessClass currentClass; iCalAccessClass currentClass;
WOContext *localContext;
[self initializeQuickTablesAclsInContext: context]; /* FIXME: The stored context from initialisation may have changed
by setContext by other operations in OpenChange library,
so we keep tighly to use the current session one. Without
this, the login is set to nil and a NSException is raised
at [SOGoAppointmentFolder:roleForComponentsWithAccessClass:forUser]
inside [SOGoAppointmentFolder:initializeQuickTablesAclsInContext]. */
localContext = [[WOApplication application] context];
[self initializeQuickTablesAclsInContext: localContext];
grantedClasses = [NSMutableArray arrayWithCapacity: 3]; grantedClasses = [NSMutableArray arrayWithCapacity: 3];
deniedClasses = [NSMutableArray arrayWithCapacity: 3]; deniedClasses = [NSMutableArray arrayWithCapacity: 3];
for (currentClass = 0; for (currentClass = 0;

View File

@ -166,9 +166,10 @@
ldifEntry = [childRecords objectForKey: objectName]; ldifEntry = [childRecords objectForKey: objectName];
if (!ldifEntry) if (!ldifEntry)
{ {
ldifEntry = [source lookupContactEntry: objectName]; ldifEntry = [source lookupContactEntry: objectName
if (ldifEntry) inDomain: [[context activeUser] domain]];
[childRecords setObject: ldifEntry forKey: objectName]; if (ldifEntry)
[childRecords setObject: ldifEntry forKey: objectName];
else if ([self isValidContentName: objectName]) else if ([self isValidContentName: objectName])
{ {
url = [[[lookupContext request] uri] urlWithoutParameters]; url = [[[lookupContext request] uri] urlWithoutParameters];
@ -373,10 +374,14 @@
NSDictionary *record; NSDictionary *record;
if (aName && [aName length] > 0) if (aName && [aName length] > 0)
record = [self _flattenedRecord: [source lookupContactEntry: aName]]; {
record = [source lookupContactEntry: aName
inDomain: [[context activeUser] domain]];
record = [self _flattenedRecord: record];
}
else else
record = nil; record = nil;
return record; return record;
} }
@ -611,7 +616,7 @@
toResponse: (WOResponse *) response toResponse: (WOResponse *) response
{ {
NSObject <DOMElement> *element; NSObject <DOMElement> *element;
NSString *url, *baseURL, *cname; NSString *url, *baseURL, *cname, *domain;
NSString **propertiesArray; NSString **propertiesArray;
NSMutableString *buffer; NSMutableString *buffer;
NSDictionary *object; NSDictionary *object;
@ -628,13 +633,13 @@
max = [refs length]; max = [refs length];
buffer = [NSMutableString stringWithCapacity: max*512]; buffer = [NSMutableString stringWithCapacity: max*512];
domain = [[context activeUser] domain];
for (count = 0; count < max; count++) for (count = 0; count < max; count++)
{ {
element = [refs objectAtIndex: count]; element = [refs objectAtIndex: count];
url = [[[element firstChild] nodeValue] stringByUnescapingURL]; url = [[[element firstChild] nodeValue] stringByUnescapingURL];
cname = [self _deduceObjectNameFromURL: url fromBaseURL: baseURL]; cname = [self _deduceObjectNameFromURL: url fromBaseURL: baseURL];
object = [source lookupContactEntry: cname]; object = [source lookupContactEntry: cname inDomain: domain];
if (object) if (object)
[self appendObject: object [self appendObject: object
properties: propertiesArray properties: propertiesArray

View File

@ -30,14 +30,13 @@
{ {
NSDictionary *parameters; NSDictionary *parameters;
NSString *filename; NSString *filename;
filename = [[self objectForKey: @"parameterList"] filename = nil;
objectForKey: @"name"]; parameters = [[self objectForKey: @"disposition"]
objectForKey: @"parameterList"];
if (!filename)
if (parameters)
{ {
parameters = [[self objectForKey: @"disposition"]
objectForKey: @"parameterList"];
filename = [parameters objectForKey: @"filename"]; filename = [parameters objectForKey: @"filename"];
@ -45,29 +44,33 @@
// See RFC2231 for details. If it was folded before, it will // See RFC2231 for details. If it was folded before, it will
// be unfolded when we get here. // be unfolded when we get here.
if (!filename) if (!filename)
{ {
filename = [parameters objectForKey: @"filename*"]; filename = [parameters objectForKey: @"filename*"];
if (filename) if (filename)
{ {
NSRange r; NSRange r;
filename = [filename stringByUnescapingURL]; filename = [filename stringByUnescapingURL];
// We skip up to the language // We skip up to the language
r = [filename rangeOfString: @"'"]; r = [filename rangeOfString: @"'"];
if (r.length) if (r.length)
{ {
r = [filename rangeOfString: @"'" options: 0 range: NSMakeRange(r.location+1, [filename length]-r.location-1)]; r = [filename rangeOfString: @"'" options: 0 range: NSMakeRange(r.location+1, [filename length]-r.location-1)];
if (r.length) if (r.length)
filename = [filename substringFromIndex: r.location+1]; filename = [filename substringFromIndex: r.location+1];
} }
} }
} }
} }
if (!filename)
filename = [[self objectForKey: @"parameterList"]
objectForKey: @"name"];
return filename; return filename;
} }

View File

@ -32,6 +32,12 @@ SOGo_HEADER_FILES = \
SOGoGCSFolder.h \ SOGoGCSFolder.h \
SOGoParentFolder.h \ SOGoParentFolder.h \
SOGoUserFolder.h \ SOGoUserFolder.h \
SOGoSource.h \
SOGoSystemDefaults.h \
SOGoDomainDefaults.h \
SOGoLDAPDefaults.h \
SOGoDefaultsSource.h \
SOGoUserDefaults.h \
\ \
SOGoSieveManager.h \ SOGoSieveManager.h \
\ \

View File

@ -120,8 +120,10 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField;
- (void) setContactMapping: (NSDictionary *) newMapping - (void) setContactMapping: (NSDictionary *) newMapping
andObjectClasses: (NSArray *) newObjectClasses; andObjectClasses: (NSArray *) newObjectClasses;
- (NGLdapEntry *) lookupGroupEntryByUID: (NSString *) theUID; - (NGLdapEntry *) lookupGroupEntryByUID: (NSString *) theUID
- (NGLdapEntry *) lookupGroupEntryByEmail: (NSString *) theEmail; inDomain: (NSString *) domain;
- (NGLdapEntry *) lookupGroupEntryByEmail: (NSString *) theEmail
inDomain: (NSString *) domain;
@end @end

View File

@ -162,6 +162,7 @@ static Class NSStringK;
[multipleBookingsField release]; [multipleBookingsField release];
[MSExchangeHostname release]; [MSExchangeHostname release];
[modifiers release]; [modifiers release];
[displayName release];
[super dealloc]; [super dealloc];
} }
@ -1242,6 +1243,7 @@ groupObjectClasses: (NSArray *) newGroupObjectClasses
} }
- (NSDictionary *) lookupContactEntry: (NSString *) theID - (NSDictionary *) lookupContactEntry: (NSString *) theID
inDomain: (NSString *) domain
{ {
NGLdapEntry *ldapEntry; NGLdapEntry *ldapEntry;
EOQualifier *qualifier; EOQualifier *qualifier;
@ -1339,12 +1341,14 @@ groupObjectClasses: (NSArray *) newGroupObjectClasses
} }
- (NGLdapEntry *) lookupGroupEntryByUID: (NSString *) theUID - (NGLdapEntry *) lookupGroupEntryByUID: (NSString *) theUID
inDomain: (NSString *) domain
{ {
return [self _lookupGroupEntryByAttributes: [NSArray arrayWithObject: UIDField] return [self _lookupGroupEntryByAttributes: [NSArray arrayWithObject: UIDField]
andValue: theUID]; andValue: theUID];
} }
- (NGLdapEntry *) lookupGroupEntryByEmail: (NSString *) theEmail - (NGLdapEntry *) lookupGroupEntryByEmail: (NSString *) theEmail
inDomain: (NSString *) domain
{ {
return [self _lookupGroupEntryByAttributes: mailFields return [self _lookupGroupEntryByAttributes: mailFields
andValue: theEmail]; andValue: theEmail];

View File

@ -50,6 +50,9 @@
andParentSource: systemDefaults]; andParentSource: systemDefaults];
} }
if (!domainDefaults)
domainDefaults = [SOGoSystemDefaults sharedSystemDefaults];
return domainDefaults; return domainDefaults;
} }

View File

@ -113,7 +113,7 @@
uid = [theID hasPrefix: @"@"] ? [theID substringFromIndex: 1] : theID; uid = [theID hasPrefix: @"@"] ? [theID substringFromIndex: 1] : theID;
return [SOGoGroup groupWithValue: uid return [SOGoGroup groupWithValue: uid
andSourceSelector: @selector (lookupGroupEntryByUID:) andSourceSelector: @selector (lookupGroupEntryByUID:inDomain:)
inDomain: domain]; inDomain: domain];
} }
@ -121,7 +121,7 @@
inDomain: (NSString *) domain inDomain: (NSString *) domain
{ {
return [SOGoGroup groupWithValue: theEmail return [SOGoGroup groupWithValue: theEmail
andSourceSelector: @selector (lookupGroupEntryByEmail:) andSourceSelector: @selector (lookupGroupEntryByEmail:inDomain:)
inDomain: domain]; inDomain: domain];
} }
@ -158,9 +158,9 @@
// Our different sources might not all implements groups support // Our different sources might not all implements groups support
if ([source respondsToSelector: theSelector]) if ([source respondsToSelector: theSelector])
entry = [source performSelector: theSelector entry = [source performSelector: theSelector
withObject: theValue]; withObject: theValue
withObject: domain];
if (entry) if (entry)
break; break;

View File

@ -180,6 +180,9 @@
[NSException raise: NSInvalidArgumentException [NSException raise: NSInvalidArgumentException
format: @"'_name' must not be an empty string"]; format: @"'_name' must not be an empty string"];
context = [[WOApplication application] context]; context = [[WOApplication application] context];
if (!context)
[self errorWithFormat: @"Error: initializing a SOGoObject (named %@) "
@"without wocontext", _name];
nameInContainer = [_name copy]; nameInContainer = [_name copy];
container = _container; container = _container;
if ([self doesRetainContainer]) if ([self doesRetainContainer])

View File

@ -41,6 +41,7 @@
#include <unistd.h> #include <unistd.h>
#import "SOGoSystemDefaults.h" #import "SOGoSystemDefaults.h"
#import "SOGoUserManager.h"
@implementation SOGoSession @implementation SOGoSession
@ -262,7 +263,7 @@
// The domain is probably appended to the username; // The domain is probably appended to the username;
// make sure it is defined as a domain in the configuration. // make sure it is defined as a domain in the configuration.
*theDomain = [*theLogin substringFromIndex: (r.location + r.length)]; *theDomain = [*theLogin substringFromIndex: (r.location + r.length)];
if (![[sd domainIds] containsObject: *theDomain]) if (![[SOGoUserManager sharedUserManager] isDomainDefined: *theDomain])
*theDomain = nil; *theDomain = nil;
} }
} }

View File

@ -56,7 +56,8 @@
newPassword: (NSString *) newPassword newPassword: (NSString *) newPassword
perr: (SOGoPasswordPolicyError *) perr; perr: (SOGoPasswordPolicyError *) perr;
- (NSDictionary *) lookupContactEntry: (NSString *) theID; - (NSDictionary *) lookupContactEntry: (NSString *) theID
inDomain: (NSString *) domain;
- (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) entryID - (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) entryID
inDomain: (NSString *) domain; inDomain: (NSString *) domain;

View File

@ -261,7 +261,7 @@ _injectConfigurationFromFile (NSMutableDictionary *defaultsDict,
- (BOOL) enableDomainBasedUID - (BOOL) enableDomainBasedUID
{ {
return ([[self domainIds] count] > 0 && [self boolForKey: @"SOGoEnableDomainBasedUID"]); return [self boolForKey: @"SOGoEnableDomainBasedUID"];
} }
- (NSArray *) loginDomains - (NSArray *) loginDomains

View File

@ -165,7 +165,7 @@
// The domain is probably appended to the username; // The domain is probably appended to the username;
// make sure it is defined as a domain in the configuration. // make sure it is defined as a domain in the configuration.
domain = [newLogin substringFromIndex: (r.location + r.length)]; domain = [newLogin substringFromIndex: (r.location + r.length)];
if ([[sd domainIds] containsObject: domain] && if ([[SOGoUserManager sharedUserManager] isDomainDefined: domain] &&
![sd enableDomainBasedUID]) ![sd enableDomainBasedUID])
newLogin = [newLogin substringToIndex: r.location]; newLogin = [newLogin substringToIndex: r.location];

View File

@ -58,6 +58,7 @@
- (NSArray *) sourceIDsInDomain: (NSString *) domain; - (NSArray *) sourceIDsInDomain: (NSString *) domain;
- (NSArray *) authenticationSourceIDsInDomain: (NSString *) domain; - (NSArray *) authenticationSourceIDsInDomain: (NSString *) domain;
- (NSArray *) addressBookSourceIDsInDomain: (NSString *) domain; - (NSArray *) addressBookSourceIDsInDomain: (NSString *) domain;
- (BOOL) isDomainDefined: (NSString *) domain;
- (NSObject <SOGoSource> *) sourceWithID: (NSString *) sourceID; - (NSObject <SOGoSource> *) sourceWithID: (NSString *) sourceID;
- (NSDictionary *) metadataForSourceID: (NSString *) sourceID; - (NSDictionary *) metadataForSourceID: (NSString *) sourceID;

View File

@ -67,10 +67,12 @@ static Class NSNullK;
if (type) if (type)
{ {
if ([type isEqualToString: @"ldap"]) if ([type caseInsensitiveCompare: @"ldap"] == NSOrderedSame)
sourceClass = @"LDAPSource"; sourceClass = @"LDAPSource";
else if ([type isEqualToString: @"sql"]) else if ([type caseInsensitiveCompare: @"sql"] == NSOrderedSame)
sourceClass = @"SQLSource"; sourceClass = @"SQLSource";
else if (NSClassFromString(type))
sourceClass = type;
else else
{ {
[NSException raise: @"SOGoUserManagerRegistryException" [NSException raise: @"SOGoUserManagerRegistryException"
@ -104,65 +106,58 @@ static Class NSNullK;
NSString *sourceID, *value, *type; NSString *sourceID, *value, *type;
NSMutableDictionary *metadata; NSMutableDictionary *metadata;
NSObject <SOGoSource> *sogoSource; NSObject <SOGoSource> *sogoSource;
BOOL isAddressBook, result; BOOL isAddressBook;
Class c; Class c;
result = NO;
sourceID = [udSource objectForKey: @"id"]; sourceID = [udSource objectForKey: @"id"];
if ([sourceID length] > 0) if (!sourceID || [sourceID length] == 0)
{ {
if ([_sourcesMetadata objectForKey: sourceID]) [self errorWithFormat: @"attempted to register a contact/user source "
[self errorWithFormat: @"attempted to register a contact/user source" @"without id (skipped)"];
@" with duplicated id (%@)", sourceID]; return NO;
else }
{ if ([_sourcesMetadata objectForKey: sourceID])
type = [[udSource objectForKey: @"type"] lowercaseString]; {
c = NSClassFromString([_registry sourceClassForType: type]); [self errorWithFormat: @"attempted to register a contact/user source "
sogoSource = [c sourceFromUDSource: udSource inDomain: domain]; @"with duplicated id (%@)", sourceID];
if (sourceID) return NO;
[_sources setObject: sogoSource forKey: sourceID]; }
else
[self errorWithFormat: @"id field missing in an user source," type = [udSource objectForKey: @"type"];
@" check the SOGoUserSources defaults"]; c = NSClassFromString([_registry sourceClassForType: type]);
metadata = [NSMutableDictionary dictionary]; sogoSource = [c sourceFromUDSource: udSource inDomain: domain];
if (domain) [_sources setObject: sogoSource forKey: sourceID];
[metadata setObject: domain forKey: @"domain"];
value = [udSource objectForKey: @"canAuthenticate"]; metadata = [NSMutableDictionary dictionary];
if (value) if (domain)
[metadata setObject: value forKey: @"canAuthenticate"]; [metadata setObject: domain forKey: @"domain"];
value = [udSource objectForKey: @"isAddressBook"]; value = [udSource objectForKey: @"canAuthenticate"];
if (value) if (value)
{ [metadata setObject: value forKey: @"canAuthenticate"];
[metadata setObject: value forKey: @"isAddressBook"]; value = [udSource objectForKey: @"isAddressBook"];
isAddressBook = [value boolValue]; if (value)
} {
else [metadata setObject: value forKey: @"isAddressBook"];
isAddressBook = NO; isAddressBook = [value boolValue];
value = [udSource objectForKey: @"displayName"];
if (value)
[metadata setObject: value forKey: @"displayName"];
else
{
if (isAddressBook)
[self errorWithFormat: @"addressbook source '%@' has"
@" no displayname", sourceID];
}
value = [udSource objectForKey: @"MailFieldNames"];
if (value)
[metadata setObject: value forKey: @"MailFieldNames"];
value = [udSource objectForKey: @"SearchFieldNames"];
if (value)
[metadata setObject: value forKey: @"SearchFieldNames"];
[_sourcesMetadata setObject: metadata forKey: sourceID];
result = YES;
}
} }
else else
[self errorWithFormat: @"attempted to register a contact/user source" isAddressBook = NO;
@" without id (skipped)"]; value = [udSource objectForKey: @"displayName"];
if (value)
[metadata setObject: value forKey: @"displayName"];
else if (isAddressBook)
[self errorWithFormat: @"addressbook source '%@' has no displayname", sourceID];
return result; value = [udSource objectForKey: @"MailFieldNames"];
if (value)
[metadata setObject: value forKey: @"MailFieldNames"];
value = [udSource objectForKey: @"SearchFieldNames"];
if (value)
[metadata setObject: value forKey: @"SearchFieldNames"];
[_sourcesMetadata setObject: metadata forKey: sourceID];
return YES;
} }
- (int) _registerSourcesInDomain: (NSString *) domain - (int) _registerSourcesInDomain: (NSString *) domain
@ -171,11 +166,7 @@ static Class NSNullK;
unsigned int count, max, total; unsigned int count, max, total;
SOGoDomainDefaults *dd; SOGoDomainDefaults *dd;
if (domain) dd = [SOGoDomainDefaults defaultsForDomain: domain];
dd = [SOGoDomainDefaults defaultsForDomain: domain];
else
dd = [SOGoSystemDefaults sharedSystemDefaults];
userSources = [dd userSources]; userSources = [dd userSources];
max = [userSources count]; max = [userSources count];
total = 0; total = 0;
@ -305,6 +296,35 @@ static Class NSNullK;
return sourceIDs; return sourceIDs;
} }
- (BOOL) isDomainDefined: (NSString *) domain
{
NSEnumerator *allIDs;
NSArray *ids;
NSString *currentID, *sourceDomain;
SOGoSystemDefaults *sd;
if (!domain) return NO;
ids = [_sources allKeys];
if ([ids containsObject: domain])
// FIXME check SOGoMailDomain?
// Now source id is being considered as the domain
return YES;
sd = [SOGoSystemDefaults sharedSystemDefaults];
if ([sd enableDomainBasedUID])
{
allIDs = [ids objectEnumerator];
while ((currentID = [allIDs nextObject]))
{
sourceDomain = [[_sources objectForKey: currentID] domain];
if (!sourceDomain) // source that can identify any domain
return YES;
}
}
return NO;
}
- (NSString *) displayNameForSourceWithID: (NSString *) sourceID - (NSString *) displayNameForSourceWithID: (NSString *) sourceID
{ {
NSDictionary *metadata; NSDictionary *metadata;
@ -328,7 +348,6 @@ static Class NSNullK;
{ {
NSDictionary *contactInfos; NSDictionary *contactInfos;
// NSLog (@"getEmailForUID: %@", uid);
contactInfos = [self contactInfosForUserWithUIDorEmail: uid]; contactInfos = [self contactInfosForUserWithUIDorEmail: uid];
return [contactInfos objectForKey: @"c_email"]; return [contactInfos objectForKey: @"c_email"];
@ -345,8 +364,7 @@ static Class NSNullK;
if ([cn length] > 0) if ([cn length] > 0)
{ {
if ([email length] > 0) if ([email length] > 0)
fullEmail = [NSString stringWithFormat: @"%@ <%@>", fullEmail = [NSString stringWithFormat: @"%@ <%@>", cn, email];
cn, email];
else else
fullEmail = cn; fullEmail = cn;
} }
@ -369,11 +387,7 @@ static Class NSNullK;
login = [contactInfos objectForKey: @"c_imaplogin"]; login = [contactInfos objectForKey: @"c_imaplogin"];
if (login == nil) if (login == nil)
{ {
if ([domain length]) dd = [SOGoDomainDefaults defaultsForDomain: domain];
dd = [SOGoDomainDefaults defaultsForDomain: domain];
else
dd = [SOGoSystemDefaults sharedSystemDefaults];
if ([dd forceExternalLoginWithEmail]) if ([dd forceExternalLoginWithEmail])
{ {
sd = [SOGoSystemDefaults sharedSystemDefaults]; sd = [SOGoSystemDefaults sharedSystemDefaults];
@ -415,16 +429,16 @@ static Class NSNullK;
- (BOOL) _sourceChangePasswordForLogin: (NSString *) login - (BOOL) _sourceChangePasswordForLogin: (NSString *) login
inDomain: (NSString *) domain inDomain: (NSString *) domain
oldPassword: (NSString *) oldPassword oldPassword: (NSString *) oldPassword
newPassword: (NSString *) newPassword newPassword: (NSString *) newPassword
perr: (SOGoPasswordPolicyError *) perr perr: (SOGoPasswordPolicyError *) perr
{ {
NSObject <SOGoSource> *sogoSource; NSObject <SOGoSource> *sogoSource;
NSEnumerator *authIDs; NSEnumerator *authIDs;
NSString *currentID; NSString *currentID;
BOOL didChange; BOOL didChange;
didChange = NO; didChange = NO;
authIDs = [[self authenticationSourceIDsInDomain: domain] objectEnumerator]; authIDs = [[self authenticationSourceIDsInDomain: domain] objectEnumerator];
while (!didChange && (currentID = [authIDs nextObject])) while (!didChange && (currentID = [authIDs nextObject]))
{ {
@ -465,7 +479,24 @@ static Class NSNullK;
} }
if (checkOK && *domain == nil) if (checkOK && *domain == nil)
*domain = [sogoSource domain]; {
SOGoSystemDefaults *sd = [SOGoSystemDefaults sharedSystemDefaults];
BOOL multidomainSource = [sd enableDomainBasedUID] &&
[sogoSource domain] == nil;
if (multidomainSource)
{
NSArray *parts = [login componentsSeparatedByString: @"@"];
if ([parts count] != 2)
{
[self errorWithFormat: @"Authenticated with multidomain source "
@"but login is not an email (%@).", login];
return NO;
}
*domain = [parts objectAtIndex: 1];
}
else
*domain = [sogoSource domain];
}
return checkOK; return checkOK;
} }
@ -546,7 +577,7 @@ static Class NSNullK;
delta = current_time - start_time; delta = current_time - start_time;
block_time = [sd failedLoginBlockInterval]; block_time = [sd failedLoginBlockInterval];
if ([[failedCount objectForKey: @"FailedCount"] intValue] >= [sd maximumFailedLoginCount] && if ([[failedCount objectForKey: @"FailedCount"] intValue] >= [sd maximumFailedLoginCount] &&
delta >= [sd maximumFailedLoginInterval] && delta >= [sd maximumFailedLoginInterval] &&
delta <= block_time ) delta <= block_time )
@ -554,7 +585,7 @@ static Class NSNullK;
*_perr = PolicyAccountLocked; *_perr = PolicyAccountLocked;
return NO; return NO;
} }
if (delta > block_time) if (delta > block_time)
{ {
[[SOGoCache sharedCache] setFailedCount: 0 [[SOGoCache sharedCache] setFailedCount: 0
@ -638,7 +669,7 @@ static Class NSNullK;
[[SOGoCache sharedCache] setFailedCount: ([[failedCount objectForKey: @"FailedCount"] intValue] + 1) [[SOGoCache sharedCache] setFailedCount: ([[failedCount objectForKey: @"FailedCount"] intValue] + 1)
forLogin: username]; forLogin: username];
} }
checkOK = NO; checkOK = NO;
} }
@ -649,7 +680,7 @@ static Class NSNullK;
{ {
NSObject <SOGoDNSource> *currentSource; NSObject <SOGoDNSource> *currentSource;
NSEnumerator *sources; NSEnumerator *sources;
sources = [[_sources allValues] objectEnumerator]; sources = [[_sources allValues] objectEnumerator];
while ((currentSource = [sources nextObject])) while ((currentSource = [sources nextObject]))
if ([currentSource conformsToProtocol: @protocol(SOGoDNSource)] && if ([currentSource conformsToProtocol: @protocol(SOGoDNSource)] &&
@ -669,9 +700,9 @@ static Class NSNullK;
// //
- (BOOL) changePasswordForLogin: (NSString *) login - (BOOL) changePasswordForLogin: (NSString *) login
inDomain: (NSString *) domain inDomain: (NSString *) domain
oldPassword: (NSString *) oldPassword oldPassword: (NSString *) oldPassword
newPassword: (NSString *) newPassword newPassword: (NSString *) newPassword
perr: (SOGoPasswordPolicyError *) perr perr: (SOGoPasswordPolicyError *) perr
{ {
NSString *jsonUser, *userLogin; NSString *jsonUser, *userLogin;
NSMutableDictionary *currentUser; NSMutableDictionary *currentUser;
@ -720,21 +751,19 @@ static Class NSNullK;
SOGoDomainDefaults *dd; SOGoDomainDefaults *dd;
domain = [contact objectForKey: @"c_domain"]; domain = [contact objectForKey: @"c_domain"];
if ([domain length]) dd = [SOGoDomainDefaults defaultsForDomain: domain];
dd = [SOGoDomainDefaults defaultsForDomain: domain];
else
dd = [SOGoSystemDefaults sharedSystemDefaults];
emails = [contact objectForKey: @"emails"]; emails = [contact objectForKey: @"emails"];
uid = [contact objectForKey: @"c_uid"]; if ([emails count] == 0)
if ([uid rangeOfString: @"@"].location == NSNotFound) {
systemEmail uid = [contact objectForKey: @"c_uid"];
= [NSString stringWithFormat: @"%@@%@", uid, [dd mailDomain]]; if ([uid rangeOfString: @"@"].location == NSNotFound)
else systemEmail = [NSString stringWithFormat: @"%@@%@", uid, [dd mailDomain]];
systemEmail = uid; else
systemEmail = uid;
// We always add the system email, which will always be returned // We always add the system email, which will always be returned
// by SOGoUser -systemEmail. // by SOGoUser -systemEmail.
[emails addObject: systemEmail]; [emails addObject: systemEmail];
}
[contact setObject: [emails objectAtIndex: 0] forKey: @"c_email"]; [contact setObject: [emails objectAtIndex: 0] forKey: @"c_email"];
} }
@ -789,7 +818,7 @@ static Class NSNullK;
while (!userEntry && (sourceID = [sogoSources nextObject])) while (!userEntry && (sourceID = [sogoSources nextObject]))
{ {
currentSource = [_sources objectForKey: sourceID]; currentSource = [_sources objectForKey: sourceID];
userEntry = [currentSource lookupContactEntryWithUIDorEmail: theUID userEntry = [currentSource lookupContactEntryWithUIDorEmail: theUID
inDomain: theDomain]; inDomain: theDomain];
if (userEntry) if (userEntry)
@ -904,7 +933,7 @@ static Class NSNullK;
[user setObject: [NSNumber numberWithBool: YES] [user setObject: [NSNumber numberWithBool: YES]
forKey: @"CalendarAccess"]; forKey: @"CalendarAccess"];
[user setObject: [NSNumber numberWithBool: NO] [user setObject: [NSNumber numberWithBool: NO]
forKey: @"MailAccess"]; forKey: @"MailAccess"];
} }
return user; return user;
@ -933,7 +962,7 @@ static Class NSNullK;
// The domain is probably appended to the username; // The domain is probably appended to the username;
// make sure it is a defined domain in the configuration. // make sure it is a defined domain in the configuration.
domain = [uid substringFromIndex: (r.location + r.length)]; domain = [uid substringFromIndex: (r.location + r.length)];
if ([[sd domainIds] containsObject: domain]) if ([self isDomainDefined: domain])
username = [uid substringToIndex: r.location]; username = [uid substringToIndex: r.location];
else else
domain = nil; domain = nil;
@ -948,7 +977,7 @@ static Class NSNullK;
// search using the original uid. // search using the original uid.
infos = [self contactInfosForUserWithUIDorEmail: uid infos = [self contactInfosForUserWithUIDorEmail: uid
inDomain: nil]; inDomain: nil];
return infos; return infos;
} }
@ -977,29 +1006,29 @@ static Class NSNullK;
if ([currentUser isKindOfClass: NSNullK]) if ([currentUser isKindOfClass: NSNullK])
currentUser = nil; currentUser = nil;
else if (!([currentUser objectForKey: @"emails"] else if (!([currentUser objectForKey: @"emails"]
&& [currentUser objectForKey: @"cn"])) && [currentUser objectForKey: @"cn"]))
{ {
// We make sure that we either have no occurence of a cache entry or // We make sure that we either have no occurence of a cache entry or
// that we have an occurence with only a cached password. In the // that we have an occurence with only a cached password. In the
// latter case, we update the entry with the remaining information // latter case, we update the entry with the remaining information
// and recache the value. // and recache the value.
if (!currentUser || if (!currentUser ||
([currentUser count] == 1 && [currentUser objectForKey: @"password"]) || ([currentUser count] == 1 && [currentUser objectForKey: @"password"]) ||
([currentUser count] == 2 && [currentUser objectForKey: @"password"] && [currentUser objectForKey: @"DomainLessLogin"])) ([currentUser count] == 2 && [currentUser objectForKey: @"password"] && [currentUser objectForKey: @"DomainLessLogin"]))
{ {
newUser = YES; newUser = YES;
if (!currentUser) if (!currentUser)
currentUser = [NSMutableDictionary dictionary]; currentUser = [NSMutableDictionary dictionary];
} }
else else
newUser = NO; newUser = NO;
[self _fillContactInfosForUser: currentUser [self _fillContactInfosForUser: currentUser
withUIDorEmail: aUID withUIDorEmail: aUID
inDomain: domain]; inDomain: domain];
if (newUser) if (newUser)
{ {
if ([[currentUser objectForKey: @"c_uid"] length] == 0) if ([[currentUser objectForKey: @"c_uid"] length] == 0)
{ {
[self _retainUser: (NSDictionary *) [NSNull null] [self _retainUser: (NSDictionary *) [NSNull null]
withLogin: cacheUid]; withLogin: cacheUid];
@ -1022,7 +1051,7 @@ static Class NSNullK;
[self _retainUser: currentUser withLogin: cacheUid]; [self _retainUser: currentUser withLogin: cacheUid];
} }
} }
} }
} }
else else
currentUser = nil; currentUser = nil;
@ -1048,7 +1077,7 @@ static Class NSNullK;
while ((sourceID = [sources nextObject])) while ((sourceID = [sources nextObject]))
{ {
currentSource = [_sources objectForKey: sourceID]; currentSource = [_sources objectForKey: sourceID];
contact = [currentSource lookupContactEntry: uid]; contact = [currentSource lookupContactEntry: uid inDomain: domain];
if (contact) if (contact)
[contacts addObject: contact]; [contacts addObject: contact];
} }
@ -1077,30 +1106,30 @@ static Class NSNullK;
{ {
uid = [userEntry objectForKey: @"c_uid"]; uid = [userEntry objectForKey: @"c_uid"];
if ([uid length]) if ([uid length])
{ {
returnContact = [compactContacts objectForKey: uid]; returnContact = [compactContacts objectForKey: uid];
if (!returnContact) if (!returnContact)
{ {
returnContact = [NSMutableDictionary dictionary]; returnContact = [NSMutableDictionary dictionary];
[returnContact setObject: uid forKey: @"c_uid"]; [returnContact setObject: uid forKey: @"c_uid"];
source = [userEntry objectForKey: @"source"]; source = [userEntry objectForKey: @"source"];
if (source) if (source)
[returnContact setObject: source forKey: @"source"]; [returnContact setObject: source forKey: @"source"];
[compactContacts setObject: returnContact forKey: uid]; [compactContacts setObject: returnContact forKey: uid];
} }
if (![[returnContact objectForKey: @"c_name"] length]) if (![[returnContact objectForKey: @"c_name"] length])
[returnContact setObject: [userEntry objectForKey: @"c_name"] [returnContact setObject: [userEntry objectForKey: @"c_name"]
forKey: @"c_name"]; forKey: @"c_name"];
if (![[returnContact objectForKey: @"cn"] length]) if (![[returnContact objectForKey: @"cn"] length])
[returnContact setObject: [userEntry objectForKey: @"c_cn"] [returnContact setObject: [userEntry objectForKey: @"c_cn"]
forKey: @"cn"]; forKey: @"cn"];
emails = [returnContact objectForKey: @"emails"]; emails = [returnContact objectForKey: @"emails"];
if (!emails) if (!emails)
{ {
emails = [NSMutableArray array]; emails = [NSMutableArray array];
[returnContact setObject: emails forKey: @"emails"]; [returnContact setObject: emails forKey: @"emails"];
} }
email = [userEntry objectForKey: @"mail"]; email = [userEntry objectForKey: @"mail"];
if ([email isKindOfClass: [NSArray class]]) if ([email isKindOfClass: [NSArray class]])
{ {
allEmails = (NSArray *) email; allEmails = (NSArray *) email;
@ -1112,22 +1141,22 @@ static Class NSNullK;
} }
} }
else if (email && ![emails containsObject: email]) else if (email && ![emails containsObject: email])
[emails addObject: email]; [emails addObject: email];
email = [userEntry objectForKey: @"mozillasecondemail"]; email = [userEntry objectForKey: @"mozillasecondemail"];
if (email && ![emails containsObject: email]) if (email && ![emails containsObject: email])
[emails addObject: email]; [emails addObject: email];
email = [userEntry objectForKey: @"xmozillasecondemail"]; email = [userEntry objectForKey: @"xmozillasecondemail"];
if (email && ![emails containsObject: email]) if (email && ![emails containsObject: email])
[emails addObject: email]; [emails addObject: email];
info = [userEntry objectForKey: @"c_info"]; info = [userEntry objectForKey: @"c_info"];
if ([info length] > 0 if ([info length] > 0
&& ![[returnContact objectForKey: @"c_info"] length]) && ![[returnContact objectForKey: @"c_info"] length])
[returnContact setObject: info forKey: @"c_info"]; [returnContact setObject: info forKey: @"c_info"];
[self _fillContactMailRecords: returnContact]; [self _fillContactMailRecords: returnContact];
isGroup = [userEntry objectForKey: @"isGroup"]; isGroup = [userEntry objectForKey: @"isGroup"];
if (isGroup) if (isGroup)
[returnContact setObject: isGroup forKey: @"isGroup"]; [returnContact setObject: isGroup forKey: @"isGroup"];
} }
} }
newContacts = [compactContacts allValues]; newContacts = [compactContacts allValues];
@ -1136,7 +1165,7 @@ static Class NSNullK;
} }
- (NSArray *) _fetchEntriesInSources: (NSArray *) sourcesList - (NSArray *) _fetchEntriesInSources: (NSArray *) sourcesList
matching: (NSString *) filter matching: (NSString *) filter
inDomain: (NSString *) domain inDomain: (NSString *) domain
{ {
NSMutableArray *contacts; NSMutableArray *contacts;
@ -1150,7 +1179,7 @@ static Class NSNullK;
{ {
currentSource = [_sources objectForKey: sourceID]; currentSource = [_sources objectForKey: sourceID];
[contacts addObjectsFromArray: [contacts addObjectsFromArray:
[currentSource fetchContactsMatching: filter [currentSource fetchContactsMatching: filter
inDomain: domain]]; inDomain: domain]];
} }

View File

@ -620,8 +620,9 @@
- (NSDictionary *) lookupContactEntry: (NSString *) theID - (NSDictionary *) lookupContactEntry: (NSString *) theID
inDomain: (NSString *) domain
{ {
return [self _lookupContactEntry: theID considerEmail: NO inDomain: nil]; return [self _lookupContactEntry: theID considerEmail: NO inDomain: domain];
} }
- (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) entryID - (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) entryID

View File

@ -363,6 +363,7 @@
} }
- (BOOL) extractUserLDIFRecord: (NSString *) uid - (BOOL) extractUserLDIFRecord: (NSString *) uid
inDomain: (NSString *) domain
intoRecord: (NSMutableDictionary *) userRecord intoRecord: (NSMutableDictionary *) userRecord
{ {
NSEnumerator *ldapSources; NSEnumerator *ldapSources;
@ -375,11 +376,11 @@
lm = [SOGoUserManager sharedUserManager]; lm = [SOGoUserManager sharedUserManager];
done = NO; done = NO;
ldapSources = [[lm authenticationSourceIDsInDomain: nil] objectEnumerator]; ldapSources = [[lm authenticationSourceIDsInDomain: domain] objectEnumerator];
while (!done && (sourceID = [ldapSources nextObject])) while (!done && (sourceID = [ldapSources nextObject]))
{ {
currentSource = [lm sourceWithID: sourceID]; currentSource = [lm sourceWithID: sourceID];
userEntry = [currentSource lookupContactEntry: uid]; userEntry = [currentSource lookupContactEntry: uid inDomain: domain];
if (userEntry) if (userEntry)
{ {
[userRecord setObject: [userEntry ldifRecordAsString] [userRecord setObject: [userEntry ldifRecordAsString]
@ -411,25 +412,26 @@
- (BOOL) exportUser: (NSDictionary *) theUser - (BOOL) exportUser: (NSDictionary *) theUser
{ {
NSString *exportPath, *gcsUID, *ldapUID; NSString *exportPath, *gcsUID, *ldapUID, *domain;
NSMutableDictionary *userRecord; NSMutableDictionary *userRecord;
SOGoSystemDefaults *sd; SOGoSystemDefaults *sd;
sd = [SOGoSystemDefaults sharedSystemDefaults]; sd = [SOGoSystemDefaults sharedSystemDefaults];
userRecord = [NSMutableDictionary dictionary]; userRecord = [NSMutableDictionary dictionary];
ldapUID = [theUser objectForKey: @"c_uid"]; ldapUID = [theUser objectForKey: @"c_uid"];
exportPath = [directory stringByAppendingPathComponent: ldapUID]; exportPath = [directory stringByAppendingPathComponent: ldapUID];
domain = [theUser objectForKey: @"c_domain"];
gcsUID = [theUser objectForKey: @"c_uid"]; gcsUID = [theUser objectForKey: @"c_uid"];
if ([sd enableDomainBasedUID] && [gcsUID rangeOfString: @"@"].location == NSNotFound) if ([sd enableDomainBasedUID] && [gcsUID rangeOfString: @"@"].location == NSNotFound)
gcsUID = [NSString stringWithFormat: @"%@@%@", gcsUID, [theUser objectForKey: @"c_domain"]]; gcsUID = [NSString stringWithFormat: @"%@@%@", gcsUID, [theUser objectForKey: @"c_domain"]];
return ([self extractUserFolders: gcsUID return ([self extractUserFolders: gcsUID
intoRecord: userRecord] intoRecord: userRecord]
&& [self extractUserLDIFRecord: ldapUID && [self extractUserLDIFRecord: ldapUID
inDomain: domain
intoRecord: userRecord] intoRecord: userRecord]
&& [self extractUserPreferences: gcsUID && [self extractUserPreferences: gcsUID
intoRecord: userRecord] intoRecord: userRecord]

@ -1 +1 @@
Subproject commit 843d63ec5520d313eb327d2d99606e9f6177912e Subproject commit 80a8929f513c508da49a347a2a52bef48c15fb2a