Compare commits
345
Commits
SOGo-2.2.1
...
SOGo-2.2.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac6e9a564a | ||
|
|
07324e56a0 | ||
|
|
397a36cc89 | ||
|
|
c240931c54 | ||
|
|
ef2432e10f | ||
|
|
571322958a | ||
|
|
bd5c05cca2 | ||
|
|
ea44308aa3 | ||
|
|
94f3246658 | ||
|
|
1df7e989e0 | ||
|
|
d9ca1051b3 | ||
|
|
4eefa4c269 | ||
|
|
4c21a050d9 | ||
|
|
b52289904f | ||
|
|
d5b71526ed | ||
|
|
c389630d76 | ||
|
|
f6ef94a631 | ||
|
|
5de51e8aa1 | ||
|
|
006727a74b | ||
|
|
037dd67635 | ||
|
|
6619840f80 | ||
|
|
08fd2fcfaa | ||
|
|
a43dd97fc9 | ||
|
|
192659fdd9 | ||
|
|
06fe36fd75 | ||
|
|
24f9d83ff7 | ||
|
|
8dd967d0a8 | ||
|
|
08cd080d47 | ||
|
|
11920f592c | ||
|
|
28e6bb8b9d | ||
|
|
b892b3f794 | ||
|
|
cdf4cc1acb | ||
|
|
3cac794de5 | ||
|
|
8f9b24a23f | ||
|
|
a2a7014140 | ||
|
|
a5ecb2063f | ||
|
|
9bd7aeebfb | ||
|
|
01af72cfe9 | ||
|
|
6dddb5c98c | ||
|
|
ccf181bcf9 | ||
|
|
e478b29c2e | ||
|
|
f3ded6ce2a | ||
|
|
c2027f072d | ||
|
|
ce6a31dd38 | ||
|
|
a71013eebf | ||
|
|
eaec5a614d | ||
|
|
5217bed5ae | ||
|
|
17319cc8dd | ||
|
|
89d116363c | ||
|
|
7c3e85f517 | ||
|
|
05fb7ae0c8 | ||
|
|
ef20108e32 | ||
|
|
b5c0363400 | ||
|
|
f0b8eb8dfb | ||
|
|
16d02455bd | ||
|
|
8ded5a8aaf | ||
|
|
1cc93c700a | ||
|
|
44d0cb5c0d | ||
|
|
dbdb7d9051 | ||
|
|
e343ed240b | ||
|
|
45553be122 | ||
|
|
1cf4841477 | ||
|
|
017a85b7f2 | ||
|
|
103bb6803a | ||
|
|
8c8e47daf6 | ||
|
|
8a17246725 | ||
|
|
4843c6b6d7 | ||
|
|
04904d8c61 | ||
|
|
6e13f15477 | ||
|
|
5dd2088d42 | ||
|
|
9c3c2cb926 | ||
|
|
55422b5f03 | ||
|
|
899a1eb026 | ||
|
|
660f39a980 | ||
|
|
8335c38830 | ||
|
|
0fb7135335 | ||
|
|
70b0cb78cd | ||
|
|
d197ab71b7 | ||
|
|
6b58e034f3 | ||
|
|
ff015afde8 | ||
|
|
6da03bc75c | ||
|
|
2b119c63e0 | ||
|
|
5b61df8ca4 | ||
|
|
659e2f3aa8 | ||
|
|
8191576361 | ||
|
|
5b9c7e07d1 | ||
|
|
cafb896e8c | ||
|
|
7a69bc46eb | ||
|
|
302e40a1c3 | ||
|
|
b6be4e6e2f | ||
|
|
dabd8d3282 | ||
|
|
d7d458a934 | ||
|
|
5419f411e5 | ||
|
|
22f5ed62fe | ||
|
|
3523dc489f | ||
|
|
5b3de04fc1 | ||
|
|
eb3cc8916d | ||
|
|
9fa0b42e19 | ||
|
|
e048346cb7 | ||
|
|
333b561a59 | ||
|
|
50c0b49a6f | ||
|
|
8202d0588f | ||
|
|
d9b578b869 | ||
|
|
5bb64916c6 | ||
|
|
e7ddfb0546 | ||
|
|
0e182f8436 | ||
|
|
de2ee2322a | ||
|
|
ce07695a55 | ||
|
|
43ac57b671 | ||
|
|
7f7e3cb06a | ||
|
|
6b3a3f858b | ||
|
|
0133bb3b6b | ||
|
|
91e3e19e40 | ||
|
|
19a95a1818 | ||
|
|
1292c191ec | ||
|
|
77dad178d1 | ||
|
|
f48839bf55 | ||
|
|
0f04be2bcb | ||
|
|
3f8bbe8c60 | ||
|
|
f0b4a05c70 | ||
|
|
6b6ec8a2ae | ||
|
|
ad30df26af | ||
|
|
6e56f46f86 | ||
|
|
fe38518a36 | ||
|
|
e118a72eab | ||
|
|
72bec939d6 | ||
|
|
ba258ca806 | ||
|
|
0c2e2f28f7 | ||
|
|
f0dfe37a55 | ||
|
|
95d6911f1a | ||
|
|
dace1439df | ||
|
|
d91b37413f | ||
|
|
bd916f06eb | ||
|
|
ecbe0858f7 | ||
|
|
24095a464c | ||
|
|
9ce3b8ff8f | ||
|
|
efc33d8174 | ||
|
|
93971dc434 | ||
|
|
fac9520f64 | ||
|
|
9eb075cc3f | ||
|
|
c5922b07aa | ||
|
|
51e07fc306 | ||
|
|
d35c52bb38 | ||
|
|
6bab4c94f2 | ||
|
|
c31429a5d5 | ||
|
|
04bb88a470 | ||
|
|
c79cd750d8 | ||
|
|
6fc81e61ec | ||
|
|
d9ad286650 | ||
|
|
dd57d56cf9 | ||
|
|
ab7780d617 | ||
|
|
cb9332f240 | ||
|
|
7b60ad4797 | ||
|
|
3261c21549 | ||
|
|
364b409501 | ||
|
|
064565e1a9 | ||
|
|
f92d280fbb | ||
|
|
ea2bce706c | ||
|
|
d74afaf295 | ||
|
|
5e7beb3345 | ||
|
|
2df5887eec | ||
|
|
3d1bdf1a09 | ||
|
|
5de1343506 | ||
|
|
1eaa3f3891 | ||
|
|
c2d3a827bd | ||
|
|
6b72a8d126 | ||
|
|
819d0641b7 | ||
|
|
5d7f4ba6c6 | ||
|
|
34a7e28858 | ||
|
|
87b010c700 | ||
|
|
a44b183b7e | ||
|
|
b488721f83 | ||
|
|
8a03f3bd63 | ||
|
|
f8c8abc989 | ||
|
|
db8d9bb16c | ||
|
|
2794425a3f | ||
|
|
2f7979c796 | ||
|
|
c426afd7f2 | ||
|
|
07445eb069 | ||
|
|
93bf98c326 | ||
|
|
c08c3e27d5 | ||
|
|
c8860dc92b | ||
|
|
1a1543a380 | ||
|
|
d2d5467317 | ||
|
|
18443de9bf | ||
|
|
be72456a9a | ||
|
|
a54b3e4289 | ||
|
|
7a4feae8b8 | ||
|
|
99d49b9bd9 | ||
|
|
5f9fb4e1c4 | ||
|
|
ef2188962a | ||
|
|
2922f15ca7 | ||
|
|
41e6fb89d3 | ||
|
|
c4a3843695 | ||
|
|
bf67b6435f | ||
|
|
b5319446db | ||
|
|
d58184af15 | ||
|
|
fbc6856fd5 | ||
|
|
5c41915080 | ||
|
|
698524b39f | ||
|
|
1f5a2a4c62 | ||
|
|
fc3cfa5484 | ||
|
|
593b44ed01 | ||
|
|
b2ed7e3f6b | ||
|
|
bc2b41f383 | ||
|
|
7d7961ffcf | ||
|
|
0b9afec635 | ||
|
|
4e42a6a689 | ||
|
|
da8febf138 | ||
|
|
8c563c2922 | ||
|
|
fa5cf55367 | ||
|
|
e43b704858 | ||
|
|
44a4baca7f | ||
|
|
78447d81ae | ||
|
|
9dc07fccc0 | ||
|
|
ba7b65cf7b | ||
|
|
66bfbeaac1 | ||
|
|
619cb2c0ec | ||
|
|
f9869d19b4 | ||
|
|
57b747c24a | ||
|
|
8f6b0f80a7 | ||
|
|
cb5e6e7ef2 | ||
|
|
49363cfe36 | ||
|
|
c345fc2b8d | ||
|
|
d200629b01 | ||
|
|
cfc1ac6b3b | ||
|
|
e66ceaad07 | ||
|
|
f370ac114a | ||
|
|
75ee6b4806 | ||
|
|
0961fbbab3 | ||
|
|
0d1c39ca71 | ||
|
|
5739356f88 | ||
|
|
33467093c1 | ||
|
|
96ece873ca | ||
|
|
8909775cf6 | ||
|
|
0ba59de88e | ||
|
|
4fbe937f6d | ||
|
|
ab80e87a3f | ||
|
|
068eb921aa | ||
|
|
5c13fade22 | ||
|
|
371e5ead08 | ||
|
|
c5e6ccf332 | ||
|
|
ec9d48c3a9 | ||
|
|
877082f042 | ||
|
|
342b68fd44 | ||
|
|
e24c22e3dc | ||
|
|
7997448d41 | ||
|
|
3629670fca | ||
|
|
c250b9a6d4 | ||
|
|
afa564a6a6 | ||
|
|
d9b99f536c | ||
|
|
5699e5e1b4 | ||
|
|
e869406081 | ||
|
|
3e221253ad | ||
|
|
446ef3467a | ||
|
|
bf64076b87 | ||
|
|
c9cbcf2566 | ||
|
|
4fe0358581 | ||
|
|
534e4e3d4d | ||
|
|
09bcd2aee2 | ||
|
|
526e21e837 | ||
|
|
c80e222210 | ||
|
|
6e60bbb553 | ||
|
|
846212336a | ||
|
|
349f4d824a | ||
|
|
2f565d2ec9 | ||
|
|
eb7cabac71 | ||
|
|
2ff4498983 | ||
|
|
3eec753b73 | ||
|
|
7b0ffacff0 | ||
|
|
f999c87d4d | ||
|
|
48f98ef34e | ||
|
|
378f2b5876 | ||
|
|
d091b3d7cd | ||
|
|
370e1e6d26 | ||
|
|
e2b3d5a7ff | ||
|
|
078b88a396 | ||
|
|
ee09b80fc3 | ||
|
|
99d9615c92 | ||
|
|
79c3fa8ad2 | ||
|
|
fd07112113 | ||
|
|
ce5d591d1d | ||
|
|
e603742d71 | ||
|
|
585d224a15 | ||
|
|
6a39b48a37 | ||
|
|
633723a470 | ||
|
|
ba32b95308 | ||
|
|
03d5975be3 | ||
|
|
1da1764aae | ||
|
|
6e4f776d4b | ||
|
|
365e271a84 | ||
|
|
bce701208a | ||
|
|
b16911edc1 | ||
|
|
76307cfaaf | ||
|
|
e5fb7dc7b8 | ||
|
|
50e7ea7188 | ||
|
|
ae0c5eae77 | ||
|
|
89e61f6d5d | ||
|
|
0c2d727057 | ||
|
|
85f4af56e9 | ||
|
|
04bdb22b00 | ||
|
|
874b1d9eba | ||
|
|
b143688419 | ||
|
|
5f3d2d988e | ||
|
|
93f1540c17 | ||
|
|
877e44c6d2 | ||
|
|
4ca3d351e0 | ||
|
|
19b6704955 | ||
|
|
64787555ff | ||
|
|
27ffcf240f | ||
|
|
893d75bd5f | ||
|
|
b0f26f1dcc | ||
|
|
a196ed210e | ||
|
|
1c28a4b4d2 | ||
|
|
fc56493b78 | ||
|
|
3a33010918 | ||
|
|
83bccda551 | ||
|
|
35d71f6150 | ||
|
|
e92a145325 | ||
|
|
c3062284e3 | ||
|
|
e2f192b793 | ||
|
|
b8f239bf34 | ||
|
|
e968be8024 | ||
|
|
3c3bebeee3 | ||
|
|
26e9defdbd | ||
|
|
8742f28c29 | ||
|
|
bd577fd513 | ||
|
|
c8550c8a4a | ||
|
|
1bdf88fb67 | ||
|
|
d108777e89 | ||
|
|
167a06e3e9 | ||
|
|
af68f10115 | ||
|
|
cbd22762c3 | ||
|
|
8cc352fb28 | ||
|
|
0d69a476bc | ||
|
|
cee1e529f8 | ||
|
|
3a681bd5a5 | ||
|
|
f5faa60814 | ||
|
|
f8939bfb3e | ||
|
|
78636f0396 | ||
|
|
037c2d3ddf | ||
|
|
f4d189ffc8 | ||
|
|
1b9ac03e94 | ||
|
|
6ad87052ba | ||
|
|
e7a16cba0d |
No files matched your search
@@ -1,6 +1,8 @@
|
||||
config.make
|
||||
tags
|
||||
*._*
|
||||
*/obj/
|
||||
*._*
|
||||
*/*/obj/
|
||||
*/*/*/obj/
|
||||
*/*/*.SOGo/
|
||||
@@ -11,3 +13,4 @@ SoObjects/SOGo/SOGo.framework/
|
||||
SoObjects/SOGo/derived_src/
|
||||
Tests/*/config.py
|
||||
*.pyc
|
||||
._*
|
||||
+26
@@ -235,6 +235,32 @@ trans.sk = SoObjects/Contacts/Slovak.lproj/Localizable.strings
|
||||
trans.sv = SoObjects/Contacts/Swedish.lproj/Localizable.strings
|
||||
trans.uk = SoObjects/Contacts/Ukrainian.lproj/Localizable.strings
|
||||
|
||||
[sogo.soobjects-mailer]
|
||||
source_file = SoObjects/Mailer/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
trans.ar = SoObjects/Mailer/Arabic.lproj/Localizable.strings
|
||||
trans.ca = SoObjects/Mailer/Catalan.lproj/Localizable.strings
|
||||
trans.cs = SoObjects/Mailer/Czech.lproj/Localizable.strings
|
||||
trans.cy = SoObjects/Mailer/Welsh.lproj/Localizable.strings
|
||||
trans.da_DK = SoObjects/Mailer/Danish.lproj/Localizable.strings
|
||||
trans.de = SoObjects/Mailer/German.lproj/Localizable.strings
|
||||
trans.es_AR = SoObjects/Mailer/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = SoObjects/Mailer/SpanishSpain.lproj/Localizable.strings
|
||||
trans.fi = SoObjects/Mailer/Finnish.lproj/Localizable.strings
|
||||
trans.fr = SoObjects/Mailer/French.lproj/Localizable.strings
|
||||
trans.hu = SoObjects/Mailer/Hungarian.lproj/Localizable.strings
|
||||
trans.is = SoObjects/Mailer/Icelandic.lproj/Localizable.strings
|
||||
trans.it = SoObjects/Mailer/Italian.lproj/Localizable.strings
|
||||
trans.nb_NO = SoObjects/Mailer/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = SoObjects/Mailer/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = SoObjects/Mailer/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = SoObjects/Mailer/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = SoObjects/Mailer/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = SoObjects/Mailer/Russian.lproj/Localizable.strings
|
||||
trans.sk = SoObjects/Mailer/Slovak.lproj/Localizable.strings
|
||||
trans.sv = SoObjects/Mailer/Swedish.lproj/Localizable.strings
|
||||
trans.uk = SoObjects/Mailer/Ukrainian.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-mailpartviewers]
|
||||
source_file = UI/MailPartViewers/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
|
||||
@@ -9,28 +9,31 @@ ActiveSync_PRINCIPAL_CLASS = ActiveSyncProduct
|
||||
|
||||
ActiveSync_OBJC_FILES = \
|
||||
ActiveSyncProduct.m \
|
||||
iCalAlarm+ActiveSync.m \
|
||||
iCalEvent+ActiveSync.m \
|
||||
iCalRecurrenceRule+ActiveSync.m \
|
||||
iCalTimeZone+ActiveSync.m \
|
||||
iCalToDo+ActiveSync.m \
|
||||
NSCalendarDate+ActiveSync.m \
|
||||
NSCalendarDate+ActiveSync.m \
|
||||
NSData+ActiveSync.m \
|
||||
NSDate+ActiveSync.m \
|
||||
NGDOMElement+ActiveSync.m \
|
||||
NGMimeMessage+ActiveSync.m \
|
||||
NGVCard+ActiveSync.m \
|
||||
NSArray+SyncCache.m \
|
||||
NSString+ActiveSync.m \
|
||||
SOGoActiveSyncDispatcher.m \
|
||||
SOGoActiveSyncDispatcher+Sync.m \
|
||||
SOGoMailObject+ActiveSync.m \
|
||||
SOGoMailObject+ActiveSync.m \
|
||||
SOGoSyncCacheObject.m \
|
||||
SoObjectWebDAVDispatcher+ActiveSync.m
|
||||
|
||||
ActiveSync_RESOURCE_FILES += \
|
||||
product.plist
|
||||
|
||||
ADDITIONAL_OBJCFLAGS += -Wno-deprecated-declarations
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../../SOPE/ -I../SoObjects/
|
||||
ADDITIONAL_LIB_DIRS += -L../../SOPE/GDLContentStore/obj/
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../SOPE/ -I../SoObjects/
|
||||
ADDITIONAL_LIB_DIRS += -L../SOPE/GDLContentStore/obj/ -L../SOPE/NGCards/obj/
|
||||
ADDITIONAL_INCLUDE_DIRS += -I/usr/include/libwbxml-1.0/
|
||||
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed -lwbxml2
|
||||
|
||||
|
||||
@@ -37,6 +37,28 @@ static NSArray *asElementArray = nil;
|
||||
|
||||
@implementation NGDOMElement (ActiveSync)
|
||||
|
||||
- (BOOL) isTextNode
|
||||
{
|
||||
id <DOMNodeList> children;
|
||||
id <DOMElement> element;
|
||||
int i;
|
||||
|
||||
if ([self nodeType] == DOM_TEXT_NODE)
|
||||
return YES;
|
||||
|
||||
children = [self childNodes];
|
||||
|
||||
for (i = 0; i < [children length]; i++)
|
||||
{
|
||||
element = [children objectAtIndex: i];
|
||||
|
||||
if ([element nodeType] != DOM_TEXT_NODE)
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
//
|
||||
// We must handle "inner data" like this:
|
||||
//
|
||||
@@ -79,7 +101,7 @@ static NSArray *asElementArray = nil;
|
||||
int i, count;
|
||||
|
||||
if (!asElementArray)
|
||||
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", nil];
|
||||
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", @"Category", nil];
|
||||
|
||||
data = [NSMutableDictionary dictionary];
|
||||
|
||||
@@ -96,9 +118,17 @@ static NSArray *asElementArray = nil;
|
||||
|
||||
tag = [element tagName];
|
||||
count = [(NSArray *)[element childNodes] count];
|
||||
|
||||
|
||||
// We check if the node is a text one or if all its
|
||||
// children are text nodes. This is important to avoid side-effects
|
||||
// in SOPE where "foo & bar" would result into 3 childnodes instead
|
||||
// of just one.
|
||||
if ([(id)element isTextNode])
|
||||
{
|
||||
value = [(id)element textValue];
|
||||
}
|
||||
// Handle inner data - see above for samples
|
||||
if (count > 2)
|
||||
else
|
||||
{
|
||||
NSMutableArray *innerElements;
|
||||
id <DOMElement> innerElement;
|
||||
@@ -123,7 +153,10 @@ static NSArray *asElementArray = nil;
|
||||
|
||||
if ([innerTag isEqualToString: [innerElement tagName]])
|
||||
{
|
||||
[innerElements addObject: [(NGDOMElement *)innerElement applicationData]];
|
||||
if ([(id)innerElement isTextNode])
|
||||
[innerElements addObject: [(NGDOMElement *)innerElement textValue]];
|
||||
else
|
||||
[innerElements addObject: [(NGDOMElement *)innerElement applicationData]];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -144,12 +177,11 @@ static NSArray *asElementArray = nil;
|
||||
value = nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
value = [[element firstChild] textValue];
|
||||
|
||||
if (value && tag)
|
||||
[data setObject: value forKey: tag];
|
||||
}
|
||||
|
||||
} // if ([element nodeType] == DOM_ELEMENT_NODE)
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
@@ -40,6 +40,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import <Contacts/NGVCard+SOGo.h>
|
||||
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
|
||||
#include "NSDate+ActiveSync.h"
|
||||
#include "NSString+ActiveSync.h"
|
||||
|
||||
@@ -47,9 +49,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSArray *emails, *addresses, *categories, *elements;
|
||||
CardElement *n, *homeAdr, *workAdr;
|
||||
NSArray *emails, *addresses;
|
||||
NSMutableString *s;
|
||||
NSString *url;
|
||||
id o;
|
||||
|
||||
int i;
|
||||
@@ -65,10 +68,42 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if ((o = [self workCompany]))
|
||||
[s appendFormat: @"<CompanyName xmlns=\"Contacts:\">%@</CompanyName>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [[self org] flattenedValueAtIndex: 1 forKey: @""]))
|
||||
[s appendFormat: @"<Department xmlns=\"Contacts:\">%@</Department>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
categories = [self categories];
|
||||
|
||||
if ([categories count])
|
||||
{
|
||||
[s appendFormat: @"<Categories xmlns=\"Contacts:\">"];
|
||||
for (i = 0; i < [categories count]; i++)
|
||||
{
|
||||
[s appendFormat: @"<Category xmlns=\"Contacts:\">%@</Category>", [[categories objectAtIndex: i] activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
[s appendFormat: @"</Categories>"];
|
||||
}
|
||||
|
||||
elements = [self childrenWithTag: @"url"
|
||||
andAttribute: @"type"
|
||||
havingValue: @"work"];
|
||||
if ([elements count] > 0)
|
||||
{
|
||||
url = [[elements objectAtIndex: 0] flattenedValuesForKey: @""];
|
||||
[s appendFormat: @"<WebPage xmlns=\"Contacts:\">%@</WebPage>", [url activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
|
||||
if ((o = [[self uniqueChildWithTag: @"x-aim"] flattenedValuesForKey: @""]))
|
||||
[s appendFormat: @"<IMAddress xmlns=\"Contacts:\">%@</IMAddress>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self nickname]))
|
||||
[s appendFormat: @"<NickName xmlns=\"Contacts:\">%@</NickName>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
|
||||
if ((o = [self title]))
|
||||
[s appendFormat: @"<JobTitle xmlns=\"Contacts:\">%@</JobTitle>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
|
||||
if ((o = [self preferredEMail]))
|
||||
[s appendFormat: @"<Email1Address xmlns=\"Contacts:\">%@</Email1Address>", o];
|
||||
|
||||
@@ -154,7 +189,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Other, less important fields
|
||||
if ((o = [self birthday]))
|
||||
[s appendFormat: @"<Birthday xmlns=\"Contacts:\">%@</Birthday>", [o activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
[s appendFormat: @"<Birthday xmlns=\"Contacts:\">%@</Birthday>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self note]))
|
||||
{
|
||||
@@ -166,6 +201,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
|
||||
if ((o = [self photo]))
|
||||
[s appendFormat: @"<Picture xmlns=\"Contacts:\">%@</Picture>", o];
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -183,6 +221,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
[self setNote: o];
|
||||
|
||||
// Categories
|
||||
if ((o = [theValues objectForKey: @"Categories"]))
|
||||
[self setCategories: o];
|
||||
|
||||
// Birthday
|
||||
if ((o = [theValues objectForKey: @"Birthday"]))
|
||||
{
|
||||
@@ -238,24 +280,31 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Company's name
|
||||
if ((o = [theValues objectForKey: @"CompanyName"]))
|
||||
{
|
||||
[self setOrg: o units: nil];
|
||||
}
|
||||
[self setOrg: o units: nil];
|
||||
|
||||
// Department
|
||||
if ((o = [theValues objectForKey: @"Department"]))
|
||||
[self setOrg: nil units: [NSArray arrayWithObjects:o,nil]];
|
||||
|
||||
// Email addresses
|
||||
if ((o = [theValues objectForKey: @"Email1Address"]))
|
||||
{
|
||||
[self addEmail: o types: [NSArray arrayWithObject: @"pref"]];
|
||||
element = [self elementWithTag: @"email" ofType: @"work"];
|
||||
[element setSingleValue: [o pureEMailAddress] forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"Email2Address"]))
|
||||
{
|
||||
[self addEmail: o types: nil];
|
||||
element = [self elementWithTag: @"email" ofType: @"home"];
|
||||
[element setSingleValue: [o pureEMailAddress] forKey: @""];
|
||||
}
|
||||
|
||||
// SOGo currently only supports 2 email addresses ... but AS clients might send 3
|
||||
// FIXME: revise this when the GUI revamp is done in SOGo
|
||||
if ((o = [theValues objectForKey: @"Email3Address"]))
|
||||
{
|
||||
[self addEmail: o types: nil];
|
||||
element = [self elementWithTag: @"email" ofType: @"three"];
|
||||
[element setSingleValue: [o pureEMailAddress] forKey: @""];
|
||||
}
|
||||
|
||||
// Formatted name
|
||||
@@ -293,16 +342,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Job's title
|
||||
if ((o = [theValues objectForKey: @"JobTitle"]))
|
||||
{
|
||||
[self setTitle: o];
|
||||
}
|
||||
[self setTitle: o];
|
||||
|
||||
// WebPage (work)
|
||||
if ((o = [theValues objectForKey: @"WebPage"]))
|
||||
{
|
||||
[[self elementWithTag: @"url" ofType: @"work"]
|
||||
[[self elementWithTag: @"url" ofType: @"work"]
|
||||
setSingleValue: o forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"NickName"]))
|
||||
[self setNickname: o];
|
||||
|
||||
if ((o = [theValues objectForKey: @"Picture"]))
|
||||
[self setPhoto: o];
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __NSARRAYSYNCCACHE_H__
|
||||
#define __NSARRAYSYNCCACHE_H__
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
|
||||
@class NSDictionary;
|
||||
|
||||
@interface NSMutableArray (SyncCache)
|
||||
|
||||
- (id) initWithDictionary: (NSDictionary *) theDictionary;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSArray (SyncCache)
|
||||
|
||||
- (NSDictionary *) dictionaryValue;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#import "NSArray+SyncCache.h"
|
||||
|
||||
#import <Foundation/NSDictionary.h>
|
||||
|
||||
#include "SOGoSyncCacheObject.h"
|
||||
|
||||
@implementation NSMutableArray (SyncCache)
|
||||
|
||||
- (id) initWithDictionary: (NSDictionary *) theDictionary
|
||||
{
|
||||
SOGoSyncCacheObject *o;
|
||||
NSArray *allKeys;
|
||||
id key;
|
||||
int i;
|
||||
|
||||
self = [self initWithCapacity: [theDictionary count]];
|
||||
|
||||
allKeys = [theDictionary allKeys];
|
||||
|
||||
for (i = 0; i < [allKeys count]; i++)
|
||||
{
|
||||
key = [allKeys objectAtIndex: i];
|
||||
o = [SOGoSyncCacheObject syncCacheObjectWithUID: key
|
||||
sequence: [theDictionary objectForKey: key]];
|
||||
[self addObject: o];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
@implementation NSArray (SyncCache)
|
||||
|
||||
- (NSDictionary *) dictionaryValue
|
||||
{
|
||||
NSMutableDictionary *d;
|
||||
SOGoSyncCacheObject *o;
|
||||
int i;
|
||||
|
||||
d = [NSMutableDictionary dictionary];
|
||||
|
||||
for (i = 0; i < [self count]; i++)
|
||||
{
|
||||
o = [self objectAtIndex: i];
|
||||
[d setObject: [o sequence] forKey: [o uid]];
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -46,6 +46,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
- (NSString *) realCollectionIdWithFolderType: (SOGoMicrosoftActiveSyncFolderType *) folderType;
|
||||
- (NSCalendarDate *) calendarDate;
|
||||
- (NSString *) deviceId;
|
||||
- (NSString *) deviceType;
|
||||
- (NSString *) attachmentName;
|
||||
- (NSString *) command;
|
||||
- (NSData *) convertHexStringToBytes;
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
NSString *s;
|
||||
int i;
|
||||
|
||||
components = [[[self componentsSeparatedByString: @"/"] lastObject] componentsSeparatedByString: @"&"];
|
||||
components = [[[self componentsSeparatedByString: @"?"] lastObject] componentsSeparatedByString: @"&"];
|
||||
|
||||
for (i = 0; i < [components count]; i++)
|
||||
{
|
||||
@@ -169,6 +169,40 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
return s;
|
||||
}
|
||||
|
||||
//
|
||||
// This method extracts the "DeviceType" from a URI:
|
||||
//
|
||||
// /SOGo/Microsoft-Server-ActiveSync?Cmd=FolderSync&User=sogo10&DeviceId=SEC17CD1A3E9E3F2&DeviceType=SAMSUNGSGHI317M
|
||||
//
|
||||
- (NSString *) deviceType
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"DEVICETYPE="];
|
||||
|
||||
if (!s)
|
||||
s = @"Unknown";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// This method extracts the "AttachmentName" from a URI:
|
||||
//
|
||||
// /SOGo/Microsoft-Server-ActiveSync?Cmd=GetAttachment&User=sogo&DeviceId=HTCa04b4932597acd3f2dc1a918b9728&DeviceType=htcvision&AttachmentName=mail/TestFldr/8/2
|
||||
//
|
||||
- (NSString *) attachmentName
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"ATTACHMENTNAME="];
|
||||
|
||||
if (!s)
|
||||
s = @"Unknown";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
@@ -32,9 +32,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSNull.h>
|
||||
#import <Foundation/NSProcessInfo.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGObjWeb/SoApplication.h>
|
||||
@@ -58,18 +60,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import <NGImap4/NSString+Imap4.h>
|
||||
|
||||
#import <NGMime/NGMimeBodyPart.h>
|
||||
#import <NGMime/NGMimeMultipartBody.h>
|
||||
#import <NGMail/NGMimeMessageParser.h>
|
||||
#import <NGMail/NGMimeMessage.h>
|
||||
#import <NGMail/NGMimeMessageGenerator.h>
|
||||
|
||||
#import <DOM/DOMElement.h>
|
||||
#import <DOM/DOMProtocols.h>
|
||||
|
||||
#import <EOControl/EOQualifier.h>
|
||||
|
||||
#import <SOGo/NSArray+DAV.h>
|
||||
#import <SOGo/SOGoCache.h>
|
||||
#import <SOGo/NSDictionary+DAV.h>
|
||||
#import <SOGo/SOGoDAVAuthenticator.h>
|
||||
#import <SOGo/SOGoDomainDefaults.h>
|
||||
@@ -77,6 +74,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserSettings.h>
|
||||
#import <SOGo/SOGoCacheGCSObject.h>
|
||||
|
||||
#import <Appointments/SOGoAppointmentObject.h>
|
||||
#import <Appointments/SOGoAppointmentFolder.h>
|
||||
@@ -106,11 +104,50 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "NSString+ActiveSync.h"
|
||||
#include "SOGoActiveSyncConstants.h"
|
||||
#include "SOGoMailObject+ActiveSync.h"
|
||||
#include "SOGoSyncCacheObject.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
@implementation SOGoActiveSyncDispatcher (Sync)
|
||||
|
||||
- (void) _setFolderMetadata: (NSDictionary *) theFolderMetadata
|
||||
forKey: (NSString *) theFolderKey
|
||||
{
|
||||
SOGoCacheGCSObject *o;
|
||||
NSString *key;
|
||||
|
||||
key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], theFolderKey];
|
||||
|
||||
o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
|
||||
[o setObjectType: ActiveSyncFolderCacheObject];
|
||||
[o setTableUrl: [self folderTableURL]];
|
||||
[o reloadIfNeeded];
|
||||
|
||||
[[o properties] removeObjectForKey: @"SyncKey"];
|
||||
[[o properties] removeObjectForKey: @"SyncCache"];
|
||||
[[o properties] removeObjectForKey: @"DateCache"];
|
||||
[[o properties] removeObjectForKey: @"MoreAvailable"];
|
||||
|
||||
[[o properties] addEntriesFromDictionary: theFolderMetadata];
|
||||
[o save];
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) _folderMetadataForKey: (NSString *) theFolderKey
|
||||
{
|
||||
SOGoCacheGCSObject *o;
|
||||
NSString *key;
|
||||
|
||||
key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], theFolderKey];
|
||||
|
||||
o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
|
||||
[o setObjectType: ActiveSyncFolderCacheObject];
|
||||
[o setTableUrl: [self folderTableURL]];
|
||||
[o reloadIfNeeded];
|
||||
|
||||
return [o properties];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// <?xml version="1.0"?>
|
||||
// <!DOCTYPE ActiveSync PUBLIC "-//MICROSOFT//DTD ActiveSync//EN" "http://www.microsoft.com/">
|
||||
@@ -392,7 +429,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
inContext: context
|
||||
acquire: NO];
|
||||
|
||||
[sogoObject delete];
|
||||
if (![sogoObject isKindOfClass: [NSException class]])
|
||||
[sogoObject delete];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -427,7 +465,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[theBuffer appendString: @"</Fetch>"];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// The method handles <GetChanges/>
|
||||
//
|
||||
@@ -441,19 +478,70 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
lastServerKey: (NSString **) theLastServerKey
|
||||
|
||||
{
|
||||
NSMutableDictionary *folderMetadata, *dateCache, *syncCache;
|
||||
NSMutableString *s;
|
||||
|
||||
BOOL more_available;
|
||||
int i, max;
|
||||
|
||||
s = [NSMutableString string];
|
||||
|
||||
more_available = NO;
|
||||
|
||||
if (theFolderType == ActiveSyncMailFolder && !([theSyncKey isEqualToString: @"-1"]) && theFilterType)
|
||||
{
|
||||
NSArray *allKeys;
|
||||
NSString *key;
|
||||
int softdelete_count;
|
||||
|
||||
softdelete_count = 0;
|
||||
|
||||
folderMetadata = [self _folderMetadataForKey: [theCollection nameInContainer]];
|
||||
dateCache = [folderMetadata objectForKey: @"DateCache"];
|
||||
syncCache = [folderMetadata objectForKey: @"SyncCache"];
|
||||
|
||||
allKeys = [dateCache allKeys];
|
||||
for (i = 0; i < [allKeys count]; i++)
|
||||
{
|
||||
key = [allKeys objectAtIndex: i];
|
||||
|
||||
if ([[dateCache objectForKey:key] compare: theFilterType] == NSOrderedAscending)
|
||||
{
|
||||
[s appendString: @"<SoftDelete xmlns=\"AirSync:\">"];
|
||||
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", key];
|
||||
[s appendString: @"</SoftDelete>"];
|
||||
|
||||
[syncCache removeObjectForKey: key];
|
||||
[dateCache removeObjectForKey: key];
|
||||
|
||||
softdelete_count++;
|
||||
}
|
||||
|
||||
if (softdelete_count >= theWindowSize)
|
||||
{
|
||||
[folderMetadata setObject: [NSNumber numberWithBool: YES] forKey: @"MoreAvailable"];
|
||||
[self _setFolderMetadata: folderMetadata forKey: [theCollection nameInContainer]];
|
||||
|
||||
more_available = YES;
|
||||
*theLastServerKey = theSyncKey;
|
||||
|
||||
// Since WindowSize is reached don't even try to add more to the response, let's just
|
||||
// jump to the end and return the response immediately
|
||||
goto return_response;
|
||||
}
|
||||
}
|
||||
|
||||
[folderMetadata removeObjectForKey: @"MoreAvailable"];
|
||||
[self _setFolderMetadata: folderMetadata forKey: [theCollection nameInContainer]];
|
||||
}
|
||||
|
||||
//
|
||||
// No changes in the collection - 2.2.2.19.1.1 Empty Sync Request.
|
||||
// We check this and we don't generate any commands if we don't have to.
|
||||
//
|
||||
if ([theSyncKey isEqualToString: [theCollection davCollectionTag]])
|
||||
if ([theSyncKey isEqualToString: [theCollection davCollectionTag]] && !([s length]))
|
||||
return;
|
||||
|
||||
s = [NSMutableString string];
|
||||
more_available = NO;
|
||||
|
||||
switch (theFolderType)
|
||||
@@ -566,100 +654,209 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendString: @"</Add>"];
|
||||
}
|
||||
} // for ...
|
||||
|
||||
folderMetadata = [NSDictionary dictionaryWithObject: [theCollection davCollectionTag]
|
||||
forKey: @"SyncKey"];
|
||||
[self _setFolderMetadata: folderMetadata
|
||||
forKey: [NSString stringWithFormat: @"%@/%@", component_name, [theCollection nameInContainer]]];
|
||||
}
|
||||
break;
|
||||
case ActiveSyncMailFolder:
|
||||
default:
|
||||
{
|
||||
NSMutableArray *addedOrChangedMessages;
|
||||
SOGoSyncCacheObject *lastCacheObject, *aCacheObject;
|
||||
NSMutableArray *allCacheObjects, *sortedBySequence;
|
||||
|
||||
SOGoMailObject *mailObject;
|
||||
NSString *uid, *command;
|
||||
NSDictionary *aMessage;
|
||||
NSArray *allMessages;
|
||||
int deleted_count;
|
||||
|
||||
int j, k, return_count;
|
||||
BOOL found_in_cache;
|
||||
|
||||
|
||||
allMessages = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType];
|
||||
addedOrChangedMessages = [NSMutableArray array];
|
||||
deleted_count = 0;
|
||||
|
||||
// Check for the WindowSize.
|
||||
// FIXME: we should eventually check for modseq and slice the maximum
|
||||
// amount of messages returned to ensure we don't have the same
|
||||
// modseq accross contiguous boundaries
|
||||
max = [allMessages count];
|
||||
|
||||
// We first check the number of deleted messages we have
|
||||
// We do NOT honor the window size here as it seems to be
|
||||
// impossible to get the modseq of an expunged message so
|
||||
// we can't iterate in the list of deleted messages.
|
||||
for (i = 0; i < max; i++)
|
||||
{
|
||||
aMessage = [allMessages objectAtIndex: i];
|
||||
|
||||
uid = [[[aMessage allKeys] lastObject] stringValue];
|
||||
command = [[aMessage allValues] lastObject];
|
||||
|
||||
if ([command isEqualToString: @"deleted"])
|
||||
{
|
||||
[s appendString: @"<Delete xmlns=\"AirSync:\">"];
|
||||
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", uid];
|
||||
[s appendString: @"</Delete>"];
|
||||
deleted_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
[addedOrChangedMessages addObject: aMessage];
|
||||
}
|
||||
}
|
||||
|
||||
// We then "pad" with our added/changed messages. We ALWAYS
|
||||
// at least return one if available
|
||||
max = [addedOrChangedMessages count];
|
||||
allCacheObjects = [NSMutableArray array];
|
||||
|
||||
for (i = 0; i < max; i++)
|
||||
{
|
||||
aMessage = [addedOrChangedMessages objectAtIndex: i];
|
||||
|
||||
uid = [[[aMessage allKeys] lastObject] stringValue];
|
||||
command = [[aMessage allValues] lastObject];
|
||||
|
||||
if ([command isEqualToString: @"added"])
|
||||
[s appendString: @"<Add xmlns=\"AirSync:\">"];
|
||||
else
|
||||
[s appendString: @"<Change xmlns=\"AirSync:\">"];
|
||||
|
||||
mailObject = [theCollection lookupName: uid
|
||||
inContext: context
|
||||
acquire: 0];
|
||||
|
||||
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", uid];
|
||||
[s appendString: @"<ApplicationData xmlns=\"AirSync:\">"];
|
||||
[s appendString: [mailObject activeSyncRepresentationInContext: context]];
|
||||
[s appendString: @"</ApplicationData>"];
|
||||
|
||||
if ([command isEqualToString: @"added"])
|
||||
[s appendString: @"</Add>"];
|
||||
else
|
||||
[s appendString: @"</Change>"];
|
||||
|
||||
|
||||
// We check if we must stop padding
|
||||
if (i+1+deleted_count > theWindowSize)
|
||||
[allCacheObjects addObject: [SOGoSyncCacheObject syncCacheObjectWithUID: [[[allMessages objectAtIndex: i] allKeys] lastObject]
|
||||
sequence: [[[allMessages objectAtIndex: i] allValues] lastObject]]];
|
||||
}
|
||||
|
||||
// If it's a new Sync operation, DateCache and SyncCache need to be deleted
|
||||
// but GUID stored by folderSync shouldn't be touched
|
||||
folderMetadata = [self _folderMetadataForKey: [theCollection nameInContainer]];
|
||||
if ([theSyncKey isEqualToString: @"-1"])
|
||||
{
|
||||
[folderMetadata setObject: [NSMutableDictionary dictionary] forKey: @"SyncCache"];
|
||||
[folderMetadata setObject: [NSMutableDictionary dictionary] forKey: @"DateCache"];
|
||||
}
|
||||
|
||||
// Check whether GUID in cache is equal to the GUID from imap - this is to avoid cache corruptions if a folder has been renamed and a new folder
|
||||
// with the same name has been created but folderSync has not yet updated the cache
|
||||
if (!([[theCollection nameInContainer] isEqualToString:
|
||||
[NSString stringWithFormat: @"folder%@", [self globallyUniqueIDToIMAPFolderName: [folderMetadata objectForKey: @"GUID"] type: theFolderType]]]))
|
||||
{
|
||||
NSLog(@"GUID mismatch don't sync now!");
|
||||
return;
|
||||
}
|
||||
|
||||
syncCache = [folderMetadata objectForKey: @"SyncCache"];
|
||||
dateCache = [folderMetadata objectForKey: @"DateCache"];
|
||||
|
||||
sortedBySequence = [[NSMutableArray alloc] initWithDictionary: syncCache];
|
||||
[sortedBySequence sortUsingSelector: @selector(compareSequence:)];
|
||||
[sortedBySequence autorelease];
|
||||
|
||||
[allCacheObjects sortUsingSelector: @selector(compareSequence:)];
|
||||
|
||||
//NSLog(@"sortedBySequence (%d) - lastObject: %@", [sortedBySequence count], [sortedBySequence lastObject]);
|
||||
//NSLog(@"allCacheObjects (%d) - lastObject: %@", [allCacheObjects count], [allCacheObjects lastObject]);
|
||||
|
||||
lastCacheObject = [sortedBySequence lastObject];
|
||||
|
||||
if ([folderMetadata objectForKey: @"MoreAvailable"] && lastCacheObject)
|
||||
{
|
||||
for (j = 0; j < [allCacheObjects count]; j++)
|
||||
{
|
||||
more_available = YES;
|
||||
break;
|
||||
if ([[lastCacheObject uid] isEqual: [[allCacheObjects objectAtIndex: j] uid]])
|
||||
{
|
||||
// Found out where we're at, let's continue from there...
|
||||
found_in_cache = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
else
|
||||
found_in_cache = NO;
|
||||
|
||||
|
||||
if (found_in_cache)
|
||||
k = j+1;
|
||||
else
|
||||
{
|
||||
k = 0;
|
||||
j = 0;
|
||||
}
|
||||
|
||||
//NSLog(@"found in cache: %d k = %d", found_in_cache, k);
|
||||
|
||||
return_count = 0;
|
||||
|
||||
for (; k < [allCacheObjects count]; k++)
|
||||
{
|
||||
// Check for the WindowSize and slice accordingly
|
||||
if (return_count >= theWindowSize)
|
||||
{
|
||||
NSString *lastSequence;
|
||||
more_available = YES;
|
||||
|
||||
lastSequence = ([[aCacheObject sequence] isEqual: [NSNull null]] ? @"1" : [aCacheObject sequence]);
|
||||
*theLastServerKey = [NSString stringWithFormat: @"%@-%@", [aCacheObject uid], lastSequence];
|
||||
//NSLog(@"Reached windowSize - lastUID will be: %@", *theLastServerKey);
|
||||
break;
|
||||
}
|
||||
|
||||
aCacheObject = [allCacheObjects objectAtIndex: k];
|
||||
|
||||
// If found in cache, it's either a Change or a Delete
|
||||
if ([syncCache objectForKey: [aCacheObject uid]])
|
||||
{
|
||||
if ([[aCacheObject sequence] isEqual: [NSNull null]])
|
||||
{
|
||||
// Deleted
|
||||
[s appendString: @"<Delete xmlns=\"AirSync:\">"];
|
||||
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", [aCacheObject uid]];
|
||||
[s appendString: @"</Delete>"];
|
||||
|
||||
[syncCache removeObjectForKey: [aCacheObject uid]];
|
||||
[dateCache removeObjectForKey: [aCacheObject uid]];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Changed
|
||||
outlook_hack:
|
||||
mailObject = [theCollection lookupName: [aCacheObject uid]
|
||||
inContext: context
|
||||
acquire: 0];
|
||||
|
||||
[s appendString: @"<Change xmlns=\"AirSync:\">"];
|
||||
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", [aCacheObject uid]];
|
||||
[s appendString: @"<ApplicationData xmlns=\"AirSync:\">"];
|
||||
[s appendString: [mailObject activeSyncRepresentationInContext: context]];
|
||||
[s appendString: @"</ApplicationData>"];
|
||||
[s appendString: @"</Change>"];
|
||||
|
||||
[syncCache setObject: [aCacheObject sequence] forKey: [aCacheObject uid]];
|
||||
}
|
||||
|
||||
return_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Added
|
||||
if (![[aCacheObject sequence] isEqual: [NSNull null]])
|
||||
{
|
||||
NSString *key;
|
||||
|
||||
// We check for Outlook stupidity to avoid creating duplicates - see the comment
|
||||
// in SOGoActiveSyncDispatcher.m: -processMoveItems:inResponse: for more details.
|
||||
key = [NSString stringWithFormat: @"%@+%@+%@+%@",
|
||||
[[context activeUser] login],
|
||||
[context objectForKey: @"DeviceType"],
|
||||
[theCollection displayName],
|
||||
[aCacheObject uid]];
|
||||
|
||||
if ([[SOGoCache sharedCache] valueForKey: key])
|
||||
{
|
||||
[[SOGoCache sharedCache] removeValueForKey: key];
|
||||
goto outlook_hack;
|
||||
}
|
||||
|
||||
mailObject = [theCollection lookupName: [aCacheObject uid]
|
||||
inContext: context
|
||||
acquire: 0];
|
||||
|
||||
[s appendString: @"<Add xmlns=\"AirSync:\">"];
|
||||
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", [aCacheObject uid]];
|
||||
[s appendString: @"<ApplicationData xmlns=\"AirSync:\">"];
|
||||
[s appendString: [mailObject activeSyncRepresentationInContext: context]];
|
||||
[s appendString: @"</ApplicationData>"];
|
||||
[s appendString: @"</Add>"];
|
||||
|
||||
[syncCache setObject: [aCacheObject sequence] forKey: [aCacheObject uid]];
|
||||
[dateCache setObject: [NSCalendarDate date] forKey: [aCacheObject uid]];
|
||||
return_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
//NSLog(@"skipping old deleted UID: %@", [aCacheObject uid]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (more_available)
|
||||
{
|
||||
*theLastServerKey = uid;
|
||||
[folderMetadata setObject: [NSNumber numberWithBool: YES] forKey: @"MoreAvailable"];
|
||||
[folderMetadata setObject: *theLastServerKey forKey: @"SyncKey"];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[folderMetadata removeObjectForKey: @"MoreAvailable"];
|
||||
[folderMetadata setObject: [theCollection davCollectionTag] forKey: @"SyncKey"];
|
||||
}
|
||||
|
||||
[self _setFolderMetadata: folderMetadata
|
||||
forKey: [theCollection nameInContainer]];
|
||||
} // default:
|
||||
break;
|
||||
} // switch (folderType) ...
|
||||
|
||||
return_response:
|
||||
|
||||
if ([s length])
|
||||
{
|
||||
[theBuffer appendString: @"<Commands>"];
|
||||
@@ -757,13 +954,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
NSMutableString *changeBuffer, *commandsBuffer;
|
||||
BOOL getChanges, first_sync;
|
||||
unsigned int windowSize;
|
||||
unsigned int windowSize, v;
|
||||
|
||||
changeBuffer = [NSMutableString string];
|
||||
commandsBuffer = [NSMutableString string];
|
||||
|
||||
collectionId = [[(id)[theDocumentElement getElementsByTagName: @"CollectionId"] lastObject] textValue];
|
||||
realCollectionId = [collectionId realCollectionIdWithFolderType: &folderType];
|
||||
realCollectionId = [self globallyUniqueIDToIMAPFolderName: realCollectionId type: folderType];
|
||||
collection = [self collectionFromId: realCollectionId type: folderType];
|
||||
|
||||
syncKey = davCollectionTag = [[(id)[theDocumentElement getElementsByTagName: @"SyncKey"] lastObject] textValue];
|
||||
@@ -773,6 +971,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if (windowSize == 0 || windowSize > 512)
|
||||
windowSize = 100;
|
||||
|
||||
// We check if we must overwrite the windowSize with a system preference. This can be useful
|
||||
// if the user population has large mailboxes and slow connectivity
|
||||
if ((v = [[SOGoSystemDefaults sharedSystemDefaults] maximumSyncWindowSize]))
|
||||
windowSize = v;
|
||||
|
||||
lastServerKey = nil;
|
||||
|
||||
@@ -845,12 +1048,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
if ([changeBuffer length] || [commandsBuffer length])
|
||||
{
|
||||
if (lastServerKey)
|
||||
davCollectionTag = [collection davCollectionTagFromId: lastServerKey];
|
||||
else
|
||||
davCollectionTag = lastServerKey;
|
||||
else if (![[self _folderMetadataForKey: [collection nameInContainer]] objectForKey: @"MoreAvailable"])
|
||||
davCollectionTag = [collection davCollectionTag];
|
||||
|
||||
*changeDetected = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (folderType == ActiveSyncMailFolder && [syncKey isEqualToString: @"-1"])
|
||||
davCollectionTag = [collection davCollectionTag];
|
||||
}
|
||||
|
||||
// Generate the response buffer
|
||||
[theBuffer appendString: @"<Collection>"];
|
||||
|
||||
@@ -32,17 +32,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "SOGoActiveSyncConstants.h"
|
||||
|
||||
@class NSException;
|
||||
@class NSURL;
|
||||
|
||||
@interface SOGoActiveSyncDispatcher : NSObject
|
||||
{
|
||||
NSURL *folderTableURL;
|
||||
id context;
|
||||
}
|
||||
|
||||
- (id) collectionFromId: (NSString *) theCollectionId
|
||||
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType;
|
||||
|
||||
- (id) globallyUniqueIDToIMAPFolderName: (NSString *) theIdToTranslate
|
||||
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType;
|
||||
|
||||
- (NSException *) dispatchRequest: (id) theRequest
|
||||
inResponse: (id) theResponse
|
||||
context: (id) theContext;
|
||||
|
||||
- (NSURL *) folderTableURL;
|
||||
- (void) ensureFolderTableExists;
|
||||
|
||||
@end
|
||||
File diff suppressed because it is too large.
Load diff
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "SOGoMailObject+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSException.h>
|
||||
@@ -42,12 +43,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
#import <NGExtensions/NGQuotedPrintableCoding.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGExtensions/NSString+Encoding.h>
|
||||
#import <NGImap4/NGImap4Envelope.h>
|
||||
#import <NGImap4/NGImap4EnvelopeAddress.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
|
||||
#import <NGMime/NGMimeBodyPart.h>
|
||||
#import <NGMime/NGMimeFileData.h>
|
||||
#import <NGMime/NGMimeMultipartBody.h>
|
||||
#import <NGMime/NGMimeType.h>
|
||||
#import <NGMail/NGMimeMessageParser.h>
|
||||
#import <NGMail/NGMimeMessage.h>
|
||||
#import <NGMail/NGMimeMessageGenerator.h>
|
||||
|
||||
#include "iCalTimeZone+ActiveSync.h"
|
||||
#include "NSData+ActiveSync.h"
|
||||
#include "NSDate+ActiveSync.h"
|
||||
@@ -196,7 +206,7 @@ struct GlobalObjectId {
|
||||
//
|
||||
- (NSData *) _preferredBodyDataInMultipartUsingType: (int) theType
|
||||
{
|
||||
NSString *key, *plainKey, *htmlKey, *type, *subtype;
|
||||
NSString *encoding, *key, *plainKey, *htmlKey, *type, *subtype;
|
||||
NSDictionary *textParts, *part;
|
||||
NSEnumerator *e;
|
||||
NSData *d;
|
||||
@@ -219,18 +229,156 @@ struct GlobalObjectId {
|
||||
plainKey = key;
|
||||
}
|
||||
|
||||
key = nil;
|
||||
|
||||
if (theType == 2)
|
||||
{
|
||||
d = [[self fetchPlainTextParts] objectForKey: htmlKey];
|
||||
}
|
||||
key = htmlKey;
|
||||
else if (theType == 1)
|
||||
key = plainKey;
|
||||
|
||||
if (key)
|
||||
{
|
||||
d = [[self fetchPlainTextParts] objectForKey: plainKey];
|
||||
NSString *s, *charset;
|
||||
|
||||
d = [[self fetchPlainTextParts] objectForKey: key];
|
||||
|
||||
encoding = [[self lookupInfoForBodyPart: key] objectForKey: @"encoding"];
|
||||
|
||||
if ([encoding caseInsensitiveCompare: @"base64"] == NSOrderedSame)
|
||||
d = [d dataByDecodingBase64];
|
||||
else if ([encoding caseInsensitiveCompare: @"quoted-printable"] == NSOrderedSame)
|
||||
d = [d dataByDecodingQuotedPrintableTransferEncoding];
|
||||
|
||||
charset = [[[self lookupInfoForBodyPart: key] objectForKey: @"parameterList"] objectForKey: @"charset"];
|
||||
|
||||
if (![charset length])
|
||||
charset = @"us-ascii";
|
||||
|
||||
s = [NSString stringWithData: d usingEncodingNamed: charset];
|
||||
d = [s dataUsingEncoding: NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) _sanitizedMIMEPart: (id) thePart
|
||||
performed: (BOOL *) b
|
||||
{
|
||||
if ([thePart isKindOfClass: [NGMimeMultipartBody class]])
|
||||
{
|
||||
NGMimeBodyPart *part;
|
||||
NSArray *parts;
|
||||
int i;
|
||||
|
||||
parts = [thePart parts];
|
||||
|
||||
for (i = 0; i < [parts count]; i++)
|
||||
{
|
||||
part = [parts objectAtIndex: i];
|
||||
|
||||
[self _sanitizedMIMEPart: part
|
||||
performed: b];
|
||||
}
|
||||
}
|
||||
else if ([thePart isKindOfClass: [NGMimeBodyPart class]])
|
||||
{
|
||||
NGMimeFileData *fdata;
|
||||
id body;
|
||||
|
||||
body = [thePart body];
|
||||
|
||||
if ([body isKindOfClass: [NGMimeMultipartBody class]])
|
||||
{
|
||||
[self _sanitizedMIMEPart: body
|
||||
performed: b];
|
||||
}
|
||||
else if (([body isKindOfClass: [NSData class]] || [body isKindOfClass: [NSString class]]) &&
|
||||
[[[thePart contentType] type] isEqualToString: @"text"] &&
|
||||
([[[thePart contentType] subType] isEqualToString: @"plain"] || [[[thePart contentType] subType] isEqualToString: @"html"]))
|
||||
{
|
||||
// We make sure everything is encoded in UTF-8
|
||||
NGMimeType *mimeType;
|
||||
NSString *s;
|
||||
|
||||
if ([body isKindOfClass: [NSData class]])
|
||||
{
|
||||
NSString *charset;
|
||||
|
||||
charset = [[thePart contentType] valueOfParameter: @"charset"];
|
||||
|
||||
if (![charset length])
|
||||
charset = @"us-ascii";
|
||||
|
||||
s = [NSString stringWithData: body usingEncodingNamed: charset];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle situations when SOPE stupidly returns us a NSString
|
||||
// This can happen for Content-Type: text/plain, Content-Transfer-Encoding: 8bit
|
||||
s = body;
|
||||
}
|
||||
|
||||
if (s)
|
||||
{
|
||||
body = [s dataUsingEncoding: NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
mimeType = [NGMimeType mimeType: [[thePart contentType] type]
|
||||
subType: [[thePart contentType] subType]
|
||||
parameters: [NSDictionary dictionaryWithObject: @"utf-8" forKey: @"charset"]];
|
||||
[thePart setHeader: mimeType forKey: @"content-type"];
|
||||
|
||||
fdata = [[NGMimeFileData alloc] initWithBytes: [body bytes]
|
||||
length: [body length]];
|
||||
|
||||
[thePart setBody: fdata];
|
||||
RELEASE(fdata);
|
||||
*b = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (NSData *) _sanitizedMIMEMessage
|
||||
{
|
||||
NGMimeMessageParser *parser;
|
||||
NGMimeMessage *message;
|
||||
NSData *d;
|
||||
|
||||
BOOL b;
|
||||
|
||||
d = [self content];
|
||||
|
||||
parser = [[NGMimeMessageParser alloc] init];
|
||||
AUTORELEASE(parser);
|
||||
|
||||
message = [parser parsePartFromData: d];
|
||||
b = NO;
|
||||
|
||||
if (message)
|
||||
{
|
||||
[self _sanitizedMIMEPart: [message body]
|
||||
performed: &b];
|
||||
|
||||
if (b)
|
||||
{
|
||||
NGMimeMessageGenerator *generator;
|
||||
|
||||
generator = [[NGMimeMessageGenerator alloc] init];
|
||||
AUTORELEASE(generator);
|
||||
|
||||
d = [generator generateMimeFromPart: message];
|
||||
}
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -258,6 +406,13 @@ struct GlobalObjectId {
|
||||
{
|
||||
if ([type isEqualToString: @"text"])
|
||||
{
|
||||
NSString *s, *charset;
|
||||
|
||||
charset = [[[self lookupInfoForBodyPart: @""] objectForKey: @"parameterList"] objectForKey: @"charset"];
|
||||
|
||||
if (![charset length])
|
||||
charset = @"us-ascii";
|
||||
|
||||
d = [[self fetchPlainTextParts] objectForKey: @""];
|
||||
|
||||
// We check if we have base64 encoded parts. If so, we just
|
||||
@@ -266,18 +421,18 @@ struct GlobalObjectId {
|
||||
|
||||
if ([encoding caseInsensitiveCompare: @"base64"] == NSOrderedSame)
|
||||
d = [d dataByDecodingBase64];
|
||||
else if ([encoding caseInsensitiveCompare: @"quoted-printable"] == NSOrderedSame)
|
||||
d = [d dataByDecodingQuotedPrintableTransferEncoding];
|
||||
|
||||
s = [NSString stringWithData: d usingEncodingNamed: charset];
|
||||
|
||||
// Check if we must convert html->plain
|
||||
if (theType == 1 && [subtype isEqualToString: @"html"])
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [[NSString alloc] initWithData: d encoding: NSUTF8StringEncoding];
|
||||
AUTORELEASE(s);
|
||||
|
||||
s = [s htmlToText];
|
||||
d = [s dataUsingEncoding: NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
d = [s dataUsingEncoding: NSUTF8StringEncoding];
|
||||
}
|
||||
else if ([type isEqualToString: @"multipart"])
|
||||
{
|
||||
@@ -286,7 +441,12 @@ struct GlobalObjectId {
|
||||
}
|
||||
else if (theType == 4)
|
||||
{
|
||||
d = [self content];
|
||||
// We sanitize the content *ONLY* for Outlook clients. Outlook has strange issues
|
||||
// with quoted-printable/base64 encoded text parts. It just doesn't decode them.
|
||||
if ([[context objectForKey: @"DeviceType"] isEqualToString: @"WindowsOutlook15"])
|
||||
d = [self _sanitizedMIMEMessage];
|
||||
else
|
||||
d = [self content];
|
||||
}
|
||||
|
||||
return d;
|
||||
@@ -346,7 +506,9 @@ struct GlobalObjectId {
|
||||
//
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) _context
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
NSData *d, *globalObjId;
|
||||
NSArray *attachmentKeys;
|
||||
NSMutableString *s;
|
||||
id value;
|
||||
|
||||
@@ -531,11 +693,16 @@ struct GlobalObjectId {
|
||||
// [s appendFormat: @"<Reply-To xmlns=\"Email:\">%@</Reply-To>", [addressFormatter stringForArray: replyTo]];
|
||||
|
||||
// InternetCPID - 65001 == UTF-8, we use this all the time for now.
|
||||
// - 20127 == US-ASCII
|
||||
[s appendFormat: @"<InternetCPID xmlns=\"Email:\">%@</InternetCPID>", @"65001"];
|
||||
|
||||
// Body - namespace 17
|
||||
preferredBodyType = [[context objectForKey: @"BodyPreferenceType"] intValue];
|
||||
|
||||
// Make use of a local pool here as _preferredBodyDataUsingType:nativeType: will consume
|
||||
// a significant amout of RAM and file descriptors
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
nativeBodyType = 1;
|
||||
d = [self _preferredBodyDataUsingType: preferredBodyType nativeType: &nativeBodyType];
|
||||
|
||||
@@ -549,6 +716,10 @@ struct GlobalObjectId {
|
||||
// FIXME: This is a hack. We should normally avoid doing this as we might get
|
||||
// broken encodings. We should rather tell that the data was truncated and expect
|
||||
// a ItemOperations call to download the whole base64 encoding multipart.
|
||||
//
|
||||
// See http://social.msdn.microsoft.com/Forums/en-US/b9944e49-9bc9-4ab8-ba33-a9fc08557c5b/mime-raw-data-in-eas-sync-response?forum=os_exchangeprotocols
|
||||
// for an "interesting" discussion around this.
|
||||
//
|
||||
if (!content)
|
||||
content = [[NSString alloc] initWithData: d encoding: NSISOLatin1StringEncoding];
|
||||
|
||||
@@ -561,15 +732,21 @@ struct GlobalObjectId {
|
||||
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", preferredBodyType];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", len];
|
||||
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
|
||||
[s appendFormat: @"<Truncated>%d</Truncated>", truncated];
|
||||
[s appendFormat: @"<Preview></Preview>"];
|
||||
|
||||
if (!truncated)
|
||||
[s appendFormat: @"<Data>%@</Data>", content];
|
||||
{
|
||||
[s appendFormat: @"<Data>%@</Data>", content];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", len];
|
||||
}
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
|
||||
DESTROY(pool);
|
||||
|
||||
// Attachments -namespace 16
|
||||
NSArray *attachmentKeys = [self fetchFileAttachmentKeys];
|
||||
attachmentKeys = [self fetchFileAttachmentKeys];
|
||||
if ([attachmentKeys count])
|
||||
{
|
||||
int i;
|
||||
@@ -599,7 +776,7 @@ struct GlobalObjectId {
|
||||
|
||||
// Flags
|
||||
[s appendString: @"<Flag xmlns=\"Email:\">"];
|
||||
[s appendFormat: @"<FlagStatus>%d</FlagStatus>", 0];
|
||||
[s appendFormat: @"<FlagStatus>%d</FlagStatus>", ([self flagged] ? 2 : 0)];
|
||||
[s appendString: @"</Flag>"];
|
||||
|
||||
// FIXME - support these in the future
|
||||
@@ -620,6 +797,16 @@ struct GlobalObjectId {
|
||||
//
|
||||
//
|
||||
//
|
||||
// Exemple for a message being marked as read:
|
||||
//
|
||||
// <Change>
|
||||
// <ServerId>607</ServerId>
|
||||
// <ApplicationData>
|
||||
// <Read xmlns="Email:">1</Read>
|
||||
// </ApplicationData>
|
||||
// </Change>
|
||||
// </Commands>
|
||||
//
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) _context
|
||||
{
|
||||
@@ -627,13 +814,32 @@ struct GlobalObjectId {
|
||||
|
||||
if ((o = [theValues objectForKey: @"Flag"]))
|
||||
{
|
||||
o = [o objectForKey: @"FlagStatus"];
|
||||
|
||||
if ([o intValue])
|
||||
[self addFlags: @"\\Flagged"];
|
||||
// We must handle empty flags -> {Flag = ""; } - some ActiveSync clients, like the HTC Desire
|
||||
// will send an empty Flag message when "unflagging" a mail.
|
||||
if (([o isKindOfClass: [NSMutableDictionary class]]))
|
||||
{
|
||||
if ((o = [o objectForKey: @"FlagStatus"]))
|
||||
{
|
||||
// 0 = The flag is cleared.
|
||||
// 1 = The status is set to complete.
|
||||
// 2 = The status is set to active.
|
||||
if (([o isEqualToString: @"2"]))
|
||||
[self addFlags: @"\\Flagged"];
|
||||
else
|
||||
[self removeFlags: @"\\Flagged"];
|
||||
}
|
||||
}
|
||||
else
|
||||
[self removeFlags: @"\\Flagged"];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"Read"]))
|
||||
{
|
||||
if ([o intValue])
|
||||
[self addFlags: @"seen"];
|
||||
else
|
||||
[self removeFlags: @"seen"];;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __SOGOSYNCCACHEOBJECT_H__
|
||||
#define __SOGOSYNCCACHEOBJECT_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class NSNull;
|
||||
|
||||
@interface SOGoSyncCacheObject : NSObject
|
||||
{
|
||||
id _uid;
|
||||
id _sequence;
|
||||
}
|
||||
|
||||
+ (id) syncCacheObjectWithUID: (id) theUID sequence: (id) theSequence;
|
||||
- (id) uid;
|
||||
- (void) setUID: (id) theUID;
|
||||
- (id) sequence;
|
||||
- (void) setSequence: (id) theSequence;
|
||||
|
||||
- (NSComparisonResult) compareUID: (SOGoSyncCacheObject *) theSyncCacheObject;
|
||||
- (NSComparisonResult) compareSequence: (SOGoSyncCacheObject *) theSyncCacheObject;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "SOGoSyncCacheObject.h"
|
||||
|
||||
#import <Foundation/NSNull.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
@implementation SOGoSyncCacheObject
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_uid = nil;
|
||||
_sequence = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id) syncCacheObjectWithUID: (id) theUID sequence: (id) theSequence;
|
||||
{
|
||||
id o;
|
||||
|
||||
o = [[self alloc] init];
|
||||
|
||||
[o setUID: theUID];
|
||||
[o setSequence: theSequence];
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(_uid);
|
||||
RELEASE(_sequence);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) uid
|
||||
{
|
||||
return _uid;
|
||||
}
|
||||
|
||||
- (void) setUID: (id) theUID
|
||||
{
|
||||
ASSIGN(_uid, theUID);
|
||||
}
|
||||
|
||||
- (id) sequence
|
||||
{
|
||||
return _sequence;
|
||||
}
|
||||
|
||||
- (void) setSequence: (id) theSequence
|
||||
{
|
||||
ASSIGN(_sequence, theSequence);
|
||||
}
|
||||
|
||||
|
||||
- (NSComparisonResult) compareUID: (SOGoSyncCacheObject *) theSyncCacheObject
|
||||
{
|
||||
return [[self uid] compare: [theSyncCacheObject uid]];
|
||||
}
|
||||
|
||||
//
|
||||
// We might get NSNull values here, so if both are NSNull instances,
|
||||
// we sort by UID. If both sequences are equal, we also sort by UID.
|
||||
//
|
||||
- (NSComparisonResult) compareSequence: (SOGoSyncCacheObject *) theSyncCacheObject
|
||||
{
|
||||
if ([[self sequence] isEqual: [NSNull null]] &&
|
||||
[[theSyncCacheObject sequence] isEqual: [NSNull null]])
|
||||
return [self compareUID: theSyncCacheObject];
|
||||
|
||||
if (![[self sequence] isEqual: [NSNull null]] && [[theSyncCacheObject sequence] isEqual: [NSNull null]])
|
||||
return NSOrderedDescending;
|
||||
|
||||
if ([[self sequence] isEqual: [NSNull null]] && ![[theSyncCacheObject sequence] isEqual: [NSNull null]])
|
||||
return NSOrderedAscending;
|
||||
|
||||
// Must check this here, to avoid comparing NSNull objects
|
||||
if ([[self sequence] compare: [theSyncCacheObject sequence]] == NSOrderedSame)
|
||||
return [self compareUID: theSyncCacheObject];
|
||||
|
||||
return [[self sequence] compare: [theSyncCacheObject sequence]];
|
||||
}
|
||||
|
||||
- (NSString *) description
|
||||
{
|
||||
return [NSString stringWithFormat: @"%@-%@", _uid, _sequence];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -62,7 +62,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[response setHeader: @"OPTIONS, POST" forKey: @"Allow"];
|
||||
[response setHeader: @"14.1" forKey: @"MS-Server-ActiveSync"];
|
||||
[response setHeader: @"2.0,2.1,2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
|
||||
[response setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,Provision,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
|
||||
[response setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
|
||||
[response setHeader: @"OPTIONS, POST" forKey: @"Public"];
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# common make file for SoObject bundles
|
||||
|
||||
include ../config.make
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
include ../Version
|
||||
@@ -18,10 +16,10 @@ ADDITIONAL_INCLUDE_DIRS += \
|
||||
-I../../SOPE
|
||||
|
||||
ADDITIONAL_LIB_DIRS += \
|
||||
-L../SOGo/SOGo.framework/ \
|
||||
-L../../SOGo/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L../../OGoContentStore/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L../../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L../SoObjects/SOGo/SOGo.framework/ \
|
||||
-L../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L../OGoContentStore/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L/usr/local/lib
|
||||
|
||||
BUNDLE_LIBS += \
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __ICALALARMACTIVESYNC_H__
|
||||
#define __ICALALARMACTIVESYNC_H__
|
||||
|
||||
#import <NGCards/iCalAlarm.h>
|
||||
|
||||
@class NSString;
|
||||
@class WOContext;
|
||||
|
||||
@interface iCalAlarm (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#import "iCalAlarm+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
|
||||
#import <NGCards/iCalAlarm.h>
|
||||
#import <NGCards/iCalEvent.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
|
||||
@implementation iCalAlarm (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSMutableString *s;
|
||||
|
||||
s = [NSMutableString string];
|
||||
|
||||
if ([[self action] caseInsensitiveCompare: @"DISPLAY"] == NSOrderedSame)
|
||||
{
|
||||
NSCalendarDate *nextAlarmDate;
|
||||
NSInteger delta;
|
||||
|
||||
nextAlarmDate = [self nextAlarmDate];
|
||||
delta = (int)(([[(iCalEvent *)parent startDate] timeIntervalSince1970] - [nextAlarmDate timeIntervalSince1970])/60);
|
||||
|
||||
// don't send negative reminder - not supported
|
||||
if (delta > 0)
|
||||
[s appendFormat: @"<Reminder xmlns=\"Calendar:\">%d</Reminder>", delta];
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
iCalTrigger *trigger;
|
||||
id o;
|
||||
|
||||
o = [theValues objectForKey: @"Reminder"];
|
||||
|
||||
// Outlook: if reminder is set to 0 minutes before start save it as 1 minute since -> 0 minutes in not accepted by SOGo
|
||||
if ([o isEqualToString: @"0"])
|
||||
o = @"1";
|
||||
|
||||
trigger = [iCalTrigger elementWithTag: @"TRIGGER"];
|
||||
[trigger setValueType: @"DURATION"];
|
||||
[self setTrigger: trigger];
|
||||
[self setAction: @"DISPLAY"];
|
||||
|
||||
// SOGo web ui only supports 1w but not 2w (custom reminder only supports min/hours/days)
|
||||
// 1week = -P1W
|
||||
// 2weeks > -PxD
|
||||
// xdays > -PxD
|
||||
// xhours -> -PTxH
|
||||
// xmin -> -PTxM
|
||||
if ([o intValue] == 10080)
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-P1W" ] forKey: @""];
|
||||
else
|
||||
{
|
||||
if (([o intValue] % 1440) == 0)
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-P%dD", ([o intValue] / 1440)] forKey: @""];
|
||||
else
|
||||
{
|
||||
if (([o intValue] % 60) == 0)
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%dH", ([o intValue] / 60)] forKey: @""];
|
||||
else
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%@M", o] forKey: @""];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -50,6 +50,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import <Appointments/iCalEntityObject+SOGo.h>
|
||||
|
||||
#include "iCalAlarm+ActiveSync.h"
|
||||
#include "iCalRecurrenceRule+ActiveSync.h"
|
||||
#include "iCalTimeZone+ActiveSync.h"
|
||||
#include "NSDate+ActiveSync.h"
|
||||
@@ -83,6 +84,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
int v;
|
||||
|
||||
NSTimeZone *userTimeZone;
|
||||
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
||||
|
||||
s = [NSMutableString string];
|
||||
|
||||
[s appendFormat: @"<AllDayEvent xmlns=\"Calendar:\">%d</AllDayEvent>", ([self isAllDay] ? 1 : 0)];
|
||||
@@ -95,12 +99,30 @@ 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])
|
||||
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>", [[self startDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
|
||||
{
|
||||
if ([self isAllDay])
|
||||
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>",
|
||||
[[[self startDate] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: ([userTimeZone secondsFromGMTForDate: [self startDate]])*-1]
|
||||
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
else
|
||||
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>", [[self startDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
|
||||
// EndTime -- http://msdn.microsoft.com/en-us/library/ee157945(v=exchg.80).aspx
|
||||
if ([self endDate])
|
||||
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>", [[self endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
|
||||
{
|
||||
if ([self isAllDay])
|
||||
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>",
|
||||
[[[self endDate] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: ([userTimeZone secondsFromGMTForDate: [self endDate]])*-1]
|
||||
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
else
|
||||
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>", [[self endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
|
||||
// Timezone
|
||||
tz = [(iCalDateTime *)[self firstChildWithTag: @"dtstart"] timeZone];
|
||||
|
||||
@@ -138,7 +160,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
attendee = [attendees objectAtIndex: i];
|
||||
[s appendFormat: @"<Attendee_Email xmlns=\"Calendar:\">%@</Attendee_Email>", [attendee rfc822Email]];
|
||||
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [attendee cn]];
|
||||
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee cn] activeSyncRepresentationInContext: context]];
|
||||
|
||||
attendee_status = [self _attendeeStatus: attendee];
|
||||
|
||||
@@ -209,7 +231,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendFormat: @"<Sensitivity xmlns=\"Calendar:\">%d</Sensitivity>", v];
|
||||
|
||||
// Reminder -- http://msdn.microsoft.com/en-us/library/ee219691(v=exchg.80).aspx
|
||||
// TODO
|
||||
// TODO: improve this to handle more alarm types
|
||||
if ([self hasAlarms])
|
||||
{
|
||||
iCalAlarm *alarm;
|
||||
|
||||
alarm = [[self alarms] objectAtIndex: 0];
|
||||
[s appendString: [alarm activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
// Recurrence rules
|
||||
if ([self isRecurrent])
|
||||
@@ -356,6 +385,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if (isAllDay)
|
||||
{
|
||||
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
||||
o = [o dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: tzOffset];
|
||||
[start setDate: o];
|
||||
[start setTimeZone: nil];
|
||||
}
|
||||
@@ -377,6 +410,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if (isAllDay)
|
||||
{
|
||||
tzOffset = [userTimeZone secondsFromGMTForDate: o];
|
||||
o = [o dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: tzOffset];
|
||||
[end setDate: o];
|
||||
[end setTimeZone: nil];
|
||||
}
|
||||
@@ -390,6 +427,35 @@ 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"]))
|
||||
{
|
||||
// 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];
|
||||
[self addToAlarms: alarm];
|
||||
RELEASE(alarm);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We remove existing alarm since no reminder in the ActiveSync payload
|
||||
[self removeAllAlarms];
|
||||
}
|
||||
|
||||
// Recurrence
|
||||
if ((o = [theValues objectForKey: @"Recurrence"]))
|
||||
{
|
||||
|
||||
@@ -34,6 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGCards/iCalEvent.h>
|
||||
#import <NGCards/iCalByDayMask.h>
|
||||
|
||||
#import "NSCalendarDate+ActiveSync.h"
|
||||
@@ -77,10 +78,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
occurrences = [[self byDayMask] weekDayOccurrences];
|
||||
v = 0;
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
if (occurrences)
|
||||
{
|
||||
if (occurrences[i])
|
||||
v += (1 << i);
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
if (occurrences[0][i])
|
||||
v += (1 << i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No byDayMask, we take the event's start date to compute the DayOfWeek
|
||||
// 0 == Sunday, 6 == Saturday
|
||||
v = (1 << [[[self parent] startDate] dayOfWeek]);
|
||||
}
|
||||
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", v];
|
||||
@@ -125,6 +135,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// FIXME
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Simple reccurrence rule of type "Monthly"
|
||||
type = 2;
|
||||
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"Calendar:\">%d</Recurrence_DayOfMonth>",
|
||||
[[[self parent] startDate] dayOfMonth]];
|
||||
}
|
||||
}
|
||||
else if ([self frequency] == iCalRecurrenceFrequenceYearly)
|
||||
{
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,3 +1,153 @@
|
||||
2.2.7 (2014-07-30)
|
||||
------------------
|
||||
|
||||
New features
|
||||
- new user preference to prevent event invitations
|
||||
|
||||
Enhancements
|
||||
- improved badges of active tasks count
|
||||
- refresh draft folder after sending a message
|
||||
- now possible to DnD events in the calendar list
|
||||
- improved handling of SOGoSubscriptionFolderFormat
|
||||
- JSON'ified folder subscription interface
|
||||
- updated Finnish, French, German, and Spanish (Spain) translations
|
||||
- updated CKEditor to version 4.4.3
|
||||
|
||||
Bug fixes
|
||||
- fixed weekdays translation in the datepicker
|
||||
- fixed event categories display
|
||||
- fixed all-day events display in IE
|
||||
- fixed rename of calendars
|
||||
- we now correctly add the "METHOD:REPLY" when sending out ITIP messages from DAV clients
|
||||
- fixed refresh of message headers when forwarding a message (#2818)
|
||||
- we now correctly escape all charset= in <meta> tags, not only in the <head>
|
||||
- we now destroy cache objects of vanished folders
|
||||
|
||||
2.2.6 (2014-07-02)
|
||||
------------------
|
||||
|
||||
New features
|
||||
- add new 'multi-columns' calendar view (#1948)
|
||||
|
||||
Enhancements
|
||||
- contacts photos are now synchronized using ActiveSync (#2807)
|
||||
- implemented the GetAttachment ActiveSync command (#2808)
|
||||
- implemented the Ping ActiveSync command
|
||||
- added "soft deletes" support for ActiveSync (#2734)
|
||||
- now display the active tasks count next to calendar names (#2760)
|
||||
|
||||
Bug fixes
|
||||
- better handling of empty "Flag" messages over ActiveSync (#2806)
|
||||
- fixed Chinese charset handling (#2809)
|
||||
- fixed folder name (calendars and contacts) of new subscriptions (#2801)
|
||||
- fixed the reply/forward operation over ActiveSync (#2805)
|
||||
- fixed regression when attaching files to a reply
|
||||
- wait 20 seconds (instead of 2) before deleting temporary download forms (#2811)
|
||||
- avoid raising exceptions when the db is down and we try to access the preferences module (#2813)
|
||||
- we now ignore the SCHEDULE-AGENT property when Thunderbird/Lightning sends it to avoid
|
||||
not-generating invitation responses for externally received IMIP messages
|
||||
- improved charset handling over ActiveSync (#2810)
|
||||
|
||||
2.2.5 (2014-06-05)
|
||||
------------------
|
||||
|
||||
Enhancements
|
||||
- new meta tag to tell IE to use the highest mode available
|
||||
- updated Dutch, Finnish, German, and Polish translations
|
||||
|
||||
Bug fixes
|
||||
- avoid crashing when we forward an email with no Subject header
|
||||
- we no longer try to include attachments when replying to a mail
|
||||
- fixed ActiveSync repetitive events issues with "Weekly" and "Monthly" ones
|
||||
- fixed ActiveSync text/plain parts re-encoding issues for Outlook
|
||||
|
||||
2.2.4 (2014-05-29)
|
||||
------------------
|
||||
|
||||
New features
|
||||
- new print option in Calendar module
|
||||
- now able to save unknown recipient emails to address book on send (#1496)
|
||||
|
||||
Enhancements
|
||||
- Sieve folder encoding is now configurable (#2622)
|
||||
- SOGo version is now displayed in preferences window (#2612)
|
||||
- report Sieve error when saving preferences (#1046)
|
||||
- added the SOGoMaximumSyncWindowSize system default to overwrite the
|
||||
maximum number of items returned during an ActiveSync sync operation
|
||||
- updated datepicker
|
||||
- addressbooks properties are now accessible from a popup window
|
||||
- extended events and tasks searches
|
||||
- updated Czech, French, Hungarian, Polish, Russian, Slovak, Spanish (Argentina), and Spanish (Spain) translations
|
||||
- added more sycned contact properties when using ActiveSync (#2775)
|
||||
- now possible to configure the default subscribed resource name using SOGoSubscriptionFolderFormat
|
||||
- now handle server-side folder updates using ActiveSync (#2688)
|
||||
- updated CKEditor to version 4.4.1
|
||||
|
||||
Bug fixes
|
||||
- fixed saved HTML content of draft when attaching a file
|
||||
- fixed text nodes of HTML content handler by encoding HTML entities
|
||||
- fixed iCal7 delegation issue with the "inbox" folder (#2489)
|
||||
- fixed birth date validity checks (#1636)
|
||||
- fixed URL handling (#2616)
|
||||
- improved folder rename operations using ActiveSync (#2700)
|
||||
- fixed SmartReply/Forward when ReplaceMime was omitted (#2680)
|
||||
- fixed wrong generation of weekly repetitive events with ActiveSync (#2654)
|
||||
- fixed incorrect XML data conversion with ActiveSync (#2695)
|
||||
- fixed display of events having a category with HTML entities (#2703)
|
||||
- fixed display of images in CSS background (#2437)
|
||||
- fixed limitation of Sieve script size (#2745)
|
||||
- fixed sync-token generation when no change was returned (#2492)
|
||||
- fixed the IMAP copy/move operation between subfolders in different accounts
|
||||
- fixed synchronization of seen/unseen status of msgs in Webmail (#2715)
|
||||
- fixed focus of popup windows open through a contextual menu with Firefox on Windows 7
|
||||
- fixed missing characters in shared folder names over ActiveSync (#2709)
|
||||
- fixed reply and forward mail templates for Brazilian Portuguese (#2738)
|
||||
- fixed newline in signature when forwarding a message as attachment in HTML mode (#2787)
|
||||
- fixed restoration of options (priority & return receipt) when editing a draft (#193)
|
||||
- fixed update of participation status via CalDAV (#2786)
|
||||
|
||||
2.2.3 (2014-04-03)
|
||||
------------------
|
||||
|
||||
Enhancements
|
||||
- updated Dutch, Hungarian, Russian and Spanish (Argentina) translations
|
||||
- initial support for ActiveSync event reminders support (#2681)
|
||||
- updated CKEditor to version 4.3.4
|
||||
|
||||
Bug fixes
|
||||
- fixed possible exception when retrieving the default event reminder value on 64bit architectures (#2678)
|
||||
- fixed calling unescapeHTML on null variables to avoid JavaScript exceptions in Contacts module
|
||||
- fixed detection of IMAP flags support on the client side (#2664)
|
||||
- fixed the ActiveSync issue marking all mails as read when downloading them
|
||||
- fixed ActiveSync's move operations not working for multiple selections (#2691)
|
||||
- fixed email validation regexp to allow gTLDs
|
||||
- improved all-day events support for ActiveSync (#2686)
|
||||
|
||||
2.2.2 (2014-03-21)
|
||||
------------------
|
||||
|
||||
Enhancements
|
||||
- updated French, Finnish, German and Spanish (Spain) translations
|
||||
- added sanitization support for Outlook/ActiveSync to circumvent Outlook bugs (#2667)
|
||||
- updated CKEditor to version 4.3.3
|
||||
- updated jQuery File Upload to version 9.5.7
|
||||
|
||||
Bug fixes
|
||||
- fixed possible exception when retrieving the default event reminder value on 64bit architectures (#2647, #2648)
|
||||
- disable file paste support in mail editor (#2641)
|
||||
- fixed copying/moving messages to a mail folder begining with a digit (#2658)
|
||||
- fixed unseen count for folders beginning with a digit and used in Sieve filters (#2652)
|
||||
- fixed decoding of HTML entities in reminder alerts (#2659)
|
||||
- fixed check for resource conflict when creating an event in the resource's calendar (#2541)
|
||||
- fixed construction of mail folders tree
|
||||
- fixed parsing of ORG attribute in cards (#2662)
|
||||
- disabled ActiveSync provisioning for now (#2663)
|
||||
- fixed messages move in Outlook which would create duplicates (#2650)
|
||||
- fixed translations for OtherUsersFolderName and SharedFoldersName folders (#2657)
|
||||
- fixed handling of accentuated characters when filtering contacts (#2656)
|
||||
- fixed classification icon of events (#2651)
|
||||
- fixed ActiveSync's SendMail with client version <= 12.1 (#2669)
|
||||
|
||||
2.2.1 (2014-03-07)
|
||||
------------------
|
||||
|
||||
@@ -13,9 +163,9 @@ Bug fixes
|
||||
- fixed wrong date format leading to Android email syncing issues (#2609)
|
||||
- fixed possible exception when retrieving the default event reminder value (#2624)
|
||||
- fixed encoding of mail folder name when creating a subfolder (#2637)
|
||||
- fixed returned date format for email messages in Active Sync
|
||||
- fixed missing 'name part' in address for email messages in Active Sync
|
||||
- fixed race condition when syncing huge amount of deleted messages over Active Sync
|
||||
- fixed returned date format for email messages in ActiveSync
|
||||
- fixed missing 'name part' in address for email messages in ActiveSync
|
||||
- fixed race condition when syncing huge amount of deleted messages over ActiveSync
|
||||
- fixed encoding of string as CSS identifier when the string starts with a digit
|
||||
- fixed auto-completion popupmenu when UID is a digit
|
||||
|
||||
|
||||
+1
-11
@@ -46,11 +46,8 @@ $(SOGOBACKEND)_OBJC_FILES += \
|
||||
MAPIStoreSamDBUtils.m \
|
||||
MAPIStoreUserContext.m \
|
||||
\
|
||||
SOGoMAPIObject.m \
|
||||
\
|
||||
SOGoMAPIDBObject.m \
|
||||
SOGoMAPIDBMessage.m \
|
||||
SOGoMAPIDBFolder.m \
|
||||
SOGoCacheGCSObject+MAPIStore.m \
|
||||
\
|
||||
MAPIStoreAppointmentWrapper.m \
|
||||
MAPIStoreAttachment.m \
|
||||
@@ -123,13 +120,6 @@ $(SOGOBACKEND)_OBJC_FILES += \
|
||||
iCalEvent+MAPIStore.m \
|
||||
iCalTimeZone+MAPIStore.m \
|
||||
\
|
||||
GCSSpecialQueries+OpenChange.m\
|
||||
\
|
||||
EOQualifier+MAPI.m \
|
||||
\
|
||||
EOBitmaskQualifier.m \
|
||||
\
|
||||
BSONCodec.m \
|
||||
RTFHandler.m
|
||||
|
||||
|
||||
|
||||
@@ -3,3 +3,6 @@ all:: MAPIStorePropertySelectors.m MAPIStorePropertySelectors.h
|
||||
MAPIStorePropertySelectors.m MAPIStorePropertySelectors.h: gen-property-selectors.py code-MAPIStorePropertySelectors.m code-MAPIStorePropertySelectors.h
|
||||
@echo " Auto-generating MAPIStorePropertySelectors.[hm]..."
|
||||
@$(PYTHON) ./gen-property-selectors.py -o MAPIStorePropertySelectors $(LIBMAPISTORE_CFLAGS)
|
||||
|
||||
distclean clean::
|
||||
-rm -f MAPIStorePropertySelectors.m MAPIStorePropertySelectors.h
|
||||
@@ -1,8 +1,6 @@
|
||||
/* MAPIStoreDBBaseContext.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2012 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2012-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
@@ -32,7 +30,7 @@
|
||||
#import "MAPIStoreDBFolder.h"
|
||||
#import "MAPIStoreMapping.h"
|
||||
#import "MAPIStoreUserContext.h"
|
||||
#import "SOGoMAPIDBFolder.h"
|
||||
#import <SOGo/SOGoCacheGCSFolder.h>
|
||||
|
||||
#import "MAPIStoreDBBaseContext.h"
|
||||
|
||||
@@ -60,7 +58,7 @@ static Class MAPIStoreDBFolderK;
|
||||
|
||||
- (void) ensureContextFolder
|
||||
{
|
||||
SOGoMAPIDBFolder *currentFolder;
|
||||
SOGoCacheGCSFolder *currentFolder;
|
||||
NSArray *parts;
|
||||
NSMutableArray *folders;
|
||||
NSString *folderName;
|
||||
@@ -78,7 +76,7 @@ static Class MAPIStoreDBFolderK;
|
||||
folderName = [parts objectAtIndex: count];
|
||||
if ([folderName length] > 0)
|
||||
{
|
||||
currentFolder = [SOGoMAPIDBFolder objectWithName: folderName
|
||||
currentFolder = [SOGoCacheGCSFolder objectWithName: folderName
|
||||
inContainer: currentFolder];
|
||||
[folders addObject: currentFolder];
|
||||
}
|
||||
@@ -98,11 +96,11 @@ static Class MAPIStoreDBFolderK;
|
||||
|
||||
- (id) rootSOGoFolder
|
||||
{
|
||||
SOGoMAPIDBFolder *folder;
|
||||
SOGoCacheGCSFolder *folder;
|
||||
|
||||
[userContext ensureFolderTableExists];
|
||||
|
||||
folder = [SOGoMAPIDBFolder objectWithName: [isa MAPIModuleName]
|
||||
folder = [SOGoCacheGCSFolder objectWithName: [isa MAPIModuleName]
|
||||
inContainer: nil];
|
||||
[folder setTableUrl: [userContext folderTableURL]];
|
||||
// [folder reloadIfNeeded];
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#import <EOControl/EOQualifier.h>
|
||||
#import <SOGo/SOGoFolder.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import "EOQualifier+MAPI.h"
|
||||
#import <SOGo/EOQualifier+SOGoCacheObject.h>
|
||||
#import "MAPIStoreContext.h"
|
||||
#import "MAPIStoreDBFolderTable.h"
|
||||
#import "MAPIStoreDBMessage.h"
|
||||
@@ -40,7 +40,7 @@
|
||||
#import "MAPIStoreMapping.h"
|
||||
#import "MAPIStoreTypes.h"
|
||||
#import "MAPIStoreUserContext.h"
|
||||
#import "SOGoMAPIDBFolder.h"
|
||||
#import <SOGo/SOGoCacheGCSFolder.h>
|
||||
#import "SOGoMAPIDBMessage.h"
|
||||
|
||||
#import "MAPIStoreDBFolder.h"
|
||||
@@ -49,7 +49,7 @@
|
||||
#include <mapistore/mapistore.h>
|
||||
#include <mapistore/mapistore_errors.h>
|
||||
|
||||
static Class EOKeyValueQualifierK, SOGoMAPIDBFolderK, MAPIStoreDBFolderK;
|
||||
static Class EOKeyValueQualifierK, SOGoCacheGCSFolderK, MAPIStoreDBFolderK;
|
||||
|
||||
static NSString *MAPIStoreRightReadItems = @"RightsReadItems";
|
||||
static NSString *MAPIStoreRightCreateItems = @"RightsCreateItems";
|
||||
@@ -66,7 +66,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
+ (void) initialize
|
||||
{
|
||||
EOKeyValueQualifierK = [EOKeyValueQualifier class];
|
||||
SOGoMAPIDBFolderK = [SOGoMAPIDBFolder class];
|
||||
SOGoCacheGCSFolderK = [SOGoCacheGCSFolder class];
|
||||
MAPIStoreDBFolderK = [MAPIStoreDBFolder class];
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
{
|
||||
enum mapistore_error rc;
|
||||
NSString *folderName, *nameInContainer;
|
||||
SOGoMAPIDBFolder *newFolder;
|
||||
SOGoCacheGCSFolder *newFolder;
|
||||
struct SPropValue *value;
|
||||
|
||||
value = get_SPropValue_SRow (aRow, PidTagDisplayName);
|
||||
@@ -111,7 +111,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
{
|
||||
nameInContainer = [NSString stringWithFormat: @"0x%.16"PRIx64,
|
||||
(unsigned long long) newFID];
|
||||
newFolder = [SOGoMAPIDBFolderK objectWithName: nameInContainer
|
||||
newFolder = [SOGoCacheGCSFolderK objectWithName: nameInContainer
|
||||
inContainer: sogoObject];
|
||||
[newFolder reloadIfNeeded];
|
||||
[[newFolder properties] setObject: folderName
|
||||
@@ -181,7 +181,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
[SOGoObject globallyUniqueObjectId]];
|
||||
fsObject = [SOGoMAPIDBMessage objectWithName: newKey
|
||||
inContainer: sogoObject];
|
||||
[fsObject setObjectType: MAPIDBObjectTypeMessage];
|
||||
[fsObject setObjectType: MAPIMessageCacheObject];
|
||||
[fsObject reloadIfNeeded];
|
||||
newMessage = [MAPIStoreDBMessage mapiStoreObjectWithSOGoObject: fsObject
|
||||
inContainer: self];
|
||||
@@ -198,7 +198,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
ownerUser = [[self userContext] sogoUser];
|
||||
if ([[context activeUser] isEqual: ownerUser]
|
||||
|| [self subscriberCanReadMessages])
|
||||
keys = [(SOGoMAPIDBFolder *) sogoObject childKeysOfType: MAPIDBObjectTypeMessage
|
||||
keys = [(SOGoCacheGCSFolder *) sogoObject childKeysOfType: MAPIMessageCacheObject
|
||||
includeDeleted: NO
|
||||
matchingQualifier: qualifier
|
||||
andSortOrderings: sortOrderings];
|
||||
@@ -211,7 +211,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
- (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier
|
||||
andSortOrderings: (NSArray *) sortOrderings
|
||||
{
|
||||
return [dbFolder childKeysOfType: MAPIDBObjectTypeFolder
|
||||
return [dbFolder childKeysOfType: MAPIFolderCacheObject
|
||||
includeDeleted: NO
|
||||
matchingQualifier: qualifier
|
||||
andSortOrderings: sortOrderings];
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* MAPIStoreFallbackContext.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2011-2012 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2011-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
@@ -26,7 +24,7 @@
|
||||
|
||||
#import "MAPIStoreUserContext.h"
|
||||
#import "NSString+MAPIStore.h"
|
||||
#import "SOGoMAPIDBFolder.h"
|
||||
#import <SOGo/SOGoCacheGCSFolder.h>
|
||||
|
||||
#import "MAPIStoreFallbackContext.h"
|
||||
|
||||
@@ -51,7 +49,7 @@
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
struct mapistore_contexts_list *firstContext = NULL, *context;
|
||||
SOGoMAPIDBFolder *root;
|
||||
SOGoCacheGCSFolder *root;
|
||||
NSArray *names;
|
||||
NSUInteger count, max;
|
||||
NSString *baseURL, *url, *name;
|
||||
@@ -70,7 +68,7 @@
|
||||
|
||||
/* Maybe emsmdbp_provisioning should be fixed in order to only take the uri
|
||||
returned above to avoid deleting its entries... */
|
||||
root = [SOGoMAPIDBFolder objectWithName: [self MAPIModuleName]
|
||||
root = [SOGoCacheGCSFolder objectWithName: [self MAPIModuleName]
|
||||
inContainer: nil];
|
||||
[root setOwner: userName];
|
||||
userContext = [MAPIStoreUserContext userContextWithUsername: userName
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* MAPIStoreFolder.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2011-2012 Inverse inc
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2011-2014 Inverse inc
|
||||
*
|
||||
* 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
|
||||
@@ -38,7 +36,7 @@
|
||||
@class MAPIStoreMessageTable;
|
||||
@class MAPIStorePermissionsTable;
|
||||
@class SOGoFolder;
|
||||
@class SOGoMAPIDBFolder;
|
||||
@class SOGoCacheGCSFolder;
|
||||
@class SOGoMAPIDBMessage;
|
||||
|
||||
#import "MAPIStoreSOGoObject.h"
|
||||
@@ -50,7 +48,7 @@
|
||||
// NSArray *faiMessageKeys;
|
||||
// NSArray *folderKeys;
|
||||
|
||||
SOGoMAPIDBFolder *dbFolder;
|
||||
SOGoCacheGCSFolder *dbFolder;
|
||||
// SOGoMAPIDBFolder *faiFolder;
|
||||
// SOGoMAPIDBFolder *propsFolder;
|
||||
// SOGoMAPIDBMessage *propsMessage;
|
||||
@@ -60,7 +58,7 @@
|
||||
|
||||
- (void) setupAuxiliaryObjects;
|
||||
|
||||
- (SOGoMAPIDBFolder *) dbFolder;
|
||||
- (SOGoCacheGCSFolder *) dbFolder;
|
||||
|
||||
- (NSArray *) activeMessageTables;
|
||||
- (NSArray *) activeFAIMessageTables;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* MAPIStoreFolder.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2011-2012 Inverse inc
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2011-2014 Inverse inc
|
||||
*
|
||||
* 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
|
||||
@@ -51,8 +49,9 @@
|
||||
#import "NSDate+MAPIStore.h"
|
||||
#import "NSString+MAPIStore.h"
|
||||
#import "NSObject+MAPIStore.h"
|
||||
#import "SOGoMAPIDBFolder.h"
|
||||
#import <SOGo/SOGoCacheGCSFolder.h>
|
||||
#import "SOGoMAPIDBMessage.h"
|
||||
#import "SOGoCacheGCSObject+MAPIStore.h"
|
||||
|
||||
#include <gen_ndr/exchange.h>
|
||||
|
||||
@@ -120,7 +119,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
[userContext ensureFolderTableExists];
|
||||
|
||||
ASSIGN (dbFolder,
|
||||
[SOGoMAPIDBFolder objectWithName: folderName
|
||||
[SOGoCacheGCSFolder objectWithName: folderName
|
||||
inContainer: [container dbFolder]]);
|
||||
[dbFolder setTableUrl: [userContext folderTableURL]];
|
||||
if (!container && [path length] > 0)
|
||||
@@ -138,7 +137,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
// ASSIGN (propsMessage,
|
||||
// [SOGoMAPIDBMessage objectWithName: @"properties.plist"
|
||||
// inContainer: dbFolder]);
|
||||
// [propsMessage setObjectType: MAPIDBObjectTypeInternal];
|
||||
// [propsMessage setObjectType: MAPIInternalCacheObject];
|
||||
// [propsMessage reloadIfNeeded];
|
||||
[properties release];
|
||||
properties = [dbFolder properties];
|
||||
@@ -192,7 +191,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (SOGoMAPIDBFolder *) dbFolder
|
||||
- (SOGoCacheGCSFolder *) dbFolder
|
||||
{
|
||||
return dbFolder;
|
||||
}
|
||||
@@ -1221,7 +1220,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
- (NSArray *) faiMessageKeysMatchingQualifier: (EOQualifier *) qualifier
|
||||
andSortOrderings: (NSArray *) sortOrderings
|
||||
{
|
||||
return [dbFolder childKeysOfType: MAPIDBObjectTypeFAI
|
||||
return [dbFolder childKeysOfType: MAPIFAICacheObject
|
||||
includeDeleted: NO
|
||||
matchingQualifier: qualifier
|
||||
andSortOrderings: sortOrderings];
|
||||
@@ -1531,7 +1530,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
newKey = [NSString stringWithFormat: @"%@.plist",
|
||||
[SOGoObject globallyUniqueObjectId]];
|
||||
dbObject = [SOGoMAPIDBMessage objectWithName: newKey inContainer: dbFolder];
|
||||
[dbObject setObjectType: MAPIDBObjectTypeFAI];
|
||||
[dbObject setObjectType: MAPIFAICacheObject];
|
||||
[dbObject setIsNew: YES];
|
||||
newMessage = [MAPIStoreFAIMessageK mapiStoreObjectWithSOGoObject: dbObject
|
||||
inContainer: self];
|
||||
|
||||
@@ -74,7 +74,7 @@ static Class NSNumberK;
|
||||
ASSIGN (versionsMessage,
|
||||
[SOGoMAPIDBMessage objectWithName: @"versions.plist"
|
||||
inContainer: dbFolder]);
|
||||
[versionsMessage setObjectType: MAPIDBObjectTypeInternal];
|
||||
[versionsMessage setObjectType: MAPIInternalCacheObject];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
#import "NSData+MAPIStore.h"
|
||||
#import "NSString+MAPIStore.h"
|
||||
#import "SOGoMAPIDBMessage.h"
|
||||
#import "SOGoMAPIDBFolder.h"
|
||||
#import <SOGo/SOGoCacheGCSFolder.h>
|
||||
|
||||
#import "MAPIStoreMailVolatileMessage.h"
|
||||
|
||||
@@ -106,7 +106,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
ASSIGN (versionsMessage,
|
||||
[SOGoMAPIDBMessage objectWithName: @"versions.plist"
|
||||
inContainer: dbFolder]);
|
||||
[versionsMessage setObjectType: MAPIDBObjectTypeInternal];
|
||||
[versionsMessage setObjectType: MAPIInternalCacheObject];
|
||||
}
|
||||
|
||||
- (BOOL) ensureFolderExists
|
||||
@@ -1172,9 +1172,9 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
|
||||
- (MAPIStoreMessage *) createMessage
|
||||
{
|
||||
SOGoMAPIObject *childObject;
|
||||
SOGoCacheObject *childObject;
|
||||
|
||||
childObject = [SOGoMAPIObject objectWithName: [SOGoMAPIObject
|
||||
childObject = [SOGoCacheObject objectWithName: [SOGoCacheObject
|
||||
globallyUniqueObjectId]
|
||||
inContainer: sogoObject];
|
||||
return [MAPIStoreMailVolatileMessage
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
#import "NSData+MAPIStore.h"
|
||||
#import "NSObject+MAPIStore.h"
|
||||
#import "NSString+MAPIStore.h"
|
||||
#import "SOGoMAPIObject.h"
|
||||
#import <SOGo/SOGoCacheObject.h>
|
||||
|
||||
#import "MAPIStoreMailVolatileMessage.h"
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <EOControl/EOQualifier.h>
|
||||
|
||||
#import "EOBitmaskQualifier.h"
|
||||
#import <SOGo/EOBitmaskQualifier.h>
|
||||
#import "MAPIStoreActiveTables.h"
|
||||
#import "MAPIStoreObject.h"
|
||||
#import "MAPIStoreTypes.h"
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#import <Mailer/SOGoMailAccount.h>
|
||||
#import <Mailer/SOGoMailAccounts.h>
|
||||
|
||||
#import "GCSSpecialQueries+OpenChange.h"
|
||||
#import <SOGo/GCSSpecialQueries+SOGoCacheObject.h>
|
||||
#import "MAPIApplication.h"
|
||||
#import "MAPIStoreAuthenticator.h"
|
||||
#import "MAPIStoreMapping.h"
|
||||
@@ -294,9 +294,12 @@ static NSMapTable *contextsTable = nil;
|
||||
if ([parts count] == 5)
|
||||
{
|
||||
/* If "OCSFolderInfoURL" is properly configured, we must have 5
|
||||
parts in this url. */
|
||||
ocFSTableName = [NSString stringWithFormat: @"socfs_%@",
|
||||
[username asCSSIdentifier]];
|
||||
parts in this url. We strip the '-' character in case we have
|
||||
this in the domain part - like foo@bar-zot.com */
|
||||
ocFSTableName = [NSString stringWithFormat: @"sogo_cache_folder_%@",
|
||||
[[[user loginInDomain] asCSSIdentifier]
|
||||
stringByReplacingOccurrencesOfString: @"-"
|
||||
withString: @"_"]];
|
||||
[parts replaceObjectAtIndex: 4 withObject: ocFSTableName];
|
||||
folderTableURL
|
||||
= [NSURL URLWithString: [parts componentsJoinedByString: @"/"]];
|
||||
@@ -329,7 +332,7 @@ static NSMapTable *contextsTable = nil;
|
||||
tableName]])
|
||||
{
|
||||
queries = [channel specialQueries];
|
||||
query = [queries createOpenChangeFSTableWithName: tableName];
|
||||
query = [queries createSOGoCacheGCSFolderTableWithName: tableName];
|
||||
if ([channel evaluateExpressionX: query])
|
||||
[NSException raise: @"MAPIStoreIOException"
|
||||
format: @"could not create special table '%@'", tableName];
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* dbmsgdump.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2011-2012 Inverse inc
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2011-2014 Inverse inc
|
||||
*
|
||||
* 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
|
||||
@@ -33,7 +31,7 @@
|
||||
#import <Foundation/NSValue.h>
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
|
||||
#import "BSONCodec.h"
|
||||
#import <SOGo/BSONCodec.h>
|
||||
|
||||
const char *indentationStep = " ";
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/* SOGoCacheGCSObject+MAPIStore.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2014 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef SOGOCACHEGCSOBJECTMAPISTORE
|
||||
#define SOGOCACHEGCSOBJECTMAPISTORE
|
||||
|
||||
#include <SOGo/SOGoCacheGCSObject.h>
|
||||
|
||||
@interface SOGoCacheGCSObject (MAPIStore)
|
||||
|
||||
- (Class) mapistoreMessageClass;
|
||||
|
||||
@end
|
||||
|
||||
#endif // SOGOCACHEGCSOBJECTMAPISTORE
|
||||
@@ -0,0 +1,68 @@
|
||||
/* SOGoCacheGCSObject+MAPIStore.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2014 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSException.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#include "MAPIStoreTypes.h"
|
||||
|
||||
#include "SOGoCacheGCSObject+MAPIStore.h"
|
||||
|
||||
@implementation SOGoCacheGCSObject (MAPIStore)
|
||||
|
||||
- (Class) mapistoreMessageClass
|
||||
{
|
||||
NSString *className, *mapiMsgClass;
|
||||
|
||||
switch (objectType)
|
||||
{
|
||||
case MAPIMessageCacheObject:
|
||||
mapiMsgClass = [properties
|
||||
objectForKey: MAPIPropertyKey (PidTagMessageClass)];
|
||||
if (mapiMsgClass)
|
||||
{
|
||||
if ([mapiMsgClass isEqualToString: @"IPM.StickyNote"])
|
||||
className = @"MAPIStoreNotesMessage";
|
||||
else
|
||||
className = @"MAPIStoreDBMessage";
|
||||
//[self logWithFormat: @"PidTagMessageClass = '%@', returning '%@'",
|
||||
// mapiMsgClass, className];
|
||||
}
|
||||
else
|
||||
{
|
||||
//[self warnWithFormat: @"PidTagMessageClass is not set, falling back"
|
||||
// @" to 'MAPIStoreDBMessage'"];
|
||||
className = @"MAPIStoreDBMessage";
|
||||
}
|
||||
break;
|
||||
case MAPIFAICacheObject:
|
||||
className = @"MAPIStoreFAIMessage";
|
||||
break;
|
||||
default:
|
||||
[NSException raise: @"MAPIStoreIOException"
|
||||
format: @"message class should not be queried for objects"
|
||||
@" of type '%d'", objectType];
|
||||
}
|
||||
|
||||
return NSClassFromString (className);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,8 +1,6 @@
|
||||
/* SOGoMAPIDBMessage.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2012 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2012-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
@@ -23,12 +21,12 @@
|
||||
#ifndef SOGOMAPIDBMESSAGE_H
|
||||
#define SOGOMAPIDBMESSAGE_H
|
||||
|
||||
#import "SOGoMAPIDBObject.h"
|
||||
#import <SOGo/SOGoCacheGCSObject.h>
|
||||
|
||||
@class NSDate;
|
||||
@class NSString;
|
||||
|
||||
@interface SOGoMAPIDBMessage : SOGoMAPIDBObject
|
||||
@interface SOGoMAPIDBMessage : SOGoCacheGCSObject
|
||||
@end
|
||||
|
||||
#endif /* SOGOMAPIDBMESSAGE_H */
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import "SOGoMAPIDBFolder.h"
|
||||
#import <SOGo/SOGoCacheGCSFolder.h>
|
||||
|
||||
#import "SOGoMAPIDBMessage.h"
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
|
||||
#import "MAPIStoreUserContext.h"
|
||||
#import "SOGoMAPIDBObject.h"
|
||||
#import <SOGo/SOGoCacheGCSObject.h>
|
||||
|
||||
#import "NSObject+PropertyList.m"
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ static NSArray *privilegedTagNames = nil;
|
||||
|
||||
if (!privilegedTagNames)
|
||||
{
|
||||
privilegedTagNames = [NSArray arrayWithObjects: @"ADR", @"N", @"RRULE", nil];
|
||||
privilegedTagNames = [NSArray arrayWithObjects: @"ADR", @"N", @"RRULE", @"ORG", nil];
|
||||
RETAIN(privilegedTagNames);
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ static NSArray *privilegedTagNames = nil;
|
||||
}
|
||||
|
||||
- (void) characters: (unichar *) _chars
|
||||
length: (int) _len
|
||||
length: (NSUInteger) _len
|
||||
{
|
||||
if (_len && _chars)
|
||||
{
|
||||
|
||||
@@ -126,6 +126,9 @@ typedef enum
|
||||
|
||||
- (void) setCategories: (NSArray *) newCategories;
|
||||
- (NSArray *) categories;
|
||||
- (NSString *) photo;
|
||||
- (void) setPhoto: (NSString *) _value;
|
||||
|
||||
|
||||
// - (void) setN: (NGVCardName *) _v;
|
||||
// - (NGVCardName *) n;
|
||||
|
||||
@@ -288,6 +288,25 @@
|
||||
return [self uniqueChildWithTag: @"n"];
|
||||
}
|
||||
|
||||
- (NSString *) photo
|
||||
{
|
||||
NGVCardPhoto *photo;
|
||||
|
||||
photo = (NGVCardPhoto *)[self uniqueChildWithTag: @"photo"];
|
||||
|
||||
return [[photo valuesAtIndex: 0 forKey: @""] objectAtIndex: 0];
|
||||
}
|
||||
|
||||
- (void) setPhoto: (NSString *) _value
|
||||
{
|
||||
CardElement *photo;
|
||||
photo = [self uniqueChildWithTag: @"photo"];
|
||||
[photo setValue: 0 ofAttribute: @"encoding" to: @"BASE64"];
|
||||
|
||||
[photo setSingleValue: _value forKey: @""];
|
||||
}
|
||||
|
||||
|
||||
- (void) setOrg: (NSString *) anOrg
|
||||
units: (NSArray *) someUnits
|
||||
{
|
||||
|
||||
@@ -217,10 +217,10 @@
|
||||
printf("</%s>\n", [_localName cString]);
|
||||
}
|
||||
|
||||
- (void)characters:(unichar *)_chars length:(int)_len {
|
||||
- (void)characters:(unichar *)_chars length:(NSUInteger)_len {
|
||||
NSString *str;
|
||||
id tmp;
|
||||
unsigned i, len;
|
||||
NSUInteger i, len;
|
||||
|
||||
if (_len == 0) {
|
||||
[self indent];
|
||||
@@ -228,7 +228,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < (unsigned)_len; i++) {
|
||||
for (i = 0; i < _len; i++) {
|
||||
if (_chars[i] > 255) {
|
||||
NSLog(@"detected large char: o%04o d%03i h%04X",
|
||||
_chars[i], _chars[i], _chars[i]);
|
||||
@@ -246,7 +246,7 @@
|
||||
[self indent];
|
||||
printf("\"%s\"\n", [str cString]);
|
||||
}
|
||||
- (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
|
||||
- (void)ignorableWhitespace:(unichar *)_chars length:(NSUInteger)_len {
|
||||
NSString *data;
|
||||
id tmp;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ sogoUserDefaultsFile = os.path.expanduser("~sogo/GNUstep/Defaults/.GNUstepDefaul
|
||||
# - removes the entry in samba's ldap tree via ldbedit (NOTYET)
|
||||
# - remove the user's directory under mapistore/ and mapistore/SOGo
|
||||
# - cleanup Junk Folders and Sync Issues imap folders
|
||||
# - Delete the socfs_ table for the username.
|
||||
# - Delete the sogo_cache_folder_ table for the username.
|
||||
|
||||
def usage():
|
||||
print """
|
||||
@@ -210,7 +210,7 @@ On RHEL, install it using 'yum install MySQL-python'"""
|
||||
|
||||
conn = MySQLdb.connect(host=dbhost, port=int(dbport), user=dbuser, passwd=dbpass, db=dbname)
|
||||
c=conn.cursor()
|
||||
tablename="socfs_%s" % (username)
|
||||
tablename="sogo_cache_folder_%s" % (username)
|
||||
c.execute("TRUNCATE TABLE %s" % tablename)
|
||||
print "Table %s emptied"
|
||||
|
||||
@@ -225,7 +225,7 @@ On RHEL, install it using 'yum install python-pgsql'"""
|
||||
raise Exception(msg)
|
||||
|
||||
conn = pg.connect(host=dbhost, port=int(dbport), user=dbuser, passwd=dbpass, dbname=dbname)
|
||||
tablename = "socfs_%s" % username
|
||||
tablename = "sogo_cache_folder_%s" % username
|
||||
conn.query("DELETE FROM %s" % tablename)
|
||||
print "Table '%s' emptied" % tablename
|
||||
|
||||
@@ -278,7 +278,7 @@ def sqlCleanup(username):
|
||||
print "Starting SQL cleanup"
|
||||
OCSFolderInfoURL = getOCSFolderInfoURL()
|
||||
if OCSFolderInfoURL is None:
|
||||
raise Exception("Couldn't fetch OCSFolderInfoURL or it is not set. the socfs_%s table should be truncated manually" % (username))
|
||||
raise Exception("Couldn't fetch OCSFolderInfoURL or it is not set. the sogo_cache_folder_%s table should be truncated manually" % (username))
|
||||
|
||||
# postgresql://sogo:sogo@127.0.0.1:5432/sogo/sogo_folder_info
|
||||
m = re.search("(.+)://(.+):(.+)@(.+):(\d+)/(.+)/(.+)", OCSFolderInfoURL)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
"Inviting the following persons is prohibited:" = "Inviting the following persons is prohibited:";
|
||||
"Personal Calendar" = "Personal Calendar";
|
||||
vevent_class0 = "(Public event)";
|
||||
vevent_class1 = "(Private event)";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
"Inviting the following persons is prohibited:" = "Seuraavien henkilöiden kutsuminen on estetty:";
|
||||
"Personal Calendar" = "Henkilökohtainen kalenteri";
|
||||
vevent_class0 = "(Julkinen tapahtuma)";
|
||||
vevent_class1 = "(Yksityinen tapahtuma)";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
"Inviting the following persons is prohibited:" = "L'invitation des personnes suivantes est interdite :";
|
||||
"Personal Calendar" = "Agenda personnel";
|
||||
vevent_class0 = "(Événement public)";
|
||||
vevent_class1 = "(Événement privé)";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
"Inviting the following persons is prohibited:" = "Das Einladen von folgenden Personen ist verboten:";
|
||||
"Personal Calendar" = "Persönlicher Kalender";
|
||||
vevent_class0 = "(Öffentlicher Termin)";
|
||||
vevent_class1 = "(Privater Termin)";
|
||||
|
||||
@@ -80,6 +80,8 @@ typedef enum {
|
||||
|
||||
- (NSArray *) calendarUIDs;
|
||||
|
||||
- (NSNumber *) activeTasks;
|
||||
|
||||
/* vevent UID handling */
|
||||
|
||||
- (NSString *) resourceNameForEventUID: (NSString *) _uid;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2007-2013 Inverse inc.
|
||||
Copyright (C) 2007-2014 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOGo.
|
||||
@@ -230,6 +230,8 @@ static iCalEvent *iCalEventK = nil;
|
||||
abstract: NO
|
||||
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
|
||||
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
|
||||
|
||||
/* read-acl and write-acl are defined in RFC3744 */
|
||||
[aclManager registerDAVPermission: davElement (@"admin", nsI)
|
||||
abstract: YES
|
||||
withEquivalent: nil
|
||||
@@ -242,6 +244,72 @@ static iCalEvent *iCalEventK = nil;
|
||||
abstract: YES
|
||||
withEquivalent: SoPerm_ChangePermissions
|
||||
asChildOf: davElement (@"admin", nsI)];
|
||||
|
||||
/* Default permissions for calendars. These are very important so that DAV client can
|
||||
detect permission changes on calendars and reload all items, if necessary */
|
||||
|
||||
/* Public ones */
|
||||
[aclManager registerDAVPermission: davElement (@"viewwhole-public-records", nsI)
|
||||
abstract: YES
|
||||
withEquivalent: SOGoCalendarPerm_ViewWholePublicRecords
|
||||
asChildOf: davElement (@"admin", nsI)];
|
||||
|
||||
[aclManager registerDAVPermission: davElement (@"viewdant-public-records", nsI)
|
||||
abstract: YES
|
||||
withEquivalent: SOGoCalendarPerm_ViewDAndTOfPublicRecords
|
||||
asChildOf: davElement (@"admin", nsI)];
|
||||
|
||||
[aclManager registerDAVPermission: davElement (@"modify-public-records", nsI)
|
||||
abstract: YES
|
||||
withEquivalent: SOGoCalendarPerm_ModifyPublicRecords
|
||||
asChildOf: davElement (@"admin", nsI)];
|
||||
|
||||
[aclManager registerDAVPermission: davElement (@"respondto-public-records", nsI)
|
||||
abstract: YES
|
||||
withEquivalent: SOGoCalendarPerm_RespondToPublicRecords
|
||||
asChildOf: davElement (@"admin", nsI)];
|
||||
|
||||
/* Private ones */
|
||||
[aclManager registerDAVPermission: davElement (@"viewwhole-private-records", nsI)
|
||||
abstract: YES
|
||||
withEquivalent: SOGoCalendarPerm_ViewWholePrivateRecords
|
||||
asChildOf: davElement (@"admin", nsI)];
|
||||
|
||||
[aclManager registerDAVPermission: davElement (@"viewdant-private-records", nsI)
|
||||
abstract: YES
|
||||
withEquivalent: SOGoCalendarPerm_ViewDAndTOfPrivateRecords
|
||||
asChildOf: davElement (@"admin", nsI)];
|
||||
|
||||
[aclManager registerDAVPermission: davElement (@"modify-private-records", nsI)
|
||||
abstract: YES
|
||||
withEquivalent: SOGoCalendarPerm_ModifyPrivateRecords
|
||||
asChildOf: davElement (@"admin", nsI)];
|
||||
|
||||
[aclManager registerDAVPermission: davElement (@"respondto-private-records", nsI)
|
||||
abstract: YES
|
||||
withEquivalent: SOGoCalendarPerm_RespondToPrivateRecords
|
||||
asChildOf: davElement (@"admin", nsI)];
|
||||
|
||||
/* Condifential ones */
|
||||
[aclManager registerDAVPermission: davElement (@"viewwhole-confidential-records", nsI)
|
||||
abstract: YES
|
||||
withEquivalent: SOGoCalendarPerm_ViewWholeConfidentialRecords
|
||||
asChildOf: davElement (@"admin", nsI)];
|
||||
|
||||
[aclManager registerDAVPermission: davElement (@"viewdant-confidential-records", nsI)
|
||||
abstract: YES
|
||||
withEquivalent: SOGoCalendarPerm_ViewDAndTOfConfidentialRecords
|
||||
asChildOf: davElement (@"admin", nsI)];
|
||||
|
||||
[aclManager registerDAVPermission: davElement (@"modify-confidential-records", nsI)
|
||||
abstract: YES
|
||||
withEquivalent: SOGoCalendarPerm_ModifyConfidentialRecords
|
||||
asChildOf: davElement (@"admin", nsI)];
|
||||
|
||||
[aclManager registerDAVPermission: davElement (@"respondto-confidential-records", nsI)
|
||||
abstract: YES
|
||||
withEquivalent: SOGoCalendarPerm_RespondToConfidentialRecords
|
||||
asChildOf: davElement (@"admin", nsI)];
|
||||
}
|
||||
|
||||
return aclManager;
|
||||
@@ -522,7 +590,6 @@ static iCalEvent *iCalEventK = nil;
|
||||
{
|
||||
/* this is used for group calendars (this folder just returns itself) */
|
||||
NSString *s;
|
||||
|
||||
s = [[self container] nameInContainer];
|
||||
// [self logWithFormat:@"CAL UID: %@", s];
|
||||
return [s isNotNull] ? [NSArray arrayWithObjects:&s count:1] : nil;
|
||||
@@ -1280,13 +1347,20 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
[baseWhere addObject: privacySQLString];
|
||||
|
||||
if ([title length])
|
||||
[baseWhere
|
||||
addObject: [NSString stringWithFormat: @"c_title isCaseInsensitiveLike: '%%%@%%'",
|
||||
if ([filters length])
|
||||
{
|
||||
if ([filters isEqualToString:@"title_Category_Location"] || [filters isEqualToString:@"entireContent"])
|
||||
{
|
||||
[baseWhere addObject: [NSString stringWithFormat: @"(c_title isCaseInsensitiveLike: '%%%@%%' OR c_category isCaseInsensitiveLike: '%%%@%%' OR c_location isCaseInsensitiveLike: '%%%@%%')",
|
||||
[title stringByReplacingString: @"'" withString: @"\\'\\'"],
|
||||
[title stringByReplacingString: @"'" withString: @"\\'\\'"],
|
||||
[title stringByReplacingString: @"'" withString: @"\\'\\'"]]];
|
||||
}
|
||||
}
|
||||
else
|
||||
[baseWhere addObject: [NSString stringWithFormat: @"c_title isCaseInsensitiveLike: '%%%@%%'",
|
||||
[title stringByReplacingString: @"'" withString: @"\\'\\'"]]];
|
||||
|
||||
if ([filters length])
|
||||
[baseWhere addObject: [NSString stringWithFormat: @"(%@)", filters]];
|
||||
|
||||
/* prepare mandatory fields */
|
||||
|
||||
fields = [NSMutableArray arrayWithArray: _fields];
|
||||
@@ -3263,4 +3337,25 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
return users;
|
||||
}
|
||||
|
||||
- (NSNumber *) activeTasks
|
||||
{
|
||||
NSArray *tasksList;
|
||||
NSMutableArray *fields;
|
||||
NSNumber *activeTasks;
|
||||
|
||||
fields = [NSMutableArray arrayWithObjects: @"c_component", @"c_status", nil];
|
||||
|
||||
tasksList = [self bareFetchFields: fields
|
||||
from: nil
|
||||
to: nil
|
||||
title: nil
|
||||
component: @"vtodo"
|
||||
additionalFilters: @"c_status != 1 AND c_status != 3"];
|
||||
|
||||
activeTasks = [NSNumber numberWithInt:[tasksList count]];
|
||||
|
||||
return activeTasks;
|
||||
}
|
||||
|
||||
|
||||
@end /* SOGoAppointmentFolder */
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
/* SOGoAppointmentFolders.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2013 Inverse inc.
|
||||
* Copyright (C) 2007-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
@@ -56,13 +56,6 @@
|
||||
|
||||
#import "SOGoAppointmentFolders.h"
|
||||
|
||||
@interface SOGoParentFolder (Private)
|
||||
|
||||
- (NSException *) _fetchPersonalFolders: (NSString *) sql
|
||||
withChannel: (EOAdaptorChannel *) fc;
|
||||
|
||||
@end
|
||||
|
||||
static SoSecurityManager *sm = nil;
|
||||
|
||||
@implementation SOGoAppointmentFolders
|
||||
@@ -596,8 +589,9 @@ static SoSecurityManager *sm = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSException *) _fetchPersonalFolders: (NSString *) sql
|
||||
withChannel: (EOAdaptorChannel *) fc
|
||||
- (NSException *) fetchSpecialFolders: (NSString *) sql
|
||||
withChannel: (EOAdaptorChannel *) fc
|
||||
andFolderType: (SOGoFolderType) folderType
|
||||
{
|
||||
BOOL isWebRequest;
|
||||
NSException *error;
|
||||
@@ -607,7 +601,7 @@ static SoSecurityManager *sm = nil;
|
||||
SOGoWebAppointmentFolder *webFolder;
|
||||
NSString *name;
|
||||
|
||||
error = [super _fetchPersonalFolders: sql withChannel: fc];
|
||||
error = [super fetchSpecialFolders: sql withChannel: fc andFolderType: folderType];
|
||||
if (!error)
|
||||
{
|
||||
isWebRequest = [[context request] handledByDefaultHandler];
|
||||
@@ -756,7 +750,8 @@ static SoSecurityManager *sm = nil;
|
||||
for (userCount = 0; userCount < userMax; userCount++)
|
||||
[currentFolder
|
||||
subscribeUserOrGroup: [proxySubscribers objectAtIndex: userCount]
|
||||
reallyDo: YES];
|
||||
reallyDo: YES
|
||||
response: nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -781,7 +776,8 @@ static SoSecurityManager *sm = nil;
|
||||
for (userCount = 0; userCount < userMax; userCount++)
|
||||
[currentFolder
|
||||
subscribeUserOrGroup: [proxySubscribers objectAtIndex: userCount]
|
||||
reallyDo: NO];
|
||||
reallyDo: NO
|
||||
response: nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* SOGoAppointmentInboxFolder.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2010 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2010-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,3 +1,4 @@
|
||||
"Inviting the following persons is prohibited:" = "Esta prohibido invitar las siguientes personas:";
|
||||
"Personal Calendar" = "Calendario personal";
|
||||
vevent_class0 = "(Evento público)";
|
||||
vevent_class1 = "(Evento privado)";
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
SOGoAppointmentInboxFolder = {
|
||||
superclass = "SOGoAppointmentFolder";
|
||||
defaultRoles = {
|
||||
"Access Contents Information" = ( "Owner" );
|
||||
"Access Contents Information" = ( "Owner", "AuthorizedSubscriber" );
|
||||
};
|
||||
};
|
||||
SOGoCalendarComponent = {
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
"Personal Address Book" = "Osobní kontakty";
|
||||
"Collected Address Book" = "Sebrané kontakty";
|
||||
@@ -1 +1,2 @@
|
||||
"Personal Address Book" = "Persoonlijk adresboek";
|
||||
"Collected Address Book" = "Verzamelde adressen";
|
||||
@@ -1 +1,2 @@
|
||||
"Personal Address Book" = "Personal Address Book";
|
||||
"Collected Address Book" = "Collected Address Book";
|
||||
@@ -1 +1,2 @@
|
||||
"Personal Address Book" = "Henkilökohtainen osoitekirja";
|
||||
"Collected Address Book" = "Kerätty osoitekirja";
|
||||
@@ -1 +1,2 @@
|
||||
"Personal Address Book" = "Carnet d'adresses personnel";
|
||||
"Collected Address Book" = "Adresses collectées";
|
||||
@@ -1 +1,2 @@
|
||||
"Personal Address Book" = "Persönliches Adressbuch";
|
||||
"Collected Address Book" = "Gesammelte Adressen";
|
||||
@@ -1 +1,2 @@
|
||||
"Personal Address Book" = "Személyes címjegyzék";
|
||||
"Collected Address Book" = "Összegyűjtöt címek jegyzéke";
|
||||
@@ -1 +1,2 @@
|
||||
"Personal Address Book" = "Osobista książka adresowa";
|
||||
"Collected Address Book" = "Książka zebranych adresów";
|
||||
@@ -1 +1,2 @@
|
||||
"Personal Address Book" = "Личная адресная книга";
|
||||
"Collected Address Book" = "Собранные адреса";
|
||||
@@ -25,12 +25,19 @@
|
||||
|
||||
@interface SOGoContactFolders : SOGoParentFolder
|
||||
|
||||
- (NSString *) defaultFolderName;
|
||||
- (NSString *) collectedFolderName;
|
||||
|
||||
- (NSException *) renameLDAPAddressBook: (NSString *) sourceID
|
||||
withDisplayName: (NSString *) newDisplayName;
|
||||
- (NSException *) removeLDAPAddressBook: (NSString *) sourceID;
|
||||
|
||||
- (NSDictionary *) systemSources;
|
||||
|
||||
- (NSArray *) allContactsFromFilter: (NSString *) theFilter
|
||||
excludeGroups: (BOOL) excludeGroups
|
||||
excludeLists: (BOOL) excludeLists;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SOGOCONTACTFOLDERS_H */
|
||||
@@ -22,12 +22,18 @@
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSSortDescriptor.h>
|
||||
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <DOM/DOMElement.h>
|
||||
#import <DOM/DOMProtocols.h>
|
||||
|
||||
#import <GDLContentStore/GCSChannelManager.h>
|
||||
#import <GDLContentStore/GCSFolderManager.h>
|
||||
#import <GDLContentStore/NSURL+GCS.h>
|
||||
#import <GDLAccess/EOAdaptorChannel.h>
|
||||
|
||||
#import <SOGo/NSObject+DAV.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
@@ -40,10 +46,17 @@
|
||||
|
||||
#import "SOGoContactFolders.h"
|
||||
|
||||
Class SOGoContactSourceFolderK;
|
||||
|
||||
#define XMLNS_INVERSEDAV @"urn:inverse:params:xml:ns:inverse-dav"
|
||||
|
||||
@implementation SOGoContactFolders
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
SOGoContactSourceFolderK = [SOGoContactSourceFolder class];
|
||||
}
|
||||
|
||||
+ (NSString *) gcsFolderType
|
||||
{
|
||||
return @"Contact";
|
||||
@@ -110,6 +123,38 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSException *) appendCollectedSources
|
||||
{
|
||||
GCSChannelManager *cm;
|
||||
EOAdaptorChannel *fc;
|
||||
NSURL *folderLocation;
|
||||
NSString *sql, *gcsFolderType;
|
||||
NSException *error;
|
||||
|
||||
cm = [GCSChannelManager defaultChannelManager];
|
||||
folderLocation = [[GCSFolderManager defaultFolderManager] folderInfoLocation];
|
||||
fc = [cm acquireOpenChannelForURL: folderLocation];
|
||||
if ([fc isOpen])
|
||||
{
|
||||
gcsFolderType = [[self class] gcsFolderType];
|
||||
|
||||
sql = [NSString stringWithFormat: (@"SELECT c_path4 FROM %@"
|
||||
@" WHERE c_path2 = '%@'"
|
||||
@" AND c_folder_type = '%@'"),
|
||||
[folderLocation gcsTableName], owner, gcsFolderType];
|
||||
|
||||
error = [super fetchSpecialFolders: sql withChannel: fc andFolderType: SOGoCollectedFolder];
|
||||
|
||||
[cm releaseChannel: fc];
|
||||
}
|
||||
else
|
||||
error = [NSException exceptionWithName: @"SOGoDBException"
|
||||
reason: @"database connection could not be open"
|
||||
userInfo: nil];
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
- (NSDictionary *) systemSources
|
||||
{
|
||||
NSMutableDictionary *systemSources;
|
||||
@@ -225,7 +270,7 @@
|
||||
|
||||
if ([sourceID isEqualToString: @"personal"])
|
||||
result = [NSException exceptionWithHTTPStatus: 403
|
||||
reason: @"folder 'personal' cannot be deleted"];
|
||||
reason: (@"folder '%@' cannot be deleted", sourceID)];
|
||||
else
|
||||
{
|
||||
result = nil;
|
||||
@@ -250,6 +295,11 @@
|
||||
return [self labelForKey: @"Personal Address Book"];
|
||||
}
|
||||
|
||||
- (NSString *) collectedFolderName
|
||||
{
|
||||
return [self labelForKey: @"Collected Address Book"];
|
||||
}
|
||||
|
||||
- (NSArray *) toManyRelationshipKeys
|
||||
{
|
||||
NSMutableArray *keys;
|
||||
@@ -371,4 +421,89 @@
|
||||
asWebDAVValue];
|
||||
}
|
||||
|
||||
- (NSArray *) allContactsFromFilter: (NSString *) theFilter
|
||||
excludeGroups: (BOOL) excludeGroups
|
||||
excludeLists: (BOOL) excludeLists
|
||||
{
|
||||
SOGoFolder <SOGoContactFolder> *folder;
|
||||
NSString *mail, *domain;
|
||||
NSArray *folders, *contacts, *descriptors, *sortedContacts;
|
||||
NSMutableArray *sortedFolders;
|
||||
NSMutableDictionary *contact, *uniqueContacts;
|
||||
unsigned int i, j, max;
|
||||
NSSortDescriptor *commonNameDescriptor;
|
||||
|
||||
// NSLog(@"Search all contacts: %@", searchText);
|
||||
|
||||
domain = [[context activeUser] domain];
|
||||
folders = nil;
|
||||
NS_DURING
|
||||
folders = [self subFolders];
|
||||
NS_HANDLER
|
||||
/* We need to specifically test for @"SOGoDBException", which is
|
||||
raised explicitly in SOGoParentFolder. Any other exception should
|
||||
be re-raised. */
|
||||
if ([[localException name] isEqualToString: @"SOGoDBException"])
|
||||
folders = nil;
|
||||
else
|
||||
[localException raise];
|
||||
NS_ENDHANDLER;
|
||||
max = [folders count];
|
||||
sortedFolders = [NSMutableArray arrayWithCapacity: max];
|
||||
uniqueContacts = [NSMutableDictionary dictionary];
|
||||
for (i = 0; i < max; i++)
|
||||
{
|
||||
folder = [folders objectAtIndex: i];
|
||||
/* We first search in LDAP folders (in case of duplicated entries in GCS folders) */
|
||||
if ([folder isKindOfClass: SOGoContactSourceFolderK])
|
||||
[sortedFolders insertObject: folder atIndex: 0];
|
||||
else
|
||||
[sortedFolders addObject: folder];
|
||||
}
|
||||
for (i = 0; i < max; i++)
|
||||
{
|
||||
folder = [sortedFolders objectAtIndex: i];
|
||||
//NSLog(@" Address book: %@ (%@)", [folder displayName], [folder class]);
|
||||
contacts = [folder lookupContactsWithFilter: theFilter
|
||||
onCriteria: @"name_or_address"
|
||||
sortBy: @"c_cn"
|
||||
ordering: NSOrderedAscending
|
||||
inDomain: domain];
|
||||
for (j = 0; j < [contacts count]; j++)
|
||||
{
|
||||
contact = [contacts objectAtIndex: j];
|
||||
mail = [contact objectForKey: @"c_mail"];
|
||||
//NSLog(@" found %@ (%@) ? %@", [contact objectForKey: @"c_name"], mail,
|
||||
// [contact description]);
|
||||
if (!excludeLists && [[contact objectForKey: @"c_component"]
|
||||
isEqualToString: @"vlist"])
|
||||
{
|
||||
[contact setObject: [folder nameInContainer]
|
||||
forKey: @"container"];
|
||||
[uniqueContacts setObject: contact
|
||||
forKey: [contact objectForKey: @"c_name"]];
|
||||
}
|
||||
else if ([mail length]
|
||||
&& [uniqueContacts objectForKey: mail] == nil
|
||||
&& !(excludeGroups && [contact objectForKey: @"isGroup"]))
|
||||
[uniqueContacts setObject: contact forKey: mail];
|
||||
}
|
||||
}
|
||||
if ([uniqueContacts count] > 0)
|
||||
{
|
||||
// Sort the contacts by display name
|
||||
commonNameDescriptor = [[NSSortDescriptor alloc] initWithKey: @"c_cn"
|
||||
ascending:YES];
|
||||
descriptors = [NSArray arrayWithObjects: commonNameDescriptor, nil];
|
||||
[commonNameDescriptor release];
|
||||
sortedContacts = [[uniqueContacts allValues]
|
||||
sortedArrayUsingDescriptors: descriptors];
|
||||
}
|
||||
else
|
||||
sortedContacts = [NSArray array];
|
||||
|
||||
return sortedContacts;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -1 +1,2 @@
|
||||
"Personal Address Book" = "Osobné kontakty";
|
||||
"Collected Address Book" = "Pozbierané osobné kontakty";
|
||||
@@ -1 +1,2 @@
|
||||
"Personal Address Book" = "Libreta personal de direcciones";
|
||||
"Collected Address Book" = "Direcciones recopiladas";
|
||||
@@ -1 +1,2 @@
|
||||
"Personal Address Book" = "Libreta personal de direcciones";
|
||||
"Collected Address Book" = "Libreta de direcciones recogidas";
|
||||
@@ -0,0 +1,2 @@
|
||||
"SieveFolderName" = "فلاتر";
|
||||
"OtherUsersFolderName" = "مستخدمين أخرين";
|
||||
@@ -0,0 +1,2 @@
|
||||
"SieveFolderName" = "Filtros";
|
||||
"OtherUsersFolderName" = "Outros Usuários";
|
||||
@@ -0,0 +1,2 @@
|
||||
"SieveFolderName" = "Filtres";
|
||||
"OtherUsersFolderName" = "Altres usuaris";
|
||||
@@ -0,0 +1,2 @@
|
||||
"OtherUsersFolderName" = "Ostatní uživatelé";
|
||||
"SharedFoldersName" = "Sdílené složky";
|
||||
@@ -0,0 +1,2 @@
|
||||
"SieveFolderName" = "Filtre";
|
||||
"OtherUsersFolderName" = "Andre brugere";
|
||||
@@ -0,0 +1,2 @@
|
||||
"OtherUsersFolderName" = "Andere Gebruikers";
|
||||
"SharedFoldersName" = "Gedeelde Mappen";
|
||||
@@ -0,0 +1,2 @@
|
||||
"OtherUsersFolderName" = "Other Users";
|
||||
"SharedFoldersName" = "Shared Folders";
|
||||
@@ -0,0 +1,2 @@
|
||||
"OtherUsersFolderName" = "Muut käyttäjät";
|
||||
"SharedFoldersName" = "Jaetut kansiot";
|
||||
@@ -0,0 +1,2 @@
|
||||
"OtherUsersFolderName" = "Autres utilisateurs";
|
||||
"SharedFoldersName" = "Dossiers partagés";
|
||||
@@ -92,7 +92,7 @@ Mailer_RESOURCE_FILES += \
|
||||
SOGoMailWelshReply.wo
|
||||
|
||||
|
||||
Mailer_LANGUAGES = English French
|
||||
Mailer_LANGUAGES = Arabic BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
||||
|
||||
Mailer_LOCALIZED_RESOURCE_FILES = Localizable.strings
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
"OtherUsersFolderName" = "Andere Benutzer";
|
||||
"SharedFoldersName" = "Gemeinsame Ordner";
|
||||
@@ -0,0 +1,2 @@
|
||||
"OtherUsersFolderName" = "Egyéb felhasználók";
|
||||
"SharedFoldersName" = "Megosztott mappák";
|
||||
@@ -0,0 +1,2 @@
|
||||
"SieveFolderName" = "Síur";
|
||||
"OtherUsersFolderName" = "Aðrir Notendur";
|
||||
@@ -0,0 +1,2 @@
|
||||
"SieveFolderName" = "Filtri";
|
||||
"OtherUsersFolderName" = "Altri Utenti";
|
||||
@@ -417,12 +417,20 @@
|
||||
{
|
||||
if (!ignoreContent)
|
||||
{
|
||||
[result appendString: [NSString stringWithCharacters: characters length: length]];
|
||||
// Append a text node
|
||||
if (ignoreContentTags)
|
||||
// We are converting a HTML message to plain text (htmlToTextContentHandler):
|
||||
// include the HTML tags in the text
|
||||
[result appendString: [NSString stringWithCharacters: characters length: length]];
|
||||
else
|
||||
// We are sanitizing an HTML message (sanitizerContentHandler):
|
||||
// escape the HTML entitites so they are visible
|
||||
[result appendString: [[NSString stringWithCharacters: characters length: length] stringByEscapingHTMLString]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) ignorableWhitespace: (unichar *) whitespaces
|
||||
length: (int) length
|
||||
length: (NSUInteger) length
|
||||
{
|
||||
showWhoWeAre();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
"SieveFolderName" = "Filter";
|
||||
"OtherUsersFolderName" = "Andre brukere";
|
||||
@@ -0,0 +1,2 @@
|
||||
"SieveFolderName" = "Filter";
|
||||
"OtherUsersFolderName" = "Other Users";
|
||||
@@ -0,0 +1,2 @@
|
||||
"OtherUsersFolderName" = "Inni użytkownicy";
|
||||
"SharedFoldersName" = "Foldery współdzielone";
|
||||
@@ -0,0 +1,2 @@
|
||||
"OtherUsersFolderName" = "Другие пользователи";
|
||||
"SharedFoldersName" = "Общие папки";
|
||||
@@ -1,20 +1,21 @@
|
||||
/*
|
||||
Copyright (C) 2007-2014 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
This file is part of SOGo.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
SOGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
License along with SOGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
@@ -52,6 +53,7 @@
|
||||
{
|
||||
NSString *path;
|
||||
int IMAP4ID;
|
||||
int sourceIMAP4ID;
|
||||
NSMutableDictionary *headers;
|
||||
NSString *inReplyTo;
|
||||
NSString *text;
|
||||
@@ -78,11 +80,17 @@
|
||||
- (BOOL) isHTML;
|
||||
|
||||
/* for replies and forwards */
|
||||
- (NSString *) inReplyTo;
|
||||
- (void) setInReplyTo: (NSString *) newInReplyTo;
|
||||
|
||||
- (void) setSourceURL: (NSString *) newSurceURL;
|
||||
- (void) setSourceFlag: (NSString *) newSourceFlag;
|
||||
- (void) setSourceFolder: (NSString *) newSourceFolder;
|
||||
- (NSString *) sourceFolder;
|
||||
|
||||
- (void) setSourceIMAP4ID: (int) newSourceIMAPID;
|
||||
- (int) sourceIMAP4ID;
|
||||
|
||||
- (void) setIMAP4ID: (int) newIMAPID;
|
||||
- (int) IMAP4ID;
|
||||
|
||||
@@ -102,6 +110,8 @@
|
||||
- (NSData *) mimeMessageAsData;
|
||||
|
||||
/* operations */
|
||||
- (NSArray *) allRecipients;
|
||||
- (NSArray *) allBareRecipients;
|
||||
|
||||
- (NSException *) delete;
|
||||
- (NSException *) sendMail;
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#import <NGImap4/NGImap4Client.h>
|
||||
#import <NGImap4/NGImap4Envelope.h>
|
||||
#import <NGImap4/NGImap4EnvelopeAddress.h>
|
||||
#import <NGMail/NGMailAddressParser.h>
|
||||
#import <NGMail/NGMimeMessage.h>
|
||||
#import <NGMail/NGMimeMessageGenerator.h>
|
||||
#import <NGMime/NGMimeBodyPart.h>
|
||||
@@ -63,6 +64,11 @@
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
|
||||
#import <NGCards/NGVCard.h>
|
||||
|
||||
#import <Contacts/SOGoContactFolders.h>
|
||||
#import <Contacts/SOGoContactGCSEntry.h>
|
||||
|
||||
#import "NSData+Mail.h"
|
||||
#import "NSString+Mail.h"
|
||||
#import "SOGoMailAccount.h"
|
||||
@@ -191,6 +197,7 @@ static NSString *userAgent = nil;
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
sourceIMAP4ID = -1;
|
||||
IMAP4ID = -1;
|
||||
headers = [NSMutableDictionary new];
|
||||
text = @"";
|
||||
@@ -228,8 +235,7 @@ static NSString *userAgent = nil;
|
||||
{
|
||||
if (!path)
|
||||
{
|
||||
path = [[self userSpoolFolderPath] stringByAppendingPathComponent:
|
||||
nameInContainer];
|
||||
path = [[self userSpoolFolderPath] stringByAppendingPathComponent: nameInContainer];
|
||||
[path retain];
|
||||
}
|
||||
|
||||
@@ -260,7 +266,7 @@ static NSString *userAgent = nil;
|
||||
{
|
||||
id headerValue;
|
||||
unsigned int count;
|
||||
NSString *messageID, *priority, *pureSender, *replyTo;
|
||||
NSString *messageID, *priority, *pureSender, *replyTo, *receipt;
|
||||
|
||||
for (count = 0; count < 8; count++)
|
||||
{
|
||||
@@ -279,26 +285,57 @@ static NSString *userAgent = nil;
|
||||
[headers setObject: messageID forKey: @"message-id"];
|
||||
}
|
||||
|
||||
priority = [newHeaders objectForKey: @"priority"];
|
||||
if (!priority || [priority isEqualToString: @"NORMAL"])
|
||||
priority = [newHeaders objectForKey: @"X-Priority"];
|
||||
if (priority)
|
||||
{
|
||||
[headers removeObjectForKey: @"X-Priority"];
|
||||
}
|
||||
else if ([priority isEqualToString: @"HIGHEST"])
|
||||
{
|
||||
[headers setObject: @"1 (Highest)" forKey: @"X-Priority"];
|
||||
}
|
||||
else if ([priority isEqualToString: @"HIGH"])
|
||||
{
|
||||
[headers setObject: @"2 (High)" forKey: @"X-Priority"];
|
||||
}
|
||||
else if ([priority isEqualToString: @"LOW"])
|
||||
{
|
||||
[headers setObject: @"4 (Low)" forKey: @"X-Priority"];
|
||||
// newHeaders come from MIME message; convert X-Priority to Web representation
|
||||
[headers setObject: priority forKey: @"X-Priority"];
|
||||
[headers removeObjectForKey: @"priority"];
|
||||
if ([priority isEqualToString: @"1 (Highest)"])
|
||||
{
|
||||
[headers setObject: @"HIGHEST" forKey: @"priority"];
|
||||
}
|
||||
else if ([priority isEqualToString: @"2 (High)"])
|
||||
{
|
||||
[headers setObject: @"HIGH" forKey: @"priority"];
|
||||
}
|
||||
else if ([priority isEqualToString: @"4 (Low)"])
|
||||
{
|
||||
[headers setObject: @"LOW" forKey: @"priority"];
|
||||
}
|
||||
else if ([priority isEqualToString: @"5 (Lowest)"])
|
||||
{
|
||||
[headers setObject: @"LOWEST" forKey: @"priority"];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[headers setObject: @"5 (Lowest)" forKey: @"X-Priority"];
|
||||
// newHeaders come from Web form; convert priority to MIME header representation
|
||||
priority = [newHeaders objectForKey: @"priority"];
|
||||
if (!priority || [priority isEqualToString: @"NORMAL"])
|
||||
{
|
||||
[headers removeObjectForKey: @"X-Priority"];
|
||||
}
|
||||
else if ([priority isEqualToString: @"HIGHEST"])
|
||||
{
|
||||
[headers setObject: @"1 (Highest)" forKey: @"X-Priority"];
|
||||
}
|
||||
else if ([priority isEqualToString: @"HIGH"])
|
||||
{
|
||||
[headers setObject: @"2 (High)" forKey: @"X-Priority"];
|
||||
}
|
||||
else if ([priority isEqualToString: @"LOW"])
|
||||
{
|
||||
[headers setObject: @"4 (Low)" forKey: @"X-Priority"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[headers setObject: @"5 (Lowest)" forKey: @"X-Priority"];
|
||||
}
|
||||
if (priority)
|
||||
{
|
||||
[headers setObject: priority forKey: @"priority"];
|
||||
}
|
||||
}
|
||||
|
||||
replyTo = [headers objectForKey: @"replyTo"];
|
||||
@@ -308,14 +345,30 @@ static NSString *userAgent = nil;
|
||||
}
|
||||
[headers removeObjectForKey: @"replyTo"];
|
||||
|
||||
if ([[newHeaders objectForKey: @"receipt"] isEqualToString: @"true"])
|
||||
receipt = [newHeaders objectForKey: @"Disposition-Notification-To"];
|
||||
if ([receipt length] > 0)
|
||||
{
|
||||
pureSender = [[newHeaders objectForKey: @"from"] pureEMailAddress];
|
||||
if (pureSender)
|
||||
[headers setObject: pureSender forKey: @"Disposition-Notification-To"];
|
||||
[headers setObject: @"true" forKey: @"receipt"];
|
||||
[headers setObject: receipt forKey: @"Disposition-Notification-To"];
|
||||
}
|
||||
else
|
||||
[headers removeObjectForKey: @"Disposition-Notification-To"];
|
||||
{
|
||||
receipt = [newHeaders objectForKey: @"receipt"];
|
||||
if ([receipt isEqualToString: @"true"])
|
||||
{
|
||||
[headers setObject: receipt forKey: @"receipt"];
|
||||
pureSender = [[newHeaders objectForKey: @"from"] pureEMailAddress];
|
||||
if (pureSender)
|
||||
{
|
||||
[headers setObject: pureSender forKey: @"Disposition-Notification-To"];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[headers removeObjectForKey: @"receipt"];
|
||||
[headers removeObjectForKey: @"Disposition-Notification-To"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary *) headers
|
||||
@@ -343,6 +396,11 @@ static NSString *userAgent = nil;
|
||||
return isHTML;
|
||||
}
|
||||
|
||||
- (NSString *) inReplyTo
|
||||
{
|
||||
return inReplyTo;
|
||||
}
|
||||
|
||||
- (void) setInReplyTo: (NSString *) newInReplyTo
|
||||
{
|
||||
ASSIGN (inReplyTo, newInReplyTo);
|
||||
@@ -408,6 +466,9 @@ static NSString *userAgent = nil;
|
||||
forKey: @"isHTML"];
|
||||
if (inReplyTo)
|
||||
[infos setObject: inReplyTo forKey: @"inReplyTo"];
|
||||
if (sourceIMAP4ID > -1)
|
||||
[infos setObject: [NSString stringWithFormat: @"%i", sourceIMAP4ID]
|
||||
forKey: @"sourceIMAP4ID"];
|
||||
if (IMAP4ID > -1)
|
||||
[infos setObject: [NSString stringWithFormat: @"%i", IMAP4ID]
|
||||
forKey: @"IMAP4ID"];
|
||||
@@ -455,6 +516,10 @@ static NSString *userAgent = nil;
|
||||
[self setText: value];
|
||||
isHTML = [[infoDict objectForKey: @"isHTML"] boolValue];
|
||||
|
||||
value = [infoDict objectForKey: @"sourceIMAP4ID"];
|
||||
if (value)
|
||||
[self setSourceIMAP4ID: [value intValue]];
|
||||
|
||||
value = [infoDict objectForKey: @"IMAP4ID"];
|
||||
if (value)
|
||||
[self setIMAP4ID: [value intValue]];
|
||||
@@ -506,6 +571,22 @@ static NSString *userAgent = nil;
|
||||
[self debugWithFormat: @"Note: info object does not yet exist: %@", p];
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) setSourceIMAP4ID: (int) newSourceIMAP4ID
|
||||
{
|
||||
sourceIMAP4ID = newSourceIMAP4ID;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (int) sourceIMAP4ID
|
||||
{
|
||||
return sourceIMAP4ID;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -552,7 +633,7 @@ static NSString *userAgent = nil;
|
||||
{
|
||||
if (IMAP4ID > -1)
|
||||
error = [imap4 markURLDeleted: [self imap4URL]];
|
||||
IMAP4ID = [self IMAP4IDFromAppendResult: result];
|
||||
[self setIMAP4ID: [self IMAP4IDFromAppendResult: result]];
|
||||
if (imap4URL)
|
||||
{
|
||||
// Invalidate the IMAP message URL since the message ID has changed
|
||||
@@ -799,8 +880,10 @@ static NSString *userAgent = nil;
|
||||
{
|
||||
NSString *subject, *msgid;
|
||||
NSMutableDictionary *info;
|
||||
NSDictionary *h;
|
||||
NSMutableArray *addresses;
|
||||
NGImap4Envelope *sourceEnvelope;
|
||||
id priority, receipt;
|
||||
|
||||
[sourceMail fetchCoreInfos];
|
||||
|
||||
@@ -830,12 +913,19 @@ static NSString *userAgent = nil;
|
||||
[self _addEMailsOfAddresses: [sourceEnvelope replyTo] toArray: addresses];
|
||||
if ([addresses count] > 0)
|
||||
[info setObject: addresses forKey: @"replyTo"];
|
||||
|
||||
h = [sourceMail mailHeaders];
|
||||
priority = [h objectForKey: @"x-priority"];
|
||||
if ([priority isNotEmpty] && [priority isKindOfClass: [NSString class]])
|
||||
[info setObject: (NSString*)priority forKey: @"X-Priority"];
|
||||
receipt = [h objectForKey: @"disposition-notification-to"];
|
||||
if ([receipt isNotEmpty] && [receipt isKindOfClass: [NSString class]])
|
||||
[info setObject: (NSString*)receipt forKey: @"Disposition-Notification-To"];
|
||||
|
||||
[self setHeaders: info];
|
||||
|
||||
[self setText: [sourceMail contentForEditing]];
|
||||
[self setSourceURL: [sourceMail imap4URLString]];
|
||||
[self setIMAP4ID: [[sourceMail nameInContainer] intValue]];
|
||||
[self setSourceFolderWithMailObject: sourceMail];
|
||||
|
||||
[self storeInfo];
|
||||
}
|
||||
@@ -857,7 +947,7 @@ static NSString *userAgent = nil;
|
||||
|
||||
sourceEnvelope = [sourceMail envelope];
|
||||
[self _fillInReplyAddresses: info replyToAll: toAll
|
||||
envelope: sourceEnvelope];
|
||||
envelope: sourceEnvelope];
|
||||
msgID = [sourceEnvelope messageID];
|
||||
if ([msgID length] > 0)
|
||||
[self setInReplyTo: msgID];
|
||||
@@ -865,7 +955,7 @@ static NSString *userAgent = nil;
|
||||
[self setHeaders: info];
|
||||
[self setSourceURL: [sourceMail imap4URLString]];
|
||||
[self setSourceFlag: @"Answered"];
|
||||
[self setIMAP4ID: [[sourceMail nameInContainer] intValue]];
|
||||
[self setSourceIMAP4ID: [[sourceMail nameInContainer] intValue]];
|
||||
[self setSourceFolderWithMailObject: sourceMail];
|
||||
|
||||
[self storeInfo];
|
||||
@@ -888,7 +978,7 @@ static NSString *userAgent = nil;
|
||||
|
||||
[self setSourceURL: [sourceMail imap4URLString]];
|
||||
[self setSourceFlag: @"$Forwarded"];
|
||||
[self setIMAP4ID: [[sourceMail nameInContainer] intValue]];
|
||||
[self setSourceIMAP4ID: [[sourceMail nameInContainer] intValue]];
|
||||
[self setSourceFolderWithMailObject: sourceMail];
|
||||
|
||||
/* attach message */
|
||||
@@ -913,7 +1003,7 @@ static NSString *userAgent = nil;
|
||||
@"message/rfc822", @"mimetype",
|
||||
nil];
|
||||
[self saveAttachment: [sourceMail content]
|
||||
withMetadata: attachment];
|
||||
withMetadata: attachment];
|
||||
}
|
||||
|
||||
[self storeInfo];
|
||||
@@ -1538,10 +1628,11 @@ static NSString *userAgent = nil;
|
||||
/* add subject */
|
||||
if ([(s = [headers objectForKey: @"subject"]) length] > 0)
|
||||
[map setObject: [s asQPSubjectString: @"utf-8"]
|
||||
forKey: @"subject"];
|
||||
|
||||
[map setObject: [headers objectForKey: @"message-id"]
|
||||
forKey: @"message-id"];
|
||||
forKey: @"subject"];
|
||||
|
||||
if ([(s = [headers objectForKey: @"message-id"]) length] > 0)
|
||||
[map setObject: s
|
||||
forKey: @"message-id"];
|
||||
|
||||
/* add standard headers */
|
||||
dateString = [[NSCalendarDate date] rfc822DateString];
|
||||
@@ -1660,7 +1751,7 @@ static NSString *userAgent = nil;
|
||||
{
|
||||
recipients = [headers objectForKey: fieldNames[count]];
|
||||
if ([recipients count] > 0)
|
||||
[allRecipients addObjectsFromArray: recipients];
|
||||
[allRecipients addObjectsFromArray: recipients];
|
||||
}
|
||||
|
||||
return allRecipients;
|
||||
@@ -1689,6 +1780,63 @@ static NSString *userAgent = nil;
|
||||
//
|
||||
- (NSException *) sendMail
|
||||
{
|
||||
SOGoUserDefaults *ud;
|
||||
ud = [[context activeUser] userDefaults];
|
||||
|
||||
if ([ud mailAddOutgoingAddresses])
|
||||
{
|
||||
Class contactGCSEntry;
|
||||
SOGoContactFolders *contactFolders;
|
||||
SOGoContactFolder *folder;
|
||||
SOGoContactGCSEntry *newContact;
|
||||
NGVCard *card;
|
||||
NGMailAddressParser *parser;
|
||||
NSArray *matchingContacts;
|
||||
NSMutableArray *recipients;
|
||||
NSString *recipient, *emailAddress, *addressBook, *uid;
|
||||
id parsedRecipient;
|
||||
int i;
|
||||
|
||||
// Get all the addressbooks
|
||||
contactFolders = [[[context activeUser] homeFolderInContext: context]
|
||||
lookupName: @"Contacts"
|
||||
inContext: context
|
||||
acquire: NO];
|
||||
// Get all the recipients from the current email
|
||||
recipients = [self allRecipients];
|
||||
for (i = 0; i < [recipients count]; i++)
|
||||
{
|
||||
// The address contains a string. ex: "John Doe <sogo1@exemple.com>"
|
||||
recipient = [recipients objectAtIndex: i];
|
||||
parser = [NGMailAddressParser mailAddressParserWithString: recipient];
|
||||
parsedRecipient = [parser parse];
|
||||
emailAddress = [parsedRecipient address];
|
||||
|
||||
matchingContacts = [contactFolders allContactsFromFilter: emailAddress
|
||||
excludeGroups: YES
|
||||
excludeLists: YES];
|
||||
}
|
||||
// If we don't get any results from the autocompletion code, we add it..
|
||||
if ([matchingContacts count] == 0)
|
||||
{
|
||||
// Get the selected addressbook from the user preferences where the new address will be added
|
||||
addressBook = [ud selectedAddressBook];
|
||||
folder = [contactFolders lookupName: addressBook inContext: context acquire: NO];
|
||||
uid = [folder globallyUniqueObjectId];
|
||||
|
||||
if (folder && uid)
|
||||
{
|
||||
card = [NGVCard cardWithUid: uid];
|
||||
[card addEmail: emailAddress types: nil];
|
||||
|
||||
contactGCSEntry = NSClassFromString(@"SOGoContactGCSEntry");
|
||||
newContact = [contactGCSEntry objectWithName: uid
|
||||
inContainer: folder];
|
||||
[newContact setIsNew: YES];
|
||||
[newContact saveContentString: [card versitString]];
|
||||
}
|
||||
}
|
||||
}
|
||||
return [self sendMailAndCopyToSent: YES];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* SOGoDraftsFolder.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2007-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -84,6 +84,8 @@ typedef enum {
|
||||
- (NSArray *) allFolderPaths;
|
||||
- (NSArray *) allFoldersMetadata;
|
||||
|
||||
- (NSDictionary *) imapFolderGUIDs;
|
||||
|
||||
- (BOOL) isInDraftsFolder;
|
||||
|
||||
/* special folders */
|
||||
|
||||
@@ -60,6 +60,8 @@
|
||||
#import "SOGoUser+Mailer.h"
|
||||
|
||||
#import "SOGoMailAccount.h"
|
||||
#import <Foundation/NSProcessInfo.h>
|
||||
|
||||
|
||||
#define XMLNS_INVERSEDAV @"urn:inverse:params:xml:ns:inverse-dav"
|
||||
|
||||
@@ -659,6 +661,62 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
return password;
|
||||
}
|
||||
|
||||
|
||||
- (NSDictionary *) imapFolderGUIDs
|
||||
{
|
||||
NSDictionary *result, *nresult, *folderData;
|
||||
NSMutableDictionary *folders;
|
||||
NGImap4Client *client;
|
||||
SOGoUserDefaults *ud;
|
||||
NSArray *folderList;
|
||||
NSEnumerator *e;
|
||||
NSString *guid;
|
||||
id object;
|
||||
|
||||
BOOL subscribedOnly;
|
||||
|
||||
ud = [[context activeUser] userDefaults];
|
||||
subscribedOnly = [ud mailShowSubscribedFoldersOnly];
|
||||
|
||||
folderList = [[self imap4Connection] allFoldersForURL: [self imap4URL]
|
||||
onlySubscribedFolders: subscribedOnly];
|
||||
|
||||
folders = [NSMutableDictionary dictionary];
|
||||
|
||||
client = [[self imap4Connection] client];
|
||||
result = [client annotation: @"*" entryName: @"/comment" attributeName: @"value.priv"];
|
||||
|
||||
e = [folderList objectEnumerator];
|
||||
|
||||
while (object = [e nextObject])
|
||||
{
|
||||
guid = [[[[result objectForKey: @"FolderList"] objectForKey: [object substringFromIndex: 1]] objectForKey: @"/comment"] objectForKey: @"value.priv"];
|
||||
|
||||
if (!guid)
|
||||
{
|
||||
guid = [[NSProcessInfo processInfo] globallyUniqueString];
|
||||
nresult = [client annotation: [object substringFromIndex: 1] entryName: @"/comment" attributeName: @"value.priv" attributeValue: guid];
|
||||
|
||||
if (![[nresult objectForKey: @"result"] boolValue])
|
||||
{
|
||||
// Need to implement X-GUID query for Dovecot - this requires modification in SOPE to support following command:
|
||||
// 1 list "" "*" return (status (x-guid)) -> this would avoid firing a command per folder to IMAP
|
||||
nresult = [client status: [object substringFromIndex: 1] flags: [NSArray arrayWithObject: @"x-guid"]];
|
||||
guid = [nresult objectForKey: @"x-guid"];
|
||||
if (!guid)
|
||||
{
|
||||
guid = [NSString stringWithFormat: @"%@", [object substringFromIndex: 1]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[folders setObject: guid forKey: [object substringFromIndex: 1]];
|
||||
}
|
||||
|
||||
return folders;
|
||||
}
|
||||
|
||||
|
||||
/* name lookup */
|
||||
|
||||
- (id) lookupName: (NSString *) _key
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
/*
|
||||
Copyright (C) 2007-2014 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
This file is part of SOGo.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
SOGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
Loaded 100 of 382 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user