Compare commits

...
113 Commits
Author SHA1 Message Date
WoodySlum (Le Programmeur) 36ce92db4a Merge pull request #331 from leecher1337/maint
Merge compatible EAS changes from 5.x branch to 2.x
2022-11-08 08:25:07 +01:00
Francis Lachapelle 583f97d3c6 fix(eas): improve error logging 2022-11-04 23:53:55 +01:00
Francis Lachapelle 6952b1274f fix(eas): handle module constraints
Fixes #5456
2022-11-04 23:53:46 +01:00
Francis Lachapelle e3a8c101b3 fix(eas): handle module constraints
Fixes #5456
2022-11-04 23:53:35 +01:00
Francis Lachapelle 487e67a291 fix(eas): handle module constraints
Fixes #5456
2022-11-04 23:53:24 +01:00
tfux 09690f61ef feat(eas): implement replyTo element 2022-11-04 23:53:15 +01:00
tfux 7fe1bea9ce fix(eas): handle attachments of type message/rfc822 when sanitize emails (fixes #5427) (#304) 2022-11-04 23:53:06 +01:00
tfux 48fc4bc87d fix(eas): use base64 encoding for attachments when sanitize emails + content-length
Fixes #5408
2022-11-04 23:52:54 +01:00
jkellerer 24c0108c47 fix(eas): proxy authentication in _sendMail 2022-11-04 23:52:44 +01:00
root 07ed0201c7 fix(eas): improve EAS parameters parsing (fixes #5266) 2022-11-04 23:52:35 +01:00
root 9fe9855423 fix(eas): handle fileAs element (fixes #5239) 2022-11-04 23:52:26 +01:00
Ludovic Marcotte f94586e47b fix(eas): avoid doing bogus truncation 2022-11-04 23:51:53 +01:00
root b77d69fbd0 fix(eas): properly encode DisplayTo (fixes #4995) 2022-11-04 23:51:43 +01:00
root 7f2b485764 fix(eas): fix invalid DisplayTo (fixes #4988) 2022-11-04 23:51:34 +01:00
root cb34fae175 fix(eas): additional name fields (fixes #4929) 2022-11-04 23:51:20 +01:00
Ludovic Marcotte 0beb0536a8 fix(eas): avoid generating broken XML ouput (fixes #4927) 2022-11-04 23:51:09 +01:00
Ludovic Marcotte d5a6f9b9d5 fix(eas): make sure there is always an attendee name (fixes #4910) 2022-11-04 23:50:59 +01:00
Ludovic Marcotte 76f9e2b009 fix(core): avoid warning by including missing file 2022-11-04 23:50:49 +01:00
Ludovic Marcotte 6d27fdd340 (fix) avoid incorrect truncation leading to exception (fixes #4806) 2022-11-04 23:50:30 +01:00
Ludovic Marcotte bd6bdcb136 (fix) improve FolderSync operation (fixes #4672) 2022-11-04 23:46:59 +01:00
Francis Lachapelle 671857fd19 (EAS) Fix handling of missing date
Fixes #4720
2022-11-04 23:35:02 +01:00
Ludovic Marcotte 896d14d8c0 (fix) better handle timezone changes (fixes #4624) 2022-11-04 23:34:49 +01:00
Ludovic Marcotte 2cd21052bd (feat) support for basic UserInformation queries (fixes #4614) 2022-11-04 23:34:38 +01:00
Ludovic Marcotte e5004db2af (fix) better handle bogus DTStart values over EAS 2022-11-04 23:34:14 +01:00
Ludovic Marcotte 562f67fc25 (fix) fix search on for Outlook application (#4605 and #4607) 2022-11-04 23:25:00 +01:00
Ludovic Marcotte 26e84aad4b (fix) strip '<>' from bodyId and when forwarding mails 2022-11-04 23:24:38 +01:00
Ludovic Marcotte 2a67e12d55 (fix) fixed EAS search operation 2022-11-04 22:32:13 +01:00
Ludovic Marcotte cb31d4faa9 (fix) also try to get event using its UID before bailing out 2022-11-04 22:32:00 +01:00
Ludovic Marcotte f40584616e (fix) avoid potential cache update when breaking sync queries (fixes #4422) 2022-11-04 22:31:18 +01:00
Ludovic Marcotte e99d8b8c81 (fix) small optimizations + code cosmetics 2022-11-04 22:27:25 +01:00
Ludovic Marcotte e0c5c5b200 (fix) improved alarms syncing with EAS devices (fixes #4351) 2022-11-04 22:27:09 +01:00
Ludovic Marcotte 102d8a977a (fix) EAS with drafts with attachments 2022-11-04 22:16:31 +01:00
Ludovic Marcotte 9461eb7027 (fix) correctly handle all-day events with EAS v16 (fixes #4397) 2022-11-04 22:16:12 +01:00
Ludovic Marcotte c9f94f1ec4 (fix) skip organizer from attendees list (fixes #4402) 2022-11-04 22:14:05 +01:00
Francis Lachapelle 0dfb621b37 Use address books search fields in Contacts module
Fixes #4356
2022-11-04 21:59:32 +01:00
Francis Lachapelle 72c97079f6 Merge to 2.4.3 2022-04-08 08:24:50 -04:00
Francis Lachapelle 07574297cd fix(mail): don't encode calendar mime part twice
SOPE will take care of encoding all text parts in quoted-printable if necessary.

Fixes #5391
Fixes #5393
2022-04-08 08:18:13 -04:00
Francis Lachapelle d23bafbae6 Merge to 2.4.2 2022-04-04 18:47:43 -04:00
Francis Lachapelle 24687abdd4 Merge to 2.4.1 2021-05-31 21:18:21 -04:00
Francis Lachapelle e2463f8115 Merge to 2.4.0 2021-03-31 10:20:18 -04:00
Francis Lachapelle c1d6d475de Merge to 2.3.23 2017-10-18 11:13:31 -04:00
Francis Lachapelle 0fe8d0eab2 Merge to 2.3.22 2017-07-20 14:03:59 -04:00
Francis Lachapelle 06c10d8b37 Merge to 2.3.21
Conflicts:
	SoObjects/Appointments/SOGoAppointmentFolder.m
2017-06-01 09:54:00 -04:00
Francis Lachapelle 2c8f56fb67 Merge to 2.3.20 2017-03-10 11:14:52 -05:00
Francis Lachapelle 42fa0a273e Update ChangeLog 2017-01-06 20:58:17 -05:00
Francis Lachapelle 07872d753c (js) Update ResizeSensor.js 2017-01-06 20:58:17 -05:00
Francis Lachapelle 0305d00d50 (js) Update CKEditor to version 4.6.1 2017-01-06 20:58:17 -05:00
Francis Lachapelle 3b65b6e2cf (i18n) Update translations 2017-01-06 20:58:16 -05:00
Ludovic Marcotte 43a68979ac Updated NEWS 2017-01-06 20:58:16 -05:00
Ludovic Marcotte 4cd2ad0337 (fix) handle sha512-crypt with rounds 2017-01-06 20:58:16 -05:00
Ludovic Marcotte ca57ac4677 Updated NEWS 2017-01-06 20:58:16 -05:00
Ludovic Marcotte 0063320d70 (fix) correctly handle all identities during IMIP status update 2017-01-06 20:58:15 -05:00
Ludovic Marcotte f7462fd5ee (fix) small optimization over previous commit 2017-01-06 20:58:15 -05:00
Ludovic Marcotte 893fdda43b (fix) handle all identities during IMIP REPLY processing 2017-01-06 20:58:15 -05:00
Francis Lachapelle 62df4fffa3 Fix support for recurrent tasks 2017-01-06 20:58:15 -05:00
Francis Lachapelle cde6fe520c Add parameter validation to alarmsListAction 2017-01-06 20:58:15 -05:00
Francis Lachapelle d548cea518 (js) Use GET instead of POST when form is empty
Fixes #3978, #3979
2017-01-06 20:58:15 -05:00
Ludovic Marcotte 278b65d89c (fix) make sure we compare the organizer's email only 2017-01-06 20:58:14 -05:00
Ludovic Marcotte 46261d61ff (fix) make sure to bump LAST-MODIFIED to trigger all auto-scheduling code 2017-01-06 20:58:14 -05:00
Ludovic Marcotte d2952f1c91 (fix) disabled bias computation for now 2017-01-06 20:58:14 -05:00
Ludovic Marcotte f10b3e8be0 Updated NEWS 2017-01-06 20:58:14 -05:00
Ludovic Marcotte 7837343383 (fix) fix events in floating time during CalDAV's PUT operation (fixes #2865) 2017-01-06 20:58:14 -05:00
Ludovic Marcotte 22acfc943c Updated NEWS 2017-01-06 20:58:14 -05:00
Ludovic Marcotte daad202e50 (fix) provide correct error response to EAS client when sending big mails (fixes #3956) 2017-01-06 20:58:14 -05:00
Ludovic Marcotte a188b5132a Updated NEWS 2017-01-06 20:58:13 -05:00
Ludovic Marcotte 56b92307b5 (fix) handle semicolon in value during LDIF import (fixes #1760) 2017-01-06 20:58:13 -05:00
Ludovic Marcotte a479356fbf Updated NEWS 2017-01-06 20:58:13 -05:00
Ludovic Marcotte 8166f48d10 (fix) small CSS fix to allow scrolling in the attachment menu (fixes #3413) 2017-01-06 20:58:13 -05:00
Ludovic Marcotte a9eecd76b3 Updated NEWS 2017-01-06 20:58:13 -05:00
Ludovic Marcotte f39e4e880e (fix) handle URI in vCard photos (fixes #2683) 2017-01-06 20:58:13 -05:00
Ludovic Marcotte 399dad7d23 Updated NEWS 2017-01-06 20:58:13 -05:00
Ludovic Marcotte 1088b027a7 (feat) added photo support for LDIF import (fixes #1084) 2017-01-06 20:58:12 -05:00
Ludovic Marcotte baa9057fd6 Updated NEWS 2017-01-06 20:58:12 -05:00
Ludovic Marcotte 90762689cf (fix) add support for "other" addresses (fixes #3966) 2017-01-06 20:58:12 -05:00
Ludovic Marcotte 4c979e3f14 (fix) avoid trying to parse empty request (fixes #3969) 2017-01-06 20:58:12 -05:00
Ludovic Marcotte d91d5b7a2d (fix) properly escape values (fixes #3241) 2017-01-06 20:58:12 -05:00
Ludovic Marcotte 617fcbbf19 (fix) set a max-height so we can scroll in the attendees list (fixes #3666) 2017-01-06 20:58:12 -05:00
Ludovic Marcotte b3741e65c8 Updated NEWS 2017-01-06 20:58:12 -05:00
Ludovic Marcotte 81df371e9f (feat) added new SOGoMaximumMessageSizeLimit config parameter (fixes #3510) 2017-01-06 20:58:11 -05:00
Ludovic Marcotte c4c1e87612 Updated NEWS 2017-01-06 20:58:11 -05:00
Ludovic Marcotte 4f9d514c2f (fix) properly honor "include in freebusy" (fixes #3354) 2017-01-06 20:58:11 -05:00
Ludovic Marcotte 7a0908c34a Updates NEWS 2017-01-06 20:58:11 -05:00
Ludovic Marcotte ced9369623 (fix) do not decode from hex the event's UID (fixes #3965) 2017-01-06 20:58:11 -05:00
Ludovic Marcotte aba24c05fa (fix) also use the filter when doing DN lookups (fixes #2253) 2017-01-06 20:58:11 -05:00
Ludovic Marcotte 0db668a0ea Updated NEWS 2017-01-06 20:58:11 -05:00
Ludovic Marcotte d53f477c8d (fix) append .ics extension if not present when importing events (fixes #2308) 2017-01-06 20:58:10 -05:00
Ludovic Marcotte 0b243987e0 Updated NEWS 2017-01-06 20:58:10 -05:00
Ludovic Marcotte 6bf26d45b9 (feat) handle alarms for tasks (fixes #3964) 2017-01-06 20:58:10 -05:00
Ludovic Marcotte 64b72969d3 Updated NEWS 2017-01-06 20:58:10 -05:00
Ludovic Marcotte 727c7ed89f (fix) use the source's domain if none is defined (fixes #3523) 2017-01-06 20:58:10 -05:00
Ludovic Marcotte 3484cd570c (fix) avoid double encoding (fixes #3960) 2017-01-06 20:58:10 -05:00
Ludovic Marcotte b9b8983343 (fix) sage-guard against empty rrule 2017-01-06 20:58:10 -05:00
Ludovic Marcotte 9c1f36d615 Updated NEWS 2017-01-06 20:58:09 -05:00
Ludovic Marcotte ff43324644 (fix) 30 mins offset in FB 2017-01-06 20:58:09 -05:00
Ludovic Marcotte ef32b0c277 (fix) return a 404 for public user 2017-01-06 20:58:09 -05:00
Ludovic Marcotte da3c68c708 Updated NEWS 2017-01-06 20:58:09 -05:00
Ludovic Marcotte 3d7071d018 (fix) return login page for unknown users (fixes #2135) 2017-01-06 20:58:09 -05:00
Ludovic Marcotte 0d6c6bb425 Updated NEWS 2017-01-06 20:58:09 -05:00
Ludovic Marcotte 60819d8233 (fix) correctly block if fail count is within interval (fixes #2850) 2017-01-06 20:58:08 -05:00
Ludovic Marcotte daadc6df69 Updated NEWS 2017-01-06 20:58:08 -05:00
Ludovic Marcotte 848201850a (fix) properly skip folders we don't want (fixes #3943) 2017-01-06 20:58:08 -05:00
Ludovic Marcotte 6649d7101e (fix) make sure we safely escape all chars 2017-01-06 20:58:08 -05:00
Francis Lachapelle 3a96b3b315 (js) Update jQuery (1.12.4) and jQuery-UI (1.11.4)
This fixes the issue of attaching a file to a draft by drag'n'drop.
2017-01-06 20:58:08 -05:00
Ludovic Marcotte cbcc942e73 (fix) prevent using localhost on additional IMAP accounts 2017-01-06 20:58:08 -05:00
Ludovic Marcotte 5433cf19da (fix) properly set interval for monthly recurring events using EAS 2017-01-06 20:58:07 -05:00
Ludovic Marcotte 26bfbcf083 Updated NEWS 2017-01-06 20:58:07 -05:00
Ludovic Marcotte 914f37c3b5 (fix) properly escape all GAL responses (fixes #3923) 2017-01-06 20:58:07 -05:00
Francis Lachapelle d4a4e49521 Add handling of BYSETPOS for BYDAY in repeat rule 2017-01-06 20:58:07 -05:00
Francis Lachapelle a0e7e9d24e Fix MSExchangeFreeBusySOAPRequest.wod 2017-01-06 20:58:07 -05:00
extrafu 52a3508479 Merge pull request #231 from inverse-inc/revert-224-maint
Revert "Fixup empty calendars, sogod crashing when it tries to call"
2016-12-30 10:06:55 -05:00
extrafu 3a33b465c8 Revert "Fixup empty calendars, sogod crashing when it tries to call" 2016-12-30 10:06:47 -05:00
extrafu 559bdf15a8 Merge pull request #224 from buzzdeee/maint
Fixup empty calendars, sogod crashing when it tries to call
2016-12-30 10:06:30 -05:00
Sebastian Reitenbach f3aa717570 Fixup empty calendars, sogod crashing when it tries to call
stringByEscapingHTMLString on NSNull objects. Those happen
to be there when not all fields of the calendar are filled
in. Leading to errors like:

ERROR(-[NSNull(misc) forwardInvocation:]): called selector stringByEscapingHTMLString on NSNull !
and subsequent crashes on the instance serving that request.
2016-11-02 08:17:31 +01:00
14 changed files with 3395 additions and 124 deletions

No files matched your search

+40 -2
View File
@@ -34,6 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSString.h>
static NSArray *asElementArray = nil;
static NSArray *considerAsSameArray = nil;
@implementation NGDOMElement (ActiveSync)
@@ -101,7 +102,44 @@ static NSArray *asElementArray = nil;
int i, count;
if (!asElementArray)
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", @"Category", @"Exception", nil];
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", @"Category", @"Exception", @"Add", @"Delete", nil];
// FIXME
/* if the client sends
<attachments>
<add>
...
</add>
<add>
...
</add>
</attachments>
the result is a NSarray i.e. {add1; add2; ...}
if the client sends
<attachments>
<add>
...
</add>
<add>
...
</add>
<delete>
...
</delete>
<delete>
...
</delete>
</attachments>
the result is a NSDictionary ie. Add = { }; Delete = { }; the dictionary would contain only one entry for add
*/
if (!considerAsSameArray)
considerAsSameArray = [[NSArray alloc] initWithObjects: @"Add", @"Delete", nil];
data = [NSMutableDictionary dictionary];
@@ -151,7 +189,7 @@ static NSArray *asElementArray = nil;
if (!innerTag)
innerTag = [innerElement tagName];
if ([innerTag isEqualToString: [innerElement tagName]])
if ([innerTag isEqualToString: [innerElement tagName]] || [considerAsSameArray containsObject: innerTag])
{
if ([(id)innerElement isTextNode])
[innerElements addObject: [(NGDOMElement *)innerElement textValue]];
+34 -7
View File
@@ -103,7 +103,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ((o = [n flattenedValueAtIndex: 1 forKey: @""]))
[s appendFormat: @"<FirstName xmlns=\"Contacts:\">%@</FirstName>", [o activeSyncRepresentationInContext: context]];
if ((o = [n flattenedValueAtIndex: 2 forKey: @""]))
[s appendFormat: @"<MiddleName xmlns=\"Contacts:\">%@</MiddleName>", [o activeSyncRepresentationInContext: context]];
if ((o = [n flattenedValueAtIndex: 3 forKey: @""]))
[s appendFormat: @"<Title xmlns=\"Contacts:\">%@</Title>", [o activeSyncRepresentationInContext: context]];
if ((o = [n flattenedValueAtIndex: 4 forKey: @""]))
[s appendFormat: @"<Suffix xmlns=\"Contacts:\">%@</Suffix>", [o activeSyncRepresentationInContext: context]];
if ((o = [self fn]))
[s appendFormat: @"<FileAs xmlns=\"Contacts:\">%@</FileAs>", [o activeSyncRepresentationInContext: context]];
if ((o = [self workCompany]))
[s appendFormat: @"<CompanyName xmlns=\"Contacts:\">%@</CompanyName>", [o activeSyncRepresentationInContext: context]];
@@ -306,8 +318,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
CardElement *element;
NSMutableArray *addressLines, *other_addresses;
id o;
id o, l, m, f, p, s;
l = m = f = p = s = nil;
// Contact's note
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setNote: o];
@@ -533,10 +547,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ((o = [theValues objectForKey: @"FileAs"]) || ![self _isGhosted: @"FileAs" inContext: context])
[self setFn: [theValues objectForKey: @"FileAs"]];
[self setNWithFamily: [theValues objectForKey: @"LastName"]
given: [theValues objectForKey: @"FirstName"]
additional: nil prefixes: nil suffixes: nil];
if ((o = [theValues objectForKey: @"LastName"]) || ![self _isGhosted: @"LastName" inContext: context])
l = o ? o : @"";
if ((o = [theValues objectForKey: @"FirstName"]) || ![self _isGhosted: @"FirstName" inContext: context])
f = o ? o : @"";
if ((o = [theValues objectForKey: @"MiddleName"]) || ![self _isGhosted: @"MiddleName" inContext: context])
m = o ? o : @"";
if ((o = [theValues objectForKey: @"Title"]) || ![self _isGhosted: @"Title" inContext: context])
p = o ? o : @"";
if ((o = [theValues objectForKey: @"Suffix"]) || ![self _isGhosted: @"Suffix" inContext: context])
s = o ? o : @"";
[self setNWithFamily: l given: f additional: m prefixes: p suffixes: s];
// IM information
if ((o = [theValues objectForKey: @"IMAddress"]) || ![self _isGhosted: @"IMAddress" inContext: context])
[[self uniqueChildWithTag: @"x-aim"]
+3 -3
View File
@@ -117,7 +117,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
[self errorWithFormat: @"wbxml2xmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
[self errorWithFormat: @"wbxml2xml failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
return nil;
}
@@ -150,7 +150,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
[self logWithFormat: @"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
[self logWithFormat: @"xml2wbxml failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
return nil;
}
@@ -165,7 +165,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
[self errorWithFormat: @"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
[self errorWithFormat: @"xml2wbxml failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
free(wbxml);
wbxml_conv_xml2wbxml_destroy(conv);
+1 -1
View File
@@ -237,7 +237,7 @@ static NSArray *easCommandParameters = nil;
// parameter_code 7 == Options
// http://msdn.microsoft.com/en-us/library/ee237789(v=exchg.80).aspx
if (parameter_code == 7)
if (parameter_code == 7 && ! [parameterValue isEqualToString: @"\000"] )
[components addObject: [NSString stringWithFormat: @"%@=%@", [easCommandParameters objectAtIndex: parameter_code],
([parameterValue isEqualToString: @"\001"]) ? @"SaveInSent" : @"AcceptMultiPart"]];
else
+109 -25
View File
@@ -189,7 +189,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
processIdentifierInCache = [[self globalMetadataForDevice] objectForKey: key];
// Don't update the cache if another request is processing the same collection.
// I case of a merged folder we have to check personal folder's lock.
// In case of a merged folder we have to check personal folder's lock.
a = [key componentsSeparatedByString: @"/"];
pkey = [NSString stringWithFormat: @"%@/personal", [a objectAtIndex:0]];
@@ -346,8 +346,34 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
anAddition = [additions objectAtIndex: i];
is_new = YES;
clientId = [[(id)[anAddition getElementsByTagName: @"ClientId"] lastObject] textValue];
/*
FIXME
<Add>
<ClientId>338</ClientId>
<ApplicationData>
<To xmlns="Email:">&lt;foot@bar.com&gt;</To>
<Cc xmlns="Email:"/>
<Subject xmlns="Email:">test</Subject>
<Reply-To xmlns="Email:">foo@bar.com</Reply-To>
<Importance xmlns="Email:">1</Importance>
<Read xmlns="Email:">1</Read>
<Attachments xmlns="AirSyncBase:">
<Add>
<ClientId>152-ab557915-8451-49a7-a9c6-a9ac153021ad</ClientId>
-> lastObject returns the ClientId in Attachments element -> try with objectAtIndex: 0 -> is this correct?
*/
//clientId = [[(id)[anAddition getElementsByTagName: @"ClientId"] lastObject] textValue];
clientId = [[(id)[anAddition getElementsByTagName: @"ClientId"] objectAtIndex: 0] textValue];
allValues = [NSMutableDictionary dictionaryWithDictionary: [[(id)[anAddition getElementsByTagName: @"ApplicationData"] lastObject] applicationData]];
// FIXME: ignore the <Add> elements of Attachemnts - above (id)[theDocumentElement getElementsByTagName: @"Add"]; return any <Add> elements instead of only the direct childs of the <commands> element ..
if (![allValues count])
continue;
switch (theFolderType)
{
@@ -402,23 +428,39 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
case ActiveSyncMailFolder:
default:
{
// Support SMS to Exchange eMail sync.
// Support Draft Mail/SMS to Exchange eMail sync.
NSString *serverId;
NSMutableString *s;
NSDictionary *result;
NSNumber *modseq;
serverId = nil;
s = [NSMutableString string];
sogoObject = [SOGoMailObject objectWithName: @"Mail" inContainer: theCollection];
serverId = [sogoObject storeMail: allValues inContext: context];
serverId = [sogoObject storeMail: allValues inBuffer: s inContext: context];
if (serverId)
{
sogoObject = [theCollection lookupName: serverId inContext: context acquire: 0];
[sogoObject takeActiveSyncValues: allValues inContext: context];
// Everything is fine, lets generate our response
// serverId = clientId - There is no furhter processing after adding the SMS to the inbox.
[theBuffer appendString: @"<Add>"];
[theBuffer appendFormat: @"<ClientId>%@</ClientId>", clientId];
[theBuffer appendFormat: @"<ServerId>%@</ServerId>", serverId];
[theBuffer appendFormat: @"<Status>%d</Status>", 1];
[theBuffer appendString: s];
[theBuffer appendString: @"</Add>"];
folderMetadata = [self _folderMetadataForKey: [self _getNameInCache: theCollection withType: theFolderType]];
syncCache = [folderMetadata objectForKey: @"SyncCache"];
[syncCache setObject: @"0" forKey: serverId];
result = [sogoObject fetchParts: [NSArray arrayWithObject: @"MODSEQ"]];
modseq = [[[result objectForKey: @"RawResponse"] objectForKey: @"fetch"] objectForKey: @"modseq"];
[syncCache setObject: [modseq stringValue] forKey: serverId];
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
continue;
@@ -688,6 +730,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NSDictionary *result;
NSNumber *modseq;
// Process an update to a Draft Mail.
if ([allChanges objectForKey: @"Body"])
{
NSString *serverId;
NSMutableString *s;
serverId = nil;
s = [NSMutableString string];
serverId = [sogoObject storeMail: allChanges inBuffer: s inContext: context];
if (serverId)
{
// we delete the original email - next sync will update the client with the new mail
[sogoObject delete];
sogoObject = [theCollection lookupName: serverId inContext: context acquire: 0];
}
}
[sogoObject takeActiveSyncValues: allChanges inContext: context];
result = [sogoObject fetchParts: [NSArray arrayWithObject: @"MODSEQ"]];
@@ -702,7 +762,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[theBuffer appendString: @"<Change>"];
[theBuffer appendFormat: @"<ServerId>%@</ServerId>", origServerId];
[theBuffer appendFormat: @"<Status>%d</Status>", 1];
// A body element is sent only for draft mails - status 8 will delete the mail on the client - the next sync update fetch the new mail
if ([allChanges objectForKey: @"Body"] && theFolderType == ActiveSyncMailFolder)
[theBuffer appendFormat: @"<Status>%d</Status>", 8];
else
[theBuffer appendFormat: @"<Status>%d</Status>", 1];
[theBuffer appendString: @"</Change>"];
}
}
@@ -824,7 +890,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// FIXME: handle errors here
if (deletesAsMoves && theFolderType == ActiveSyncMailFolder)
{
[(SOGoMailFolder *)[sogoObject container] deleteUIDs: [NSArray arrayWithObjects: serverId, nil] useTrashFolder: &useTrash inContext: context];
[(SOGoMailFolder *)[sogoObject container] deleteUIDs: [NSArray arrayWithObjects: serverId, nil]
useTrashFolder: &useTrash
inContext: context];
}
else if (theFolderType == ActiveSyncEventFolder || theFolderType == ActiveSyncTaskFolder || theFolderType == ActiveSyncContactFolder)
{
@@ -1401,7 +1469,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
}
allMessages = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType initialLoad: initialLoadInProgress];
allMessages = [theCollection syncTokenFieldsWithProperties: nil
matchingSyncToken: theSyncKey
fromDate: theFilterType
initialLoad: initialLoadInProgress];
max = [allMessages count];
allCacheObjects = [NSMutableArray array];
@@ -2525,15 +2596,41 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//[output appendFormat: @"<Status>%d</Status>", 14];
}
[output appendString: @"<Collections>"];
s = nil;
// We enter our loop detection change
for (i = 0; i < (heartbeatInterval/internalInterval); i++)
{
// Terminate the process if we need to
if ([self easShouldTerminate])
break;
// We first check of any of the collections we want to sync are already
// in an other sync process. If that's the case, we do not do anything
// and we return immediately. So we'll let the other sync process terminate
for (j = 0; j < [allCollections count]; j++)
{
aCollection = [allCollections objectAtIndex: j];
globalMetadata = [self globalMetadataForDevice];
key = [NSString stringWithFormat: @"SyncRequest+%@", [[[(id)[aCollection getElementsByTagName: @"CollectionId"] lastObject] textValue] stringByUnescapingURL]];
if (!([[globalMetadata objectForKey: key] isEqual: processIdentifier]))
{
if (debugOn)
[self logWithFormat: @"EAS - Discard response %@", [self globalMetadataForDevice]];
[output appendString: @"<Status>13</Status>"];
[output appendString: @"</Sync>"];
d = [[output dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
[theResponse setContent: d];
RELEASE(output);
return;
}
}
// We're good to go to sync the collections
s = [NSMutableString string];
for (j = 0; j < [allCollections count]; j++)
@@ -2545,21 +2642,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
changeDetected: &changeDetected
maxSyncResponseSize: maxSyncResponseSize];
// Don't return a response if another Sync is waiting.
globalMetadata = [self globalMetadataForDevice];
key = [NSString stringWithFormat: @"SyncRequest+%@", [[[(id)[aCollection getElementsByTagName: @"CollectionId"] lastObject] textValue] stringByUnescapingURL]];
if (!([[globalMetadata objectForKey: key] isEqual: processIdentifier]))
{
if (debugOn)
[self logWithFormat: @"EAS - Discard response %@", [self globalMetadataForDevice]];
[theResponse setStatus: 503];
RELEASE(output);
return;
}
if ((maxSyncResponseSize > 0 && [s length] >= maxSyncResponseSize))
break;
}
@@ -2616,6 +2698,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
if (changeDetected || [[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"] || [[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"12.0"])
{
[output appendString: @"<Collections>"];
// We always return the last generated response.
// If we only return <Sync><Collections/></Sync>,
// iOS powered devices will simply crash.
+162 -22
View File
@@ -290,6 +290,39 @@ void handle_eas_terminate(int signum)
return theIdToTranslate;
}
//
//
//
- (SOGoAppointmentObject *) _eventObjectWithUID: (NSString *) uid
{
SOGoAppointmentFolder *folder;
SOGoAppointmentObject *eventObject;
NSArray *folders;
NSEnumerator *e;
NSString *cname;
eventObject = nil;
folders = [[[context activeUser] calendarsFolderInContext: context] subFolders];
e = [folders objectEnumerator];
while (eventObject == nil && (folder = [e nextObject]))
{
cname = [folder resourceNameForEventUID: uid];
if (cname)
{
eventObject = [folder lookupName: cname inContext: context
acquire: NO];
if ([eventObject isKindOfClass: [NSException class]])
eventObject = nil;
}
}
if (eventObject)
return eventObject;
else
return [NSException exceptionWithHTTPStatus:404 /* Not Found */];
}
//
//
//
@@ -313,7 +346,9 @@ void handle_eas_terminate(int signum)
case ActiveSyncEventFolder:
case ActiveSyncTaskFolder:
{
collection = [[[[context activeUser] homeFolderInContext: context] lookupName: @"Calendar" inContext: context acquire: NO] lookupName: theCollectionId inContext: context acquire: NO];
collection = [[[context activeUser] homeFolderInContext: context] lookupName: @"Calendar" inContext: context acquire: NO];
if (![collection isKindOfClass: [NSException class]])
collection = [collection lookupName: theCollectionId inContext: context acquire: NO];
if (!collection || ([collection isKindOfClass: [NSException class]]))
collection = nil;
}
@@ -643,6 +678,12 @@ void handle_eas_terminate(int signum)
SOGoMailFolder *folderToUpdate;
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
if ([accountsFolder isKindOfClass: [NSException class]])
{
[theResponse setStatus: 403];
[self logWithFormat: @"Mail - Forbidden access for user %@", [[context activeUser] loginInDomain]];
return;
}
currentFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
folderToUpdate = [currentFolder lookupName: [NSString stringWithFormat: @"folder%@", serverId]
@@ -688,6 +729,12 @@ void handle_eas_terminate(int signum)
NSString *nameInCache;
appointmentFolders = [userFolder privateCalendars: @"Calendar" inContext: context];
if ([appointmentFolders isKindOfClass: [NSException class]])
{
[theResponse setStatus: 403];
[self logWithFormat: @"Calendar - Forbidden access for user %@", [[context activeUser] loginInDomain]];
return;
}
folderToUpdate = [appointmentFolders lookupName: [NSString stringWithFormat: @"%@", serverId]
inContext: context
@@ -798,7 +845,7 @@ void handle_eas_terminate(int signum)
- (void) processFolderSync: (id <DOMElement>) theDocumentElement
inResponse: (WOResponse *) theResponse
{
NSString *key, *cKey, *nkey, *name, *serverId, *parentId, *nameInCache, *personalFolderName, *syncKey, *folderType, *operation;
NSString *key, *cKey, *nkey, *name, *serverId, *parentId, *nameInCache, *personalFolderName, *syncKey, *folderType, *operation, *parent;
NSMutableDictionary *cachedGUIDs, *metadata;
NSMutableArray *folders, *processedFolders, *allFoldersMetadata;
NSDictionary *folderMetadata, *imapGUIDs;
@@ -814,17 +861,18 @@ void handle_eas_terminate(int signum)
int status, command_count, i, type, fi, count;
BOOL first_sync;
metadata = [self globalMetadataForDevice];
syncKey = [[(id)[theDocumentElement getElementsByTagName: @"SyncKey"] lastObject] textValue];
s = [NSMutableString string];
personalFolderName = [[[context activeUser] personalCalendarFolderInContext: context] nameInContainer];
first_sync = NO;
status = 1;
command_count = 0;
personalFolderName = nil;
commands = [NSMutableString string];
processedFolders = [NSMutableArray array];
s = [NSMutableString string];
metadata = [self globalMetadataForDevice];
syncKey = [[(id)[theDocumentElement getElementsByTagName: @"SyncKey"] lastObject] textValue];
if ([[context activeUser] canAccessModule: @"Calendar"])
personalFolderName = [[[context activeUser] personalCalendarFolderInContext: context] nameInContainer];
[s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
[s appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
@@ -1099,14 +1147,16 @@ void handle_eas_terminate(int signum)
[[o properties] removeObjectForKey: @"CleanoutDate"];
[o save];
command_count++;
}
}
folders = [NSMutableArray array];
// We get the list of subscribed calendars
folders = [[[[[context activeUser] homeFolderInContext: context] lookupName: @"Calendar" inContext: context acquire: NO] subFolders] mutableCopy];
[folders autorelease];
if ([personalFolderName length])
[folders addObjectsFromArray: [[[[context activeUser] homeFolderInContext: context] lookupName: @"Calendar" inContext: context acquire: NO] subFolders]];
// We get the list of subscribed address books
[folders addObjectsFromArray: [[[[context activeUser] homeFolderInContext: context] lookupName: @"Contacts" inContext: context acquire: NO] subFolders]];
@@ -1166,9 +1216,19 @@ void handle_eas_terminate(int signum)
{
if ([[folders objectAtIndex:fi] isKindOfClass: [SOGoAppointmentFolder class]])
{
type = ([[[folders objectAtIndex:fi] nameInContainer] isEqualToString: personalFolderName] ? 8 : 13);
if ([[[folders objectAtIndex:fi] nameInContainer] isEqualToString: personalFolderName])
{
type = 8;
parent = @"0";
}
else
{
type = 13;
parent = [NSString stringWithFormat: @"vevent/%@",personalFolderName];
}
[commands appendFormat: @"<%@><ServerId>%@</ServerId><ParentId>%@</ParentId><DisplayName>%@</DisplayName><Type>%d</Type></%@>", operation,
[name stringByEscapingURL], @"0", [[[folders objectAtIndex:fi] displayName] activeSyncRepresentationInContext: context], type, operation];
[name stringByEscapingURL], [parent stringByEscapingURL], [[[folders objectAtIndex:fi] displayName] activeSyncRepresentationInContext: context], type, operation];
command_count++;
@@ -1176,7 +1236,17 @@ void handle_eas_terminate(int signum)
[o save];
name = [NSString stringWithFormat: @"vtodo/%@", [[folders objectAtIndex:fi] nameInContainer]];
type = ([[[folders objectAtIndex:fi] nameInContainer] isEqualToString: personalFolderName] ? 7 : 15);
if ([[[folders objectAtIndex:fi] nameInContainer] isEqualToString: personalFolderName])
{
type = 7;
parent = @"0";
}
else
{
type = 15;
parent = [NSString stringWithFormat: @"vtodo/%@",personalFolderName];
}
// We always sync the "Default Tasks folder" (7). For "User-created Tasks folder" (15), we check if we include it in
// the sync process by checking if "Show tasks" is enabled. If not, we skip the folder entirely.
@@ -1184,7 +1254,7 @@ void handle_eas_terminate(int signum)
(type == 15 && [[folders objectAtIndex: fi] showCalendarTasks]))
{
[commands appendFormat: @"<%@><ServerId>%@</ServerId><ParentId>%@</ParentId><DisplayName>%@</DisplayName><Type>%d</Type></%@>", operation,
[name stringByEscapingURL], @"0", [[[folders objectAtIndex:fi] displayName] activeSyncRepresentationInContext: context], type, operation];
[name stringByEscapingURL], [parent stringByEscapingURL], [[[folders objectAtIndex:fi] displayName] activeSyncRepresentationInContext: context], type, operation];
command_count++;
@@ -1219,9 +1289,19 @@ void handle_eas_terminate(int signum)
}
else if ([[folders objectAtIndex:fi] isKindOfClass: [SOGoContactGCSFolder class]])
{
type = ([[[folders objectAtIndex:fi] nameInContainer] isEqualToString: personalFolderName] ? 9 : 14);
if ([[[folders objectAtIndex:fi] nameInContainer] isEqualToString: personalFolderName])
{
type = 9;
parent = @"0";
}
else
{
type = 14;
parent = [NSString stringWithFormat: @"vcard/%@",personalFolderName];
}
[commands appendFormat: @"<%@><ServerId>%@</ServerId><ParentId>%@</ParentId><DisplayName>%@</DisplayName><Type>%d</Type></%@>", operation,
[name stringByEscapingURL], @"0", [[[folders objectAtIndex:fi] displayName] activeSyncRepresentationInContext: context], type, operation];
[name stringByEscapingURL], [parent stringByEscapingURL], [[[folders objectAtIndex:fi] displayName] activeSyncRepresentationInContext: context], type, operation];
command_count++;
@@ -1848,6 +1928,9 @@ void handle_eas_terminate(int signum)
inContext: context
acquire: NO];
if ([appointmentObject isKindOfClass: [NSException class]])
appointmentObject = [self _eventObjectWithUID:[event uid]];
// Create the appointment if it is not added to calendar yet
if ([appointmentObject isKindOfClass: [NSException class]])
{
@@ -2416,6 +2499,11 @@ void handle_eas_terminate(int signum)
realCollectionId = [collectionId realCollectionIdWithFolderType: &folderType];
realCollectionId = [self globallyUniqueIDToIMAPFolderName: realCollectionId type: folderType];
// We avoid loading the cache metadata if we can't get the real connection. This can happen
// for example if the IMAP server is down. We just skip the folder for now.
if (!realCollectionId)
continue;
if (folderType == ActiveSyncMailFolder)
folderMetadata = [self _folderMetadataForKey: [NSString stringWithFormat: @"folder%@", [[collectionId stringByUnescapingURL] substringFromIndex:5]]];
else
@@ -2857,7 +2945,7 @@ void handle_eas_terminate(int signum)
{
currentFolder = [systemSources objectForKey: [allKeys objectAtIndex: i]];
allContacts = [currentFolder lookupContactsWithFilter: query
onCriteria: @"name_or_address"
onCriteria: nil
sortBy: @"c_cn"
ordering: NSOrderedAscending
inDomain: [[context activeUser] domain]];
@@ -3026,7 +3114,7 @@ void handle_eas_terminate(int signum)
- (void) processSearchMailbox: (id <DOMElement>) theDocumentElement
inResponse: (WOResponse *) theResponse
{
NSString *folderId, *realCollectionId, *itemId;
NSString *folderId, *realCollectionId, *itemId, *bodyPreferenceType, *mimeSupport;
NSMutableArray *folderIdentifiers;
SOGoMailAccounts *accountsFolder;
SOGoMailAccount *accountFolder;
@@ -3050,12 +3138,20 @@ void handle_eas_terminate(int signum)
return;
}
bodyPreferenceType = [[(id)[[(id)[theDocumentElement getElementsByTagName: @"BodyPreference"] lastObject] getElementsByTagName: @"Type"] lastObject] textValue];
[context setObject: bodyPreferenceType forKey: @"BodyPreferenceType"];
mimeSupport = [[(id)[theDocumentElement getElementsByTagName: @"MIMESupport"] lastObject] textValue];
[context setObject: mimeSupport forKey: @"MIMESupport"];
[context setObject: @"8" forKey: @"MIMETruncation"];
// FIXME: support more than one CollectionId tag + DeepTraversal
folderId = [[(id)[[(id)[theDocumentElement getElementsByTagName: @"Query"] lastObject] getElementsByTagName: @"CollectionId"] lastObject] textValue];
folderIdentifiers = [NSMutableArray array];
// Android 6 will send search requests with no collection ID - so we search in all folders.
if (!folderId)
// Outlook Mobile App sends search requests with CollectionId=0 - We treat this as an all-folder-search.
if (!folderId || [folderId isEqualToString: @"0"])
{
NSArray *foldersInCache;
SOGoCacheGCSObject *o;
@@ -3123,7 +3219,7 @@ void handle_eas_terminate(int signum)
[s appendFormat: @"<LongId>%@+%@</LongId>", folderId, itemId];
[s appendFormat: @"<CollectionId xmlns=\"AirSyncBase:\">%@</CollectionId>", folderId];
[s appendString: @"<Properties>"];
[s appendFormat: [mailObject activeSyncRepresentationInContext: context]];
[s appendString: [mailObject activeSyncRepresentationInContext: context]];
[s appendString: @"</Properties>"];
[s appendFormat: @"</Result>"];
}
@@ -3179,7 +3275,7 @@ void handle_eas_terminate(int signum)
NSException *error;
NSString *from;
authenticator = [SOGoDAVAuthenticator sharedSOGoDAVAuthenticator];
authenticator = [[context activeUser] authenticatorInContext: context];
dd = [[context activeUser] domainDefaults];
// We generate the Sender
@@ -3573,6 +3669,48 @@ void handle_eas_terminate(int signum)
}
}
if ([(id)[[(id)[theDocumentElement getElementsByTagName: @"UserInformation"] lastObject] getElementsByTagName: @"Get"] lastObject])
{
NSArray *identities;
int i;
identities = [[context activeUser] allIdentities];
[s appendString: @"<UserInformation>"];
[s appendString: @"<Get>"];
if ([[context objectForKey: @"ASProtocolVersion"] floatValue] >= 14.1)
{
[s appendString: @"<Accounts>"];
[s appendString: @"<Account>"];
[s appendFormat: @"<UserDisplayName>%@</UserDisplayName>", [[[identities objectAtIndex: 0] objectForKey: @"fullName"] activeSyncRepresentationInContext: context] ];
}
[s appendString: @"<EmailAddresses>"];
if ([[context objectForKey: @"ASProtocolVersion"] floatValue] >= 14.1)
[s appendFormat: @"<PrimarySmtpAddress>%@</PrimarySmtpAddress>", [[[identities objectAtIndex: 0] objectForKey: @"email"] activeSyncRepresentationInContext: context] ];
else
[s appendFormat: @"<SmtpAddress>%@</SmtpAddress>", [[[identities objectAtIndex: 0] objectForKey: @"email"] activeSyncRepresentationInContext: context] ];
if ([identities count] > 1)
{
for (i = 1; i < [identities count]; i++)
[s appendFormat: @"<SmtpAddress>%@</SmtpAddress>", [[[identities objectAtIndex: i] objectForKey: @"email"] activeSyncRepresentationInContext: context] ];
}
[s appendString: @"</EmailAddresses>"];
if ([[context objectForKey: @"ASProtocolVersion"] floatValue] >= 14.1)
{
[s appendString: @"</Account>"];
[s appendString: @"</Accounts>"];
}
[s appendString: @"</Get>"];
[s appendString: @"</UserInformation>"];
}
[s appendString: @"</Settings>"];
d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
@@ -3891,6 +4029,8 @@ void handle_eas_terminate(int signum)
[map setObject: [currentAttachment objectForKey: @"mimetype"] forKey: @"content-type"];
[map setObject: [currentAttachment objectForKey: @"encoding"] forKey: @"content-transfer-encoding"];
[map addObject: [NSString stringWithFormat: @"attachment; filename=\"%@\"", [currentAttachment objectForKey: @"filename"]] forKey: @"content-disposition"];
if ([[currentAttachment objectForKey: @"bodyId"] length])
[map setObject: [currentAttachment objectForKey: @"bodyId"] forKey: @"content-id"];
bodyPart = [[[NGMimeBodyPart alloc] initWithHeader: map] autorelease];
fdata = [[NGMimeFileData alloc] initWithBytes:[bodydata bytes] length:[bodydata length]];
+1
View File
@@ -43,6 +43,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
- (NSString *) storeMail: (NSDictionary *) theValues
inBuffer: (NSMutableString *) theBuffer
inContext: (WOContext *) _context;
@end
+250 -25
View File
@@ -36,6 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSString.h>
#import <Foundation/NSCharacterSet.h>
#import <Foundation/NSTimeZone.h>
#import <Foundation/NSValue.h>
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalDateTime.h>
@@ -60,6 +61,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGMime/NGMimeFileData.h>
#import <NGMime/NGMimeMultipartBody.h>
#import <NGMime/NGMimeType.h>
#import <NGMime/NGMimeHeaderFields.h>
#import <NGMail/NGMimeMessageParser.h>
#import <NGMail/NGMimeMessage.h>
#import <NGMail/NGMimeMessageGenerator.h>
@@ -68,6 +70,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoUserFolder.h>
#import <SOGo/NSArray+Utilities.h>
#include "iCalTimeZone+ActiveSync.h"
#include "NSData+ActiveSync.h"
@@ -256,6 +259,68 @@ struct GlobalObjectId {
return rc;
}
//
//
//
- (NSString *) _personalNameFrom: (NSArray *) enveloppeAddresses
{
NGImap4EnvelopeAddress *address;
NSString *email, *rc, *name;
NSMutableArray *addresses;
int i, max;
rc = nil;
max = [enveloppeAddresses count];
if (max > 0)
{
addresses = [NSMutableArray array];
for (i = 0; i < max; i++)
{
address = [enveloppeAddresses objectAtIndex: i];
name = [address personalName];
email = [NSString stringWithFormat: @"%@", (name ? name : [address baseEMail])];
if (email)
[addresses addObject: email];
}
rc = [addresses componentsJoinedByString: @";"];
}
return rc;
}
// Format replyTo
//
// If there are multiple e-mail addresses, they are separated by a semi-colon.
- (NSString *) _replyToAddressesFrom: (NSArray *) enveloppeAddresses
{
NSMutableArray *addresses;
NSString *rc;
NGImap4EnvelopeAddress *address;
NSString *email;
int count, max;
rc = nil;
max = [enveloppeAddresses count];
if (max > 0)
{
addresses = [NSMutableArray array];
for (count = 0; count < max; count++)
{
address = [enveloppeAddresses objectAtIndex: count];
email = [NSString stringWithFormat: @"%@", [address email]];
[addresses addObject: email];
}
rc = [addresses componentsJoinedByString: @"; "];
}
return rc;
}
//
//
//
@@ -392,7 +457,7 @@ struct GlobalObjectId {
body = [thePart body];
if ([body isKindOfClass: [NGMimeMultipartBody class]])
if ([body isKindOfClass: [NGMimeMultipartBody class]] || [body isKindOfClass: [NGMimeMessage class]])
{
[self _sanitizedMIMEPart: body
performed: b];
@@ -444,6 +509,13 @@ struct GlobalObjectId {
RELEASE(fdata);
*b = YES;
}
else if ([body isKindOfClass: [NSData class]])
{
[thePart setHeader: @"base64" forKey: @"content-transfer-encoding"];
[thePart setBody: [body dataByEncodingBase64]];
[thePart setHeader: [NSString stringWithFormat:@"%d", (int)[[thePart body] length]]
forKey: @"content-length"];
}
}
}
@@ -727,7 +799,19 @@ struct GlobalObjectId {
break;
}
return [theContent substringToIndex: i];
// If we didn't find a "space" character search again for &# to avoid
// truncating the content in the middle of a XML entity
if (i < 0)
{
for (i = len-2 ; i >= 0; i--)
{
if ([theContent characterAtIndex: i] == '&' && [theContent characterAtIndex: i+1] == '#')
break;
}
}
if (i >= 0)
return [theContent substringToIndex: i];
}
*wasTruncated = 0;
@@ -836,7 +920,13 @@ struct GlobalObjectId {
// If there are multiple e-mail addresses, they are separated by commas."
value = [self _emailAddressesFrom: [[self envelope] to]];
if (value)
[s appendFormat: @"<To xmlns=\"Email:\">%@</To>", [value activeSyncRepresentationInContext: context]];
{
[s appendFormat: @"<To xmlns=\"Email:\">%@</To>", [value activeSyncRepresentationInContext: context]];
// DisplayTo - If there are multiple display names, they are separated by semi-colons.
value = [self _personalNameFrom: [[self envelope] to]];
if (value)
[s appendFormat: @"<DisplayTo xmlns=\"Email:\">%@</DisplayTo>", [value activeSyncRepresentationInContext: context]];
}
// From
value = [self _emailAddressesFrom: [[self envelope] from]];
@@ -855,10 +945,9 @@ struct GlobalObjectId {
value = [self date];
if (value)
[s appendFormat: @"<DateReceived xmlns=\"Email:\">%@</DateReceived>", [value activeSyncRepresentationInContext: context]];
else
[s appendFormat: @"<DateReceived xmlns=\"Email:\">%@</DateReceived>", [[NSDate date] activeSyncRepresentationInContext: context]];
// DisplayTo
[s appendFormat: @"<DisplayTo xmlns=\"Email:\">%@</DisplayTo>", [[context activeUser] login]];
// Cc - same syntax as the To field
value = [self _emailAddressesFrom: [[self envelope] cc]];
if (value)
@@ -959,7 +1048,7 @@ struct GlobalObjectId {
if ([event startDate])
[s appendFormat: @"<StartTime xmlns=\"Email:\">%@</StartTime>", [[event startDate] activeSyncRepresentationInContext: context]];
if ([event timeStampAsDate])
if ([event timeStampAsDate] && [[event timeStampAsDate] dayOfMonth] > 0 && [[event timeStampAsDate] monthOfYear] > 0)
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event timeStampAsDate] activeSyncRepresentationInContext: context]];
else if ([event created])
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event created] activeSyncRepresentationInContext: context]];
@@ -1040,10 +1129,11 @@ struct GlobalObjectId {
[s appendFormat: @"<ContentClass xmlns=\"Email:\">%@</ContentClass>", @"urn:content-classes:message"];
}
// Reply-To - FIXME
//NSArray *replyTo = [[message objectForKey: @"envelope"] replyTo];
//if ([replyTo count])
// [s appendFormat: @"<Reply-To xmlns=\"Email:\">%@</Reply-To>", [addressFormatter stringForArray: replyTo]];
// ReplyTo
value = [self _replyToAddressesFrom: [self replyToEnvelopeAddresses]];
if (value)
[s appendFormat: @"<Reply-To xmlns=\"Email:\">%@</Reply-To>", [value activeSyncRepresentationInContext: context]];
// InternetCPID - 65001 == UTF-8, we use this all the time for now.
// - 20127 == US-ASCII
@@ -1249,7 +1339,7 @@ struct GlobalObjectId {
{
if ([[value objectForKey: @"bodyId"] length])
{
[s appendFormat: @"<ContentId>%@</ContentId>", [[value objectForKey: @"bodyId"] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<ContentId>%@</ContentId>", [[[value objectForKey: @"bodyId"] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString: @"<>"]] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<IsInline>%d</IsInline>", 1];
}
@@ -1439,18 +1529,22 @@ struct GlobalObjectId {
}
- (NSString *) storeMail: (NSDictionary *) theValues
inBuffer: (NSMutableString *) theBuffer
inContext: (WOContext *) _context
{
NSString *dateReceived, *folder, *s;
NSString *dateReceived, *folder, *s, *serverId, *messageId;
NGMimeMessageGenerator *generator;
NGMimeMessage *bounceMessage;
NGMimeMessage *draftMessage;
NGMimeBodyPart *bodyPart;
NGMimeMultipartBody *body;
NSDictionary *identity;
NGMutableHashMap *map;
NGImap4Client *client;
NSData *message_data;
NSArray *attachmentKeys;
id o, result;
int bodyType;
id o, a, result, attachments;
int bodyType, i;
identity = [[context activeUser] primaryIdentity];
message_data = nil;
@@ -1470,11 +1564,21 @@ struct GlobalObjectId {
map = [[[NGMutableHashMap alloc] initWithCapacity: 1] autorelease];
[map setObject: [NSString stringWithFormat: @"%@ <%@>", [identity objectForKey: @"fullName"], [identity objectForKey: @"email"]] forKey: @"from"];
if ((o = [theValues objectForKey: @"To"]))
[map setObject: o forKey: @"to"];
if ((o = [theValues objectForKey: @"Cc"]))
[map setObject: o forKey: @"cc"];
if ((o = [theValues objectForKey: @"Bcc"]))
[map setObject: o forKey: @"bcc"];
if ((o = [theValues objectForKey: @"Reply-To"]))
[map setObject: o forKey: @"Reply-To"];
if ((o = [theValues objectForKey: @"Subject"]))
[map setObject: o forKey: @"subject"];
[map setObject: o forKey: @"subject"];
o = [[theValues objectForKey: @"DateReceived"] calendarDate];
@@ -1500,17 +1604,114 @@ struct GlobalObjectId {
#endif
[map setObject: dateReceived forKey: @"date"];
[map setObject: [NSString generateMessageID] forKey: @"message-id"];
[map setObject: (bodyType == 1 ? @"text/plain; charset=utf-8" : @"text/html; charset=utf-8")
forKey: @"content-type"];
[map setObject: @"quoted-printable" forKey: @"content-transfer-encoding"];
bounceMessage = [[[NGMimeMessage alloc] initWithHeader: map] autorelease];
messageId = [NSString generateMessageID];
[map setObject: messageId forKey: @"message-id"];
[bounceMessage setBody: [[NSString stringWithFormat: @"%@", [[theValues objectForKey: @"Body"] objectForKey: @"Data"] ] dataUsingEncoding: NSUTF8StringEncoding]];
attachmentKeys = [self fetchFileAttachmentKeys];
if ((attachments = [theValues objectForKey: @"Attachments"]) || [attachmentKeys count])
{
[map setObject: @"multipart/mixed" forKey: @"content-type"];
draftMessage = [[[NGMimeMessage alloc] initWithHeader: map] autorelease];
body = [[[NGMimeMultipartBody alloc] initWithPart: draftMessage] autorelease];
map = [[[NGMutableHashMap alloc] initWithCapacity: 1] autorelease];
[map setObject: (bodyType == 1 ? @"text/plain; charset=utf-8" : @"text/html; charset=utf-8")
forKey: @"content-type"];
[map setObject: @"quoted-printable" forKey: @"content-transfer-encoding"];
bodyPart = [[[NGMimeBodyPart alloc] initWithHeader:map] autorelease];
[bodyPart setBody: [[NSString stringWithFormat: @"%@", [[theValues objectForKey: @"Body"] objectForKey: @"Data"] ] dataUsingEncoding: NSUTF8StringEncoding]];
[body addBodyPart: bodyPart];
// Add attachments from the original mail - skip deletions
if ([attachmentKeys count])
{
id currentAttachment;
NGHashMap *response;
NSData *bodydata;
NSArray *paths;
NGMimeFileData *fdata;
int i, ii;
BOOL found;
paths = [attachmentKeys keysWithFormat: @"BODY[%{path}]"];
response = [[self fetchParts: paths] objectForKey: @"RawResponse"];
for (i = 0; i < [attachmentKeys count]; i++)
{
currentAttachment = [attachmentKeys objectAtIndex: i];
found = NO;
for (ii = 0; ii < [attachments count]; ii++)
{
// no ClientId means its a deletio
if (![[attachments objectAtIndex: ii] objectForKey: @"ClientId"] &&
[[[[attachments objectAtIndex: ii] objectForKey: @"FileReference"] lastPathComponent] isEqualToString: [currentAttachment objectForKey: @"path"]])
{
found = YES;
break;
}
}
// skip deletions
if (found)
continue;
bodydata = [[[response objectForKey: @"fetch"] objectForKey: [NSString stringWithFormat: @"body[%@]", [currentAttachment objectForKey: @"path"]]] valueForKey: @"data"];
map = [[[NGMutableHashMap alloc] initWithCapacity: 1] autorelease];
[map setObject: [currentAttachment objectForKey: @"mimetype"] forKey: @"content-type"];
[map setObject: [currentAttachment objectForKey: @"encoding"] forKey: @"content-transfer-encoding"];
[map addObject: [NSString stringWithFormat: @"attachment; filename=\"%@\"", [currentAttachment objectForKey: @"filename"]] forKey: @"content-disposition"];
bodyPart = [[[NGMimeBodyPart alloc] initWithHeader: map] autorelease];
fdata = [[NGMimeFileData alloc] initWithBytes:[bodydata bytes] length:[bodydata length]];
[bodyPart setBody: fdata];
RELEASE(fdata);
[body addBodyPart: bodyPart];
}
}
// add new attachments
for (i = 0; i < [attachments count]; i++)
{
map = [[[NGMutableHashMap alloc] initWithCapacity: 1] autorelease];
a = [attachments objectAtIndex: i];
// no ClientId means its a deletion
if (![a objectForKey: @"ClientId"])
continue;
[map setObject: @"application/octet-stream" forKey: @"content-type"]; // FIXME ?? can we guess the right content-type
[map setObject: @"base64" forKey: @"content-transfer-encoding"];
[map setObject: [NSString stringWithFormat: @"attachment; filename=\"%@\"", [a objectForKey: @"DisplayName"]] forKey: @"content-disposition"];
bodyPart = [[[NGMimeBodyPart alloc] initWithHeader:map] autorelease];
[bodyPart setBody: [[a objectForKey: @"Content"] stringByDecodingBase64]];
[body addBodyPart: bodyPart];
}
[draftMessage setBody: body];
}
else
{
[map setObject: (bodyType == 1 ? @"text/plain; charset=utf-8" : @"text/html; charset=utf-8")
forKey: @"content-type"];
[map setObject: @"quoted-printable" forKey: @"content-transfer-encoding"];
draftMessage = [[[NGMimeMessage alloc] initWithHeader: map] autorelease];
[draftMessage setBody: [[NSString stringWithFormat: @"%@", [[theValues objectForKey: @"Body"] objectForKey: @"Data"] ] dataUsingEncoding: NSUTF8StringEncoding]];
}
generator = [[[NGMimeMessageGenerator alloc] init] autorelease];
message_data = [generator generateMimeFromPart: bounceMessage];
message_data = [generator generateMimeFromPart: draftMessage];
}
if (message_data)
@@ -1530,8 +1731,32 @@ struct GlobalObjectId {
toFolder: folder
withFlags: [NSArray arrayWithObjects: @"draft", nil]];
serverId = [NSString stringWithFormat: @"%d", [self IMAP4IDFromAppendResult: result]];
[theBuffer appendString: @"<ApplicationData>"];
[theBuffer appendFormat: @"<ConversationId xmlns=\"Email2:\">%@</ConversationId>", [[messageId dataUsingEncoding: NSUTF8StringEncoding] activeSyncRepresentationInContext: context]];
if ([attachments count])
{
[theBuffer appendString: @"<Attachments xmlns=\"AirSyncBase:\">"];
for (i = 0; i < [attachments count]; i++)
{
a = [attachments objectAtIndex: i];
[theBuffer appendString: @"<Attachment>"];
[theBuffer appendFormat: @"<ClientId xmlns=\"AirSyncBase:\">%@</ClientId>", [a objectForKey: @"ClientId"]];
[theBuffer appendFormat: @"<FileReference xmlns=\"AirSyncBase:\">mail/%@/%@/%d</FileReference>", [[[self container] relativeImap4Name] stringByEscapingURL], serverId, i+2];
[theBuffer appendString: @"</Attachment>"];
}
[theBuffer appendString: @"</Attachments>"];
}
[theBuffer appendString: @"</ApplicationData>"];
if ([[result objectForKey: @"result"] boolValue])
return [NSString stringWithFormat: @"%d", [self IMAP4IDFromAppendResult: result]];
return serverId;
}
return nil;
+24 -19
View File
@@ -48,27 +48,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSMutableString *s;
NSCalendarDate *nextAlarmDate;
NSInteger delta;
s = [NSMutableString string];
nextAlarmDate = [self nextAlarmDate];
delta = (int)(([[(iCalEvent *)parent startDate] timeIntervalSince1970] - [nextAlarmDate timeIntervalSince1970])/60);
if ([[self action] caseInsensitiveCompare: @"DISPLAY"] == NSOrderedSame)
if ([parent isKindOfClass: [iCalEvent class]])
{
NSCalendarDate *nextAlarmDate;
NSInteger delta;
nextAlarmDate = [self nextAlarmDate];
delta = (int)(([[(iCalEvent *)parent startDate] timeIntervalSince1970] - [nextAlarmDate timeIntervalSince1970])/60);
if ([parent isKindOfClass: [iCalEvent class]])
{
// don't send negative reminder - not supported
if (delta > 0)
[s appendFormat: @"<Reminder xmlns=\"Calendar:\">%d</Reminder>", (int)delta];
}
else
{
[s appendFormat: @"<ReminderTime xmlns=\"Task:\">%@</ReminderTime>", [nextAlarmDate activeSyncRepresentationInContext: context]];
}
// don't send negative reminder - not supported
if (delta > 0)
[s appendFormat: @"<Reminder xmlns=\"Calendar:\">%d</Reminder>", (int)delta];
}
else
{
[s appendFormat: @"<ReminderTime xmlns=\"Task:\">%@</ReminderTime>", [nextAlarmDate activeSyncRepresentationInContext: context]];
}
return s;
@@ -89,7 +85,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
trigger = [iCalTrigger elementWithTag: @"TRIGGER"];
[trigger setValueType: @"DURATION"];
[self setTrigger: trigger];
[self setAction: @"DISPLAY"];
if (![self action])
[self setAction: @"DISPLAY"];
// SOGo web ui only supports 1w but not 2w (custom reminder only supports min/hours/days)
// 1week = -P1W
@@ -118,8 +115,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
trigger = [iCalTrigger elementWithTag: @"TRIGGER"];
[trigger setValueType: @"DATE-TIME"];
[trigger setSingleValue: [NSString stringWithFormat: @"%@Z", [o iCalFormattedDateTimeString]] forKey: @""];
if ((o = [theValues objectForKey: @"ReminderSet"]))
{
if ([o intValue] == 0)
[trigger setValue: 0 ofAttribute: @"x-webstatus" to: @"triggered"];
}
[self setTrigger: trigger];
[self setAction: @"DISPLAY"];
if (![self action])
[self setAction: @"DISPLAY"];
}
}
+17 -14
View File
@@ -135,7 +135,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// StartTime -- http://msdn.microsoft.com/en-us/library/ee157132(v=exchg.80).aspx
if ([self startDate])
{
if ([self isAllDay] && !tz)
if ([self isAllDay] && !tz && [[context objectForKey: @"ASProtocolVersion"] floatValue] < 16.0)
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>",
[[[self startDate] dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
@@ -148,7 +148,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// EndTime -- http://msdn.microsoft.com/en-us/library/ee157945(v=exchg.80).aspx
if ([self endDate])
{
if ([self isAllDay] && !tz)
if ([self isAllDay] && !tz && [[context objectForKey: @"ASProtocolVersion"] floatValue] < 16.0)
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>",
[[[self endDate] dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
@@ -194,7 +194,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
attendee = [attendees objectAtIndex: i];
[s appendFormat: @"<Attendee_Email xmlns=\"Calendar:\">%@</Attendee_Email>", [[attendee rfc822Email] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee cn] activeSyncRepresentationInContext: context]];
if ([[attendee cn] length])
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee cn] activeSyncRepresentationInContext: context]];
else
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee rfc822Email] activeSyncRepresentationInContext: context]];
attendee_status = [self _attendeeStatus: attendee];
@@ -328,7 +331,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
iCalAlarm *alarm;
alarm = [self firstDisplayOrAudioAlarm];
alarm = [self firstSupportedAlarm];
[s appendString: [alarm activeSyncRepresentationInContext: context]];
}
@@ -454,6 +457,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NSCalendarDate *oldstart;
NSTimeZone *userTimeZone;
iCalTimeZone *tz;
iCalAlarm *alarm;
id o;
int deltasecs;
@@ -589,23 +593,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
}
//
// If an alarm is deinfed with an action != DISPLAY, we ignore the alarm - don't want to overwrite.
//
if ([self hasAlarms] && [[[[self alarms] objectAtIndex: 0] action] caseInsensitiveCompare: @"DISPLAY"] != NSOrderedSame)
{
// Ignore the alarm for now
}
else if ((o = [theValues objectForKey: @"Reminder"]) && [o length])
if ((o = [theValues objectForKey: @"Reminder"]) && [o length])
{
if ([self hasAlarms])
alarm = [[self firstSupportedAlarm] mutableCopy];
else
alarm = [[iCalAlarm alloc] init];
// NOTE: Outlook sends a 15 min reminder (18 hour for allday) if no reminder is specified
// although no default reminder is defined (File -> Options -> Clendar -> Calendar Options - > Default Reminders)
//
// http://answers.microsoft.com/en-us/office/forum/office_2013_release-outlook/desktop-outlook-calendar-creates-entries-with/9aef72d8-81bb-4a32-a6ab-bf7d216fb811?page=5&tm=1395690285088
//
iCalAlarm *alarm;
alarm = [[iCalAlarm alloc] init];
[alarm takeActiveSyncValues: theValues inContext: context];
[self removeAllAlarms];
@@ -868,6 +868,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// { "Attendee_Email" = "sogo3@example.com"; "Attendee_Name" = "Wolfgang Fritz"; "Attendee_Status" = 5; "Attendee_Type" = 1; }
attendee = [o objectAtIndex: i];
if ([self isOrganizer: [attendee objectForKey: @"Attendee_Email"]])
continue;
person = [iCalPerson elementWithTag: @"attendee"];
[person setCn: [attendee objectForKey: @"Attendee_Name"]];
[person setEmail: [attendee objectForKey: @"Attendee_Email"]];
+22 -4
View File
@@ -83,10 +83,28 @@ struct SYSTEMTIME {
tzData->wDay = ([mask firstOccurrence] == -1) ? 5 : [mask firstOccurrence];
dateValue = [self startDate];
tzData->wHour = [dateValue hourOfDay];
tzData->wMinute = [dateValue minuteOfHour];
tzData->wSecond = [dateValue secondOfMinute];
tzData->wMilliseconds = 0;
if (![dateValue hourOfDay])
{
if ([mask firstDay]-1 < 0)
tzData->wDayOfWeek = 6;
else
tzData->wDayOfWeek = [mask firstDay]-1;
tzData->wHour = 23;
tzData->wMinute = 59;
tzData->wSecond = 59;
tzData->wMilliseconds = 999;
}
else
{
tzData->wDayOfWeek = [mask firstDay];
tzData->wHour = [dateValue hourOfDay];
tzData->wMinute = [dateValue minuteOfHour];
tzData->wSecond = [dateValue secondOfMinute];
tzData->wMilliseconds = 0;
}
}
}
+1
View File
@@ -46,6 +46,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalDateTime.h>
#import <NGCards/iCalTimeZone.h>
#import <NGCards/iCalTrigger.h>
#import <Appointments/iCalEntityObject+SOGo.h>
+2729
View File
File diff suppressed because it is too large. Load diff
@@ -524,7 +524,7 @@ static Class iCalEventK = nil;
//
// If the user is the owner of the calendar, by default we include the freebusy information.
//
// If the user is NOT the owner of the calendar, by default we exclude the freebusy information.
// If the user is NOT the owner of the calendar but is subscribed, by default we exclude the freebusy information.
//
// We must include the freebusy information of other users if we are actually looking at their freebusy information
// but we aren't necessarily subscribed to their calendars.
@@ -534,7 +534,7 @@ static Class iCalEventK = nil;
NSNumber *excludeFromFreeBusy;
NSString *userLogin, *ownerInContext;
BOOL is_owner;
userLogin = [[context activeUser] login];
ownerInContext = [[self container] ownerInContext: context];
is_owner = [userLogin isEqualToString: ownerInContext];