Compare commits
155
Commits
SOGo-4.0.3
...
SOGo-2.3.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f2eae5d67 | ||
|
|
9a7ea26b80 | ||
|
|
38c9a229c0 | ||
|
|
e75ec09445 | ||
|
|
58d03eedc3 | ||
|
|
98ad8f1c0b | ||
|
|
37b817cd68 | ||
|
|
9fd8f3edef | ||
|
|
ce11aca2bd | ||
|
|
861057f22f | ||
|
|
b910501afa | ||
|
|
063f878199 | ||
|
|
6bccd2eea0 | ||
|
|
652ae763d4 | ||
|
|
3da6c90bbe | ||
|
|
21a6480834 | ||
|
|
42f10e1929 | ||
|
|
03b706e1d8 | ||
|
|
2be556299e | ||
|
|
b075a306c6 | ||
|
|
36d8fa12d3 | ||
|
|
07092828fe | ||
|
|
7c0ba7b72b | ||
|
|
750a629df8 | ||
|
|
33a1d2c397 | ||
|
|
2e75972df6 | ||
|
|
1fdb44b0a7 | ||
|
|
3868ce0fb1 | ||
|
|
fc82eb79f6 | ||
|
|
9425868365 | ||
|
|
6280e4ded6 | ||
|
|
f19074334c | ||
|
|
b702e40ebb | ||
|
|
190f27ed7c | ||
|
|
cbc3e3e97d | ||
|
|
361d5ea3a6 | ||
|
|
24e3071e24 | ||
|
|
1f29198495 | ||
|
|
916442f9cf | ||
|
|
47859b76d6 | ||
|
|
3a60b6e38e | ||
|
|
ae3ac0a09a | ||
|
|
27a19ac956 | ||
|
|
27b9b7bfa7 | ||
|
|
18f758cb0a | ||
|
|
321672e2c3 | ||
|
|
8d9b54815c | ||
|
|
1dbfc18379 | ||
|
|
05b330e11b | ||
|
|
307876e6c7 | ||
|
|
ac6b299988 | ||
|
|
234db671ad | ||
|
|
2d33b01f31 | ||
|
|
490354427d | ||
|
|
22ce38808a | ||
|
|
82aca2cfe5 | ||
|
|
b17488ff25 | ||
|
|
ff3557598f | ||
|
|
26bd1b30fa | ||
|
|
0ce04fd4b6 | ||
|
|
f3656f7571 | ||
|
|
2aba083147 | ||
|
|
9414df26c5 | ||
|
|
7496b92da5 | ||
|
|
e38b0ac64f | ||
|
|
1404dbdb88 | ||
|
|
3dc8cc78ea | ||
|
|
72cbd9a45f | ||
|
|
10ac445f7c | ||
|
|
c5b5a4243d | ||
|
|
304ffa2099 | ||
|
|
e4ad255fc2 | ||
|
|
390a853471 | ||
|
|
dd9b5e18b6 | ||
|
|
5c017c19fc | ||
|
|
dec152e8e5 | ||
|
|
4922e6004d | ||
|
|
b91972d1dc | ||
|
|
5c3cdda186 | ||
|
|
4b19e64071 | ||
|
|
b6dee056ca | ||
|
|
372247a643 | ||
|
|
6830d6d930 | ||
|
|
366ad44cd1 | ||
|
|
9430f40101 | ||
|
|
b7c2d8ae95 | ||
|
|
f03e7a6604 | ||
|
|
4e7a3ce5fa | ||
|
|
61c542cb95 | ||
|
|
d2640e1501 | ||
|
|
20b91cc7bf | ||
|
|
b05f7a5beb | ||
|
|
3a61b7bae4 | ||
|
|
7bde181d3f | ||
|
|
1336a1d5a8 | ||
|
|
cf606e3224 | ||
|
|
c9f2fe2f85 | ||
|
|
10bc15d41d | ||
|
|
393b6d5128 | ||
|
|
68ae978b13 | ||
|
|
f4e3b98042 | ||
|
|
cfab18e1b8 | ||
|
|
959b4e015d | ||
|
|
7c6c78d13b | ||
|
|
7db109525d | ||
|
|
2ce85f6c5c | ||
|
|
7d2f96e96b | ||
|
|
3bf7afdfb7 | ||
|
|
503a70118f | ||
|
|
928b6b596e | ||
|
|
d0d93a297b | ||
|
|
936c38c43e | ||
|
|
7da7bdc1bf | ||
|
|
1e101ef01a | ||
|
|
3171257ef4 | ||
|
|
2c8d65843f | ||
|
|
62b16f4ef3 | ||
|
|
b86b1afdb9 | ||
|
|
8e047aaa9c | ||
|
|
dc2cc14d25 | ||
|
|
3f1a43cc13 | ||
|
|
67d0d95869 | ||
|
|
d16bf7c1a7 | ||
|
|
b527099907 | ||
|
|
72aab7f83f | ||
|
|
dfecce7381 | ||
|
|
82798ccb99 | ||
|
|
3809c002ed | ||
|
|
d9b4abc2f1 | ||
|
|
c1b0fd53dc | ||
|
|
c0a22ead1d | ||
|
|
d8e37cd7d8 | ||
|
|
7540cc3e33 | ||
|
|
d92b0341fb | ||
|
|
5e84f2817f | ||
|
|
c61eca27a1 | ||
|
|
96d88de564 | ||
|
|
90e11d76f6 | ||
|
|
3dd8bddc0e | ||
|
|
95f11f6d0d | ||
|
|
1ec53a063c | ||
|
|
cab5846e37 | ||
|
|
76f80c507c | ||
|
|
afed233131 | ||
|
|
b04b66fd79 | ||
|
|
13f2ac9cbb | ||
|
|
7dc333e790 | ||
|
|
cc62576fef | ||
|
|
a1d07c59af | ||
|
|
0a37652dd6 | ||
|
|
725dea5f6f | ||
|
|
76dd53b461 | ||
|
|
020c895925 | ||
|
|
f4963df50f | ||
|
|
7160d94e91 |
No files matched your search
+22
@@ -25,8 +25,10 @@ trans.pl = UI/MailerUI/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/MailerUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/MailerUI/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/MailerUI/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/MailerUI/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/MailerUI/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/MailerUI/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-preferencesui]
|
||||
source_file = UI/PreferencesUI/English.lproj/Localizable.strings
|
||||
@@ -52,8 +54,10 @@ trans.pl = UI/PreferencesUI/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/PreferencesUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/PreferencesUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/PreferencesUI/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/PreferencesUI/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/PreferencesUI/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/PreferencesUI/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/PreferencesUI/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-scheduler]
|
||||
source_file = UI/Scheduler/English.lproj/Localizable.strings
|
||||
@@ -79,8 +83,10 @@ trans.pl = UI/Scheduler/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/Scheduler/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/Scheduler/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/Scheduler/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/Scheduler/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/Scheduler/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/Scheduler/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-contacts]
|
||||
source_file = UI/Contacts/English.lproj/Localizable.strings
|
||||
@@ -106,8 +112,10 @@ trans.pl = UI/Contacts/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/Contacts/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/Contacts/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/Contacts/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/Contacts/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/Contacts/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/Contacts/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/Contacts/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-mainui]
|
||||
source_file = UI/MainUI/English.lproj/Localizable.strings
|
||||
@@ -133,8 +141,10 @@ trans.pl = UI/MainUI/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/MainUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/MainUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/MainUI/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/MainUI/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/MainUI/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/MainUI/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/MainUI/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-common]
|
||||
source_file = UI/Common/English.lproj/Localizable.strings
|
||||
@@ -160,8 +170,10 @@ trans.pl = UI/Common/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/Common/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/Common/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/Common/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/Common/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/Common/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/Common/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/Common/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-administrationui]
|
||||
source_file = UI/AdministrationUI/English.lproj/Localizable.strings
|
||||
@@ -187,8 +199,10 @@ trans.pl = UI/AdministrationUI/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/AdministrationUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/AdministrationUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/AdministrationUI/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/AdministrationUI/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/AdministrationUI/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/AdministrationUI/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/AdministrationUI/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.soobjects-appointments]
|
||||
source_file = SoObjects/Appointments/English.lproj/Localizable.strings
|
||||
@@ -214,8 +228,10 @@ trans.pl = SoObjects/Appointments/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = SoObjects/Appointments/Russian.lproj/Localizable.strings
|
||||
trans.sk = SoObjects/Appointments/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = SoObjects/Appointments/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = SoObjects/Appointments/Swedish.lproj/Localizable.strings
|
||||
trans.uk = SoObjects/Appointments/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = SoObjects/Appointments/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.soobjects-contacts]
|
||||
source_file = SoObjects/Contacts/English.lproj/Localizable.strings
|
||||
@@ -241,8 +257,10 @@ trans.pl = SoObjects/Contacts/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = SoObjects/Contacts/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = SoObjects/Contacts/Russian.lproj/Localizable.strings
|
||||
trans.sk = SoObjects/Contacts/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = SoObjects/Contacts/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = SoObjects/Contacts/Swedish.lproj/Localizable.strings
|
||||
trans.uk = SoObjects/Contacts/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = SoObjects/Contacts/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.soobjects-mailer]
|
||||
source_file = SoObjects/Mailer/English.lproj/Localizable.strings
|
||||
@@ -268,8 +286,10 @@ 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.sl_SI = SoObjects/Mailer/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = SoObjects/Mailer/Swedish.lproj/Localizable.strings
|
||||
trans.uk = SoObjects/Mailer/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = SoObjects/Mailer/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-mailpartviewers]
|
||||
source_file = UI/MailPartViewers/English.lproj/Localizable.strings
|
||||
@@ -295,5 +315,7 @@ trans.pl = UI/MailPartViewers/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/MailPartViewers/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/MailPartViewers/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/MailPartViewers/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/MailPartViewers/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/MailPartViewers/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/MailPartViewers/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/MailPartViewers/ChineseTaiwan.lproj/Localizable.strings
|
||||
@@ -131,10 +131,12 @@ static NSArray *easCommandParameters = nil;
|
||||
}
|
||||
}
|
||||
|
||||
self = [[[NSString alloc] initWithBytes:buf length:(j) * sizeof(wchar_t) encoding:NSUTF32StringEncoding] autorelease];
|
||||
self = [[NSString alloc] initWithBytesNoCopy: buf
|
||||
length: (j*sizeof(wchar_t))
|
||||
encoding: NSUTF32StringEncoding
|
||||
freeWhenDone: YES];
|
||||
|
||||
if (buf) free(buf);
|
||||
return self;
|
||||
return [self autorelease];
|
||||
}
|
||||
|
||||
- (NSString *) sanitizedServerIdWithType: (SOGoMicrosoftActiveSyncFolderType) folderType
|
||||
|
||||
@@ -133,6 +133,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[[o properties] removeObjectForKey: @"MoreAvailable"];
|
||||
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
|
||||
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
|
||||
[[o properties] removeObjectForKey: @"InitialLoadSequence"];
|
||||
|
||||
[[o properties] addEntriesFromDictionary: values];
|
||||
[o save];
|
||||
@@ -159,7 +160,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
NSString *nameInCache;
|
||||
|
||||
if (theFolderType == ActiveSyncMailFolder)
|
||||
nameInCache= [[[theCollection mailAccountFolder] imapFolderGUIDs] objectForKey: [theCollection nameInContainer]];
|
||||
nameInCache = [imapFolderGUIDS objectForKey: [theCollection nameInContainer]];
|
||||
else
|
||||
{
|
||||
NSString *component_name;
|
||||
@@ -170,7 +171,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
else
|
||||
component_name = @"vtodo";
|
||||
|
||||
nameInCache= [NSString stringWithFormat: @"%@/%@", component_name, [theCollection nameInContainer]];
|
||||
nameInCache = [NSString stringWithFormat: @"%@/%@", component_name, [theCollection nameInContainer]];
|
||||
}
|
||||
|
||||
return nameInCache;
|
||||
@@ -283,7 +284,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
serverId = [NSString stringWithFormat: @"%@.ics", [theCollection globallyUniqueObjectId]];
|
||||
sogoObject = [[SOGoTaskObject alloc] initWithName: serverId
|
||||
inContainer: theCollection];
|
||||
o = [sogoObject component: YES secure: NO];
|
||||
o = [sogoObject component: YES secure: NO];
|
||||
}
|
||||
break;
|
||||
case ActiveSyncMailFolder:
|
||||
@@ -311,10 +312,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syncCache = [folderMetadata objectForKey: @"SyncCache"];
|
||||
dateCache = [folderMetadata objectForKey: @"DateCache"];
|
||||
|
||||
[syncCache setObject: [folderMetadata objectForKey: @"SyncKey"] forKey: serverId];
|
||||
|
||||
[syncCache setObject: [NSString stringWithFormat:@"%f", [[sogoObject lastModified] timeIntervalSince1970]] forKey: serverId];
|
||||
[dateCache setObject: [NSCalendarDate date] forKey: serverId];
|
||||
|
||||
|
||||
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
|
||||
}
|
||||
}
|
||||
@@ -365,6 +366,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
NSString *serverId;
|
||||
NSArray *changes;
|
||||
id aChange, o, sogoObject;
|
||||
NSMutableDictionary *folderMetadata, *syncCache;
|
||||
|
||||
int i;
|
||||
|
||||
@@ -372,6 +374,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if ([changes count])
|
||||
{
|
||||
folderMetadata = [self _folderMetadataForKey: [self _getNameInCache: theCollection withType: theFolderType]];
|
||||
syncCache = [folderMetadata objectForKey: @"SyncCache"];
|
||||
|
||||
for (i = 0; i < [changes count]; i++)
|
||||
{
|
||||
aChange = [changes objectAtIndex: i];
|
||||
@@ -398,6 +403,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
o = [sogoObject vCard];
|
||||
[o takeActiveSyncValues: allChanges inContext: context];
|
||||
[sogoObject saveComponent: o];
|
||||
|
||||
[syncCache setObject: [NSString stringWithFormat:@"%f", [[sogoObject lastModified] timeIntervalSince1970]] forKey: serverId];
|
||||
|
||||
}
|
||||
break;
|
||||
case ActiveSyncEventFolder:
|
||||
@@ -406,15 +414,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
o = [sogoObject component: NO secure: NO];
|
||||
[o takeActiveSyncValues: allChanges inContext: context];
|
||||
[sogoObject saveComponent: o];
|
||||
|
||||
[syncCache setObject: [NSString stringWithFormat:@"%f", [[sogoObject lastModified] timeIntervalSince1970]] forKey: serverId];
|
||||
|
||||
}
|
||||
break;
|
||||
case ActiveSyncMailFolder:
|
||||
default:
|
||||
{
|
||||
NSDictionary *result;
|
||||
NSString *modseq;
|
||||
|
||||
[sogoObject takeActiveSyncValues: allChanges inContext: context];
|
||||
|
||||
result = [sogoObject fetchParts: [NSArray arrayWithObject: @"MODSEQ"]];
|
||||
modseq = [[[result objectForKey: @"RawResponse"] objectForKey: @"fetch"] objectForKey: @"modseq"];
|
||||
|
||||
if (modseq)
|
||||
[syncCache setObject: modseq forKey: serverId];
|
||||
}
|
||||
}
|
||||
|
||||
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
|
||||
|
||||
|
||||
[theBuffer appendString: @"<Change>"];
|
||||
[theBuffer appendFormat: @"<ServerId>%@</ServerId>", serverId];
|
||||
[theBuffer appendFormat: @"<Status>%d</Status>", 1];
|
||||
@@ -453,16 +476,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
withType: (SOGoMicrosoftActiveSyncFolderType) theFolderType
|
||||
inBuffer: (NSMutableString *) theBuffer
|
||||
{
|
||||
|
||||
id aDelete, sogoObject, value;
|
||||
NSArray *deletions;
|
||||
NSString *serverId;
|
||||
|
||||
id aDelete, sogoObject;
|
||||
BOOL deletesAsMoves, useTrash;
|
||||
int i;
|
||||
|
||||
deletions = (id)[theDocumentElement getElementsByTagName: @"Delete"];
|
||||
|
||||
if ([deletions count])
|
||||
{
|
||||
// From the documention, if DeletesAsMoves is missing, we must assume it's a YES.
|
||||
// See https://msdn.microsoft.com/en-us/library/gg675480(v=exchg.80).aspx for all details.
|
||||
value = [theDocumentElement getElementsByTagName: @"DeletesAsMoves"];
|
||||
deletesAsMoves = YES;
|
||||
useTrash = YES;
|
||||
|
||||
if ([value count] && [[[value lastObject] textValue] length])
|
||||
deletesAsMoves = [[[value lastObject] textValue] boolValue];
|
||||
|
||||
for (i = 0; i < [deletions count]; i++)
|
||||
{
|
||||
aDelete = [deletions objectAtIndex: i];
|
||||
@@ -474,7 +508,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
acquire: NO];
|
||||
|
||||
if (![sogoObject isKindOfClass: [NSException class]])
|
||||
[sogoObject delete];
|
||||
{
|
||||
// FIXME: handle errors here
|
||||
if (deletesAsMoves && theFolderType == ActiveSyncMailFolder)
|
||||
[(SOGoMailFolder *)[sogoObject container] deleteUIDs: [NSArray arrayWithObjects: serverId, nil] useTrashFolder: &useTrash inContext: context];
|
||||
else
|
||||
[sogoObject delete];
|
||||
}
|
||||
|
||||
[theBuffer appendString: @"<Delete>"];
|
||||
[theBuffer appendFormat: @"<ServerId>%@</ServerId>", serverId];
|
||||
@@ -634,7 +674,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
NSDictionary *component;
|
||||
NSArray *allComponents;
|
||||
|
||||
BOOL updated;
|
||||
BOOL updated, initialLoadInProgress;
|
||||
int deleted, return_count;
|
||||
|
||||
if (theFolderType == ActiveSyncContactFolder)
|
||||
@@ -644,7 +684,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
else
|
||||
component_name = @"vtodo";
|
||||
|
||||
allComponents = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType];
|
||||
initialLoadInProgress = NO;
|
||||
|
||||
if ([theSyncKey isEqualToString: @"-1"])
|
||||
[folderMetadata setObject: davCollectionTagToStore forKey: @"InitialLoadSequence"];
|
||||
|
||||
if ([folderMetadata objectForKey: @"InitialLoadSequence"])
|
||||
{
|
||||
if ([theSyncKey intValue] < [[folderMetadata objectForKey: @"InitialLoadSequence"] intValue])
|
||||
initialLoadInProgress = YES;
|
||||
else
|
||||
[folderMetadata removeObjectForKey: @"InitialLoadSequence"];
|
||||
}
|
||||
|
||||
allComponents = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType initialLoad: initialLoadInProgress];
|
||||
allComponents = [allComponents sortedArrayUsingDescriptors: [NSArray arrayWithObjects: [[NSSortDescriptor alloc] initWithKey: @"c_lastmodified" ascending:YES], nil]];
|
||||
|
||||
|
||||
@@ -808,12 +861,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
NSMutableArray *allCacheObjects, *sortedBySequence;
|
||||
|
||||
SOGoMailObject *mailObject;
|
||||
NSArray *allMessages;
|
||||
NSArray *allMessages, *a;
|
||||
|
||||
int j, k, return_count;
|
||||
BOOL found_in_cache;
|
||||
int j, k, return_count, highestmodseq;
|
||||
BOOL found_in_cache, initialLoadInProgress;
|
||||
|
||||
allMessages = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType];
|
||||
initialLoadInProgress = NO;
|
||||
|
||||
if ([theSyncKey isEqualToString: @"-1"])
|
||||
{
|
||||
highestmodseq = 0;
|
||||
|
||||
a = [[theCollection davCollectionTag] componentsSeparatedByString: @"-"];
|
||||
[folderMetadata setObject: [a objectAtIndex: 1] forKey: @"InitialLoadSequence"];
|
||||
}
|
||||
else
|
||||
{
|
||||
a = [theSyncKey componentsSeparatedByString: @"-"];
|
||||
highestmodseq = [[a objectAtIndex: 1] intValue];
|
||||
}
|
||||
|
||||
if ([folderMetadata objectForKey: @"InitialLoadSequence"])
|
||||
{
|
||||
if (highestmodseq < [[folderMetadata objectForKey: @"InitialLoadSequence"] intValue])
|
||||
initialLoadInProgress = YES;
|
||||
else
|
||||
[folderMetadata removeObjectForKey: @"InitialLoadSequence"];
|
||||
}
|
||||
|
||||
allMessages = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType initialLoad: initialLoadInProgress];
|
||||
max = [allMessages count];
|
||||
|
||||
allCacheObjects = [NSMutableArray array];
|
||||
@@ -872,7 +948,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
NSString *lastSequence;
|
||||
more_available = YES;
|
||||
|
||||
lastSequence = ([[aCacheObject sequence] isEqual: [NSNull null]] ? @"1" : [aCacheObject sequence]);
|
||||
lastSequence = ([[aCacheObject sequence] isEqual: [NSNull null]] ? [NSString stringWithFormat:@"%d", highestmodseq] : [aCacheObject sequence]);
|
||||
*theLastServerKey = [[NSString alloc] initWithFormat: @"%@-%@", [aCacheObject uid], lastSequence];
|
||||
//NSLog(@"Reached windowSize - lastUID will be: %@", *theLastServerKey);
|
||||
DESTROY(pool);
|
||||
@@ -893,6 +969,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
[syncCache removeObjectForKey: [aCacheObject uid]];
|
||||
[dateCache removeObjectForKey: [aCacheObject uid]];
|
||||
|
||||
return_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -902,17 +980,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
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>"];
|
||||
|
||||
if (![[aCacheObject sequence] isEqual: [syncCache objectForKey: [aCacheObject uid]]])
|
||||
{
|
||||
[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>"];
|
||||
|
||||
return_count++;
|
||||
}
|
||||
|
||||
[syncCache setObject: [aCacheObject sequence] forKey: [aCacheObject uid]];
|
||||
}
|
||||
|
||||
return_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1187,22 +1268,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
[context setObject: bodyPreferenceType forKey: @"BodyPreferenceType"];
|
||||
|
||||
// We generate the commands, if any, for the response. We might also have
|
||||
// generated some in processSyncCommand:inResponse: as we could have
|
||||
// received a Fetch command
|
||||
if (getChanges && !first_sync)
|
||||
{
|
||||
[self processSyncGetChanges: theDocumentElement
|
||||
inCollection: collection
|
||||
withWindowSize: windowSize
|
||||
withMaxSyncResponseSize: theMaxSyncResponseSize
|
||||
withSyncKey: syncKey
|
||||
withFolderType: folderType
|
||||
withFilterType: [NSCalendarDate dateFromFilterType: [[(id)[theDocumentElement getElementsByTagName: @"FilterType"] lastObject] textValue]]
|
||||
inBuffer: changeBuffer
|
||||
lastServerKey: &lastServerKey];
|
||||
}
|
||||
|
||||
//
|
||||
// We process the commands from the request
|
||||
//
|
||||
@@ -1220,12 +1285,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
inBuffer: s
|
||||
processed: &processed];
|
||||
|
||||
// Windows phons don't empty Responses tags - such as: <Responses></Responses>.
|
||||
// We onnly generate this tag when the command has generated a response.
|
||||
// Windows phones don't like empty Responses tags - such as: <Responses></Responses>.
|
||||
// We only generate this tag when there is a response
|
||||
if (processed && [s length])
|
||||
[commandsBuffer appendFormat: @"<Responses>%@</Responses>", s];
|
||||
}
|
||||
|
||||
|
||||
|
||||
// We generate the commands, if any, for the response. We might also have
|
||||
// generated some in processSyncCommand:inResponse: as we could have
|
||||
// received a Fetch command
|
||||
if (getChanges && !first_sync)
|
||||
{
|
||||
[self processSyncGetChanges: theDocumentElement
|
||||
inCollection: collection
|
||||
withWindowSize: windowSize
|
||||
withMaxSyncResponseSize: theMaxSyncResponseSize
|
||||
withSyncKey: syncKey
|
||||
withFolderType: folderType
|
||||
withFilterType: [NSCalendarDate dateFromFilterType: [[(id)[theDocumentElement getElementsByTagName: @"FilterType"] lastObject] textValue]]
|
||||
inBuffer: changeBuffer
|
||||
lastServerKey: &lastServerKey];
|
||||
}
|
||||
|
||||
folderMetadata = [self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]];
|
||||
|
||||
// If we got any changes or if we have applied any commands
|
||||
@@ -1250,7 +1332,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
// Make sure that client is updated with the right syncKey. - This keeps vtodo's and vevent's syncKey in sync.
|
||||
syncKeyInCache = [folderMetadata objectForKey: @"SyncKey"];
|
||||
if (syncKeyInCache && !([davCollectionTag isEqualToString:syncKeyInCache]) && ![davCollectionTag isEqualToString: @"-1"])
|
||||
if (syncKeyInCache && !([davCollectionTag isEqualToString:syncKeyInCache]) && !first_sync)
|
||||
{
|
||||
davCollectionTag = syncKeyInCache;
|
||||
*changeDetected = YES;
|
||||
|
||||
@@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@interface SOGoActiveSyncDispatcher : NSObject
|
||||
{
|
||||
NSURL *folderTableURL;
|
||||
NSDictionary *imapFolderGUIDS;
|
||||
id context;
|
||||
}
|
||||
|
||||
|
||||
@@ -151,12 +151,14 @@ static BOOL debugOn = NO;
|
||||
|
||||
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] easDebugEnabled];
|
||||
folderTableURL = nil;
|
||||
imapFolderGUIDS = nil;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(folderTableURL);
|
||||
RELEASE(imapFolderGUIDS);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -229,23 +231,27 @@ static BOOL debugOn = NO;
|
||||
SOGoMailAccounts *accountsFolder;
|
||||
SOGoMailAccount *accountFolder;
|
||||
SOGoUserFolder *userFolder;
|
||||
NSDictionary *imapGUIDs;
|
||||
|
||||
userFolder = [[context activeUser] homeFolderInContext: context];
|
||||
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
|
||||
accountFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
|
||||
|
||||
// Get the GUID of the IMAP folder
|
||||
imapGUIDs = [accountFolder imapFolderGUIDs];
|
||||
|
||||
//return [[imapGUIDs allKeysForObject: theIdToTranslate] objectAtIndex: 0];
|
||||
return [[[imapGUIDs allKeysForObject: [NSString stringWithFormat: @"folder%@", theIdToTranslate]] objectAtIndex: 0] substringFromIndex: 6] ;
|
||||
if (!imapFolderGUIDS)
|
||||
{
|
||||
userFolder = [[context activeUser] homeFolderInContext: context];
|
||||
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
|
||||
accountFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
|
||||
|
||||
// Get the GUID of the IMAP folder
|
||||
imapFolderGUIDS = [accountFolder imapFolderGUIDs];
|
||||
[imapFolderGUIDS retain];
|
||||
|
||||
}
|
||||
|
||||
return [[[imapFolderGUIDS allKeysForObject: [NSString stringWithFormat: @"folder%@", theIdToTranslate]] objectAtIndex: 0] substringFromIndex: 6] ;
|
||||
}
|
||||
|
||||
return theIdToTranslate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -699,7 +705,7 @@ static BOOL debugOn = NO;
|
||||
SOGoMailAccount *accountFolder;
|
||||
NSMutableString *s, *commands;
|
||||
SOGoUserFolder *userFolder;
|
||||
NSMutableArray *folders;
|
||||
NSMutableArray *folders, *processedFolders;
|
||||
SoSecurityManager *sm;
|
||||
SOGoCacheGCSObject *o;
|
||||
id currentFolder;
|
||||
@@ -719,6 +725,8 @@ static BOOL debugOn = NO;
|
||||
command_count = 0;
|
||||
commands = [NSMutableString string];
|
||||
|
||||
processedFolders = [NSMutableArray array];
|
||||
|
||||
[s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
|
||||
[s appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
|
||||
|
||||
@@ -727,7 +735,7 @@ static BOOL debugOn = NO;
|
||||
first_sync = YES;
|
||||
syncKey = @"1";
|
||||
}
|
||||
else if (![syncKey isEqualToString: [metadata objectForKey: @"FolderSyncKey"]])
|
||||
else if (![metadata objectForKey: @"FolderSyncKey"])
|
||||
{
|
||||
// Synchronization key mismatch or invalid synchronization key
|
||||
//NSLog(@"FolderSync syncKey mismatch %@ <> %@", syncKey, metadata);
|
||||
@@ -862,7 +870,13 @@ static BOOL debugOn = NO;
|
||||
|
||||
serverId = [NSString stringWithFormat: @"mail/%@", [[imapGUIDs objectForKey: nameInCache] substringFromIndex: 6]];
|
||||
name = [folderMetadata objectForKey: @"displayName"];
|
||||
|
||||
|
||||
// avoid duplicate folders if folder is returned by different imap namespaces
|
||||
if ([processedFolders indexOfObject: serverId] == NSNotFound)
|
||||
[processedFolders addObject: serverId];
|
||||
else
|
||||
continue;
|
||||
|
||||
if ([name hasPrefix: @"/"])
|
||||
name = [name substringFromIndex: 1];
|
||||
|
||||
@@ -874,7 +888,10 @@ static BOOL debugOn = NO;
|
||||
|
||||
if ([folderMetadata objectForKey: @"parent"])
|
||||
{
|
||||
parentId = [NSString stringWithFormat: @"mail/%@", [[imapGUIDs objectForKey: [NSString stringWithFormat: @"folder%@", [[folderMetadata objectForKey: @"parent"] substringFromIndex: 1]]] substringFromIndex: 6]];
|
||||
// make sure that parent of main-folders is always 0
|
||||
if (type == 12)
|
||||
parentId = [NSString stringWithFormat: @"mail/%@", [[imapGUIDs objectForKey: [NSString stringWithFormat: @"folder%@", [[folderMetadata objectForKey: @"parent"] substringFromIndex: 1]]] substringFromIndex: 6]];
|
||||
|
||||
name = [[name pathComponents] lastObject];
|
||||
}
|
||||
|
||||
@@ -927,6 +944,7 @@ static BOOL debugOn = NO;
|
||||
[[o properties] removeObjectForKey: @"MoreAvailable"];
|
||||
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
|
||||
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
|
||||
[[o properties] removeObjectForKey: @"InitialLoadSequence"];
|
||||
[o save];
|
||||
|
||||
command_count++;
|
||||
@@ -1012,6 +1030,7 @@ static BOOL debugOn = NO;
|
||||
[[o properties] removeObjectForKey: @"MoreAvailable"];
|
||||
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
|
||||
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
|
||||
[[o properties] removeObjectForKey: @"InitialLoadSequence"];
|
||||
}
|
||||
|
||||
[o save];
|
||||
@@ -1035,6 +1054,7 @@ static BOOL debugOn = NO;
|
||||
[[o properties] removeObjectForKey: @"MoreAvailable"];
|
||||
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
|
||||
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
|
||||
[[o properties] removeObjectForKey: @"InitialLoadSequence"];
|
||||
}
|
||||
|
||||
[o save];
|
||||
@@ -1193,7 +1213,7 @@ static BOOL debugOn = NO;
|
||||
filter = [NSCalendarDate dateFromFilterType: [[(id)[[allCollections objectAtIndex: j] getElementsByTagName: @"FilterType"] lastObject] textValue]];
|
||||
syncKey = [[(id)[[allCollections objectAtIndex: j] getElementsByTagName: @"SyncKey"] lastObject] textValue];
|
||||
|
||||
allMessages = [currentCollection syncTokenFieldsWithProperties: nil matchingSyncToken: syncKey fromDate: filter];
|
||||
allMessages = [currentCollection syncTokenFieldsWithProperties: nil matchingSyncToken: syncKey fromDate: filter initialLoad: NO];
|
||||
|
||||
count = [allMessages count];
|
||||
|
||||
@@ -2565,7 +2585,7 @@ static BOOL debugOn = NO;
|
||||
NGMimeFileData *fdata;
|
||||
NSException *error;
|
||||
NSArray *attachmentKeys;
|
||||
NSMutableArray *attachments;
|
||||
NSMutableArray *attachments, *references;
|
||||
|
||||
id body, bodyFromSmartForward, htmlPart, textPart;
|
||||
NSString *fullName, *email, *charset, *s;
|
||||
@@ -2604,7 +2624,25 @@ static BOOL debugOn = NO;
|
||||
[map setObject: email forKey: @"from"];
|
||||
|
||||
if ([mailObject messageId])
|
||||
[map setObject: [mailObject messageId] forKey: @"in-reply-to"];
|
||||
{
|
||||
[map setObject: [mailObject messageId] forKey: @"in-reply-to"];
|
||||
|
||||
references = [[[[[mailObject mailHeaders] objectForKey: @"references"] componentsSeparatedByString: @" "] mutableCopy] autorelease];
|
||||
if ([references count] > 0)
|
||||
{
|
||||
// If there are more than ten identifiers listed, we eliminate the second one.
|
||||
if ([references count] >= 10)
|
||||
[references removeObjectAtIndex: 1];
|
||||
|
||||
[references addObject: [mailObject messageId]];
|
||||
|
||||
[map setObject: [references componentsJoinedByString:@" "] forKey: @"references"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[map setObject: [mailObject messageId] forKey: @"references"];
|
||||
}
|
||||
}
|
||||
|
||||
messageToSend = [[[NGMimeMessage alloc] initWithHeader: map] autorelease];
|
||||
body = [[[NGMimeMultipartBody alloc] initWithPart: messageToSend] autorelease];
|
||||
@@ -2862,6 +2900,7 @@ static BOOL debugOn = NO;
|
||||
NSAutoreleasePool *pool;
|
||||
id builder, dom;
|
||||
SEL aSelector;
|
||||
id activeUser;
|
||||
|
||||
NSString *cmdName, *deviceId;
|
||||
NSData *d;
|
||||
@@ -2870,6 +2909,14 @@ static BOOL debugOn = NO;
|
||||
|
||||
ASSIGN(context, theContext);
|
||||
|
||||
activeUser = [context activeUser];
|
||||
if (![activeUser canAccessModule: @"ActiveSync"])
|
||||
{
|
||||
[(WOResponse *)theResponse setStatus: 403];
|
||||
[self logWithFormat: @"EAS - Forbidden access for user %@", [activeUser loginInDomain]];
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Get the device ID, device type and "stash" them
|
||||
deviceId = [[theRequest uri] deviceId];
|
||||
[context setObject: deviceId forKey: @"DeviceId"];
|
||||
|
||||
@@ -77,6 +77,41 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import <Appointments/SOGoAptMailNotification.h>
|
||||
|
||||
unsigned char strToChar(char a, char b) {
|
||||
char encoder[3] = {'\0','\0','\0'};
|
||||
encoder[0] = a;
|
||||
encoder[1] = b;
|
||||
return (char) strtol(encoder,NULL,16);
|
||||
}
|
||||
|
||||
@interface NSString (NSStringExtensions)
|
||||
- (NSData *) decodeFromHexidecimal;
|
||||
@end
|
||||
|
||||
@implementation NSString (NSStringExtensions)
|
||||
|
||||
- (NSData *) decodeFromHexidecimal;
|
||||
{
|
||||
const char * bytes = [self cStringUsingEncoding: NSUTF8StringEncoding];
|
||||
NSUInteger length = strlen(bytes);
|
||||
unsigned char * r = (unsigned char *) malloc(length / 2 + 1);
|
||||
unsigned char * index = r;
|
||||
|
||||
while ((*bytes) && (*(bytes +1))) {
|
||||
*index = strToChar(*bytes, *(bytes +1));
|
||||
index++;
|
||||
bytes+=2;
|
||||
}
|
||||
*index = '\0';
|
||||
|
||||
NSData * result = [NSData dataWithBytes: r length: length / 2];
|
||||
free(r);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
typedef struct {
|
||||
uint32_t dwLowDateTime;
|
||||
uint32_t dwHighDateTime;
|
||||
@@ -91,7 +126,7 @@ struct GlobalObjectId {
|
||||
FILETIME CreationTime;
|
||||
uint8_t X[8];
|
||||
uint32_t Size;
|
||||
uint8_t* Data;
|
||||
uint8_t Data[0];
|
||||
};
|
||||
|
||||
@implementation SOGoMailObject (ActiveSync)
|
||||
@@ -118,39 +153,40 @@ struct GlobalObjectId {
|
||||
//
|
||||
// The GlobalObjId is documented here: http://msdn.microsoft.com/en-us/library/ee160198(v=EXCHG.80).aspx
|
||||
//
|
||||
|
||||
- (NSData *) _computeGlobalObjectIdFromEvent: (iCalEvent *) event
|
||||
{
|
||||
NSData *binPrefix, *globalObjectId, *uidAsASCII;
|
||||
NSString *prefix, *uid;
|
||||
|
||||
struct GlobalObjectId newGlobalId;
|
||||
struct GlobalObjectId *newGlobalId;
|
||||
const char *bytes;
|
||||
|
||||
|
||||
uid = [event uid];
|
||||
uidAsASCII = [uid decodeFromHexidecimal];
|
||||
newGlobalId = (struct GlobalObjectId*)calloc(sizeof(uint8_t), sizeof(struct GlobalObjectId) + 0x0c + [uidAsASCII length]);
|
||||
|
||||
prefix = @"040000008200e00074c5b7101a82e008";
|
||||
|
||||
// dataPrefix is "vCal-Uid %x01 %x00 %x00 %x00"
|
||||
uint8_t dataPrefix[] = { 0x76, 0x43, 0x61, 0x6c, 0x2d, 0x55, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00 };
|
||||
uid = [event uid];
|
||||
|
||||
binPrefix = [prefix convertHexStringToBytes];
|
||||
[binPrefix getBytes: &newGlobalId.ByteArrayID];
|
||||
[self _setInstanceDate: &newGlobalId
|
||||
[binPrefix getBytes: &newGlobalId->ByteArrayID];
|
||||
[self _setInstanceDate: newGlobalId
|
||||
fromDate: [event recurrenceId]];
|
||||
uidAsASCII = [uid dataUsingEncoding: NSASCIIStringEncoding];
|
||||
bytes = [uidAsASCII bytes];
|
||||
|
||||
// 0x0c is the size of our dataPrefix
|
||||
newGlobalId.Size = 0x0c + [uidAsASCII length];
|
||||
newGlobalId.Data = malloc(newGlobalId.Size * sizeof(uint8_t));
|
||||
memcpy(newGlobalId.Data, dataPrefix, 0x0c);
|
||||
memcpy(newGlobalId.Data + 0x0c, bytes, newGlobalId.Size - 0x0c);
|
||||
newGlobalId->Size = 0x0c + [uidAsASCII length];
|
||||
memcpy(newGlobalId->Data, dataPrefix, 0x0c);
|
||||
memcpy(newGlobalId->Data + 0x0c, bytes, newGlobalId->Size - 0x0c);
|
||||
|
||||
globalObjectId = [[NSData alloc] initWithBytes: &newGlobalId length: 40 + newGlobalId.Size*sizeof(uint8_t)];
|
||||
free(newGlobalId.Data);
|
||||
|
||||
globalObjectId = [[NSData alloc] initWithBytes: newGlobalId length: 40 + newGlobalId->Size*sizeof(uint8_t)];
|
||||
free(newGlobalId);
|
||||
return [globalObjectId autorelease];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// For debugging purposes...
|
||||
//
|
||||
@@ -514,6 +550,28 @@ struct GlobalObjectId {
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) _getNormalizedSubject
|
||||
{
|
||||
NSString *subject;
|
||||
NSUInteger colIdx;
|
||||
NSString *stringValue;
|
||||
|
||||
subject = [[self subject] decodedHeader];
|
||||
|
||||
colIdx = [subject rangeOfString: @":" options:NSBackwardsSearch].location;
|
||||
if (colIdx != NSNotFound && colIdx + 1 < [subject length])
|
||||
stringValue = [[subject substringFromIndex: colIdx + 1] stringByTrimmingLeadSpaces];
|
||||
else
|
||||
stringValue = subject;
|
||||
|
||||
if (!stringValue)
|
||||
stringValue = @"";
|
||||
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -627,7 +685,7 @@ struct GlobalObjectId {
|
||||
if (value)
|
||||
{
|
||||
[s appendFormat: @"<Subject xmlns=\"Email:\">%@</Subject>", [value activeSyncRepresentationInContext: context]];
|
||||
[s appendFormat: @"<ThreadTopic xmlns=\"Email:\">%@</ThreadTopic>", [value activeSyncRepresentationInContext: context]];
|
||||
[s appendFormat: @"<ThreadTopic xmlns=\"Email:\">%@</ThreadTopic>", [[self _getNormalizedSubject] activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
// DateReceived
|
||||
@@ -1013,7 +1071,13 @@ struct GlobalObjectId {
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"14.0"] ||
|
||||
[[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"14.1"])
|
||||
{
|
||||
if ([self inReplyTo])
|
||||
NSString *reference;
|
||||
|
||||
reference = [[[[self mailHeaders] objectForKey: @"references"] componentsSeparatedByString: @" "] objectAtIndex: 0];
|
||||
|
||||
if ([reference length] > 0)
|
||||
[s appendFormat: @"<ConversationId xmlns=\"Email2:\">%@</ConversationId>", [[reference dataUsingEncoding: NSUTF8StringEncoding] activeSyncRepresentationInContext: context]];
|
||||
else if ([self inReplyTo])
|
||||
[s appendFormat: @"<ConversationId xmlns=\"Email2:\">%@</ConversationId>", [[[self inReplyTo] dataUsingEncoding: NSUTF8StringEncoding] activeSyncRepresentationInContext: context]];
|
||||
else if ([self messageId])
|
||||
[s appendFormat: @"<ConversationId xmlns=\"Email2:\">%@</ConversationId>", [[[self messageId] dataUsingEncoding: NSUTF8StringEncoding] activeSyncRepresentationInContext: context]];
|
||||
|
||||
@@ -1035,8 +1035,8 @@ repository
|
||||
|
||||
|ModulesConstraints (optional)
|
||||
|Limits the access of any module through a constraint based on an LDAP
|
||||
attribute; must be a dictionary with keys `Mail`, and/or `Calendar`, for
|
||||
example:
|
||||
attribute; must be a dictionary with keys `Mail`, and/or `Calendar`,
|
||||
and/or `ActiveSync` for example:
|
||||
|
||||
----
|
||||
ModulesConstraints = {
|
||||
|
||||
@@ -233,6 +233,7 @@ Installation
|
||||
This section will guide you through the installation of the native
|
||||
Microsoft Outlook compatibility layer SOGo offers.
|
||||
|
||||
////
|
||||
Red Hat Enterprise Linux v6 x86_64
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -316,7 +317,7 @@ from this guide.
|
||||
On Ubuntu 12.04, the Samba init scripts need to be modified to
|
||||
disable the upstart check. For more details, refer to:
|
||||
https://wiki.samba.org/index.php/Samba4/InitScript
|
||||
|
||||
////
|
||||
|
||||
Debian 8 (Jessie) and Ubuntu 14.04 (Trusty Tahr)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -395,7 +396,7 @@ samba-tool user setexpiry administrator --noexpiry
|
||||
----
|
||||
|
||||
You might consider changing the realm and domain used, to suit your
|
||||
enviroment.
|
||||
environment.
|
||||
|
||||
You might also have to
|
||||
remove `/etc/samba/smb.conf` prior running this command.
|
||||
@@ -441,7 +442,7 @@ Your Samba 4 configuration file should look like this:
|
||||
OpenChange Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
OpenChange 2.2 stores its metadata in MySQL so you need to have it installed.
|
||||
Since v2.2, OpenChange stores its metadata in MySQL so you need to have it installed.
|
||||
|
||||
First, create the OpenChange MySQL user:
|
||||
|
||||
@@ -512,9 +513,11 @@ mapistore:indexing_backend = mysql://openchange-user:openchange$123@localhost/op
|
||||
mapiproxy:openchangedb = mysql://openchange-user:openchange$123@localhost/openchange
|
||||
----
|
||||
|
||||
////
|
||||
On RHEL, make sure SELinux is disabled:
|
||||
|
||||
setenforce 0
|
||||
////
|
||||
|
||||
Next, you can start Samba using the usual command:
|
||||
|
||||
@@ -545,9 +548,11 @@ This service runs as a WSGI application under apache (mod_wsgi).
|
||||
While HTTPS is not required to access this service, it is strongly
|
||||
recommended.
|
||||
|
||||
////
|
||||
On RHEL-based distributions, the apache configuration required by these
|
||||
services can be found in `/etc/httpd/conf.d/ocsmanager.conf` and
|
||||
`/etc/httpd/conf.d/rpcproxy.conf`.
|
||||
////
|
||||
|
||||
For Debian-based distributions, these files can be found
|
||||
in `/etc/apache2/conf.d/` or `/etc/apache2/conf-available`.
|
||||
@@ -563,8 +568,10 @@ The OCS Manager and RPC Proxy configuration module can be enabled using:
|
||||
a2enconf ocsmanager
|
||||
a2enconf rpcproxy
|
||||
|
||||
////
|
||||
On RHEL-based distributions, make sure the `LoadModule` directive is
|
||||
uncommented in `/etc/httpd/conf.d/wsgi.conf`.
|
||||
////
|
||||
|
||||
The _reqtimeout_ apache module is known to cause problems when using the
|
||||
default configuration shipped with Debian-based systems. On such
|
||||
@@ -580,10 +587,12 @@ To avoid this problem, use a much higher timeout or disable the module:
|
||||
a2dismod reqtimeout
|
||||
|
||||
You should now restart the Apache service and make sure it will start on
|
||||
boot. On RHEL-based distributions, do:
|
||||
boot.
|
||||
////
|
||||
On RHEL-based distributions, do:
|
||||
|
||||
chkconfig httpd on && /etc/init.d/httpd restart
|
||||
|
||||
////
|
||||
On Debian-based distributions, do:
|
||||
|
||||
update-rc.d apache2 defaults && /etc/init.d/apache2 restart
|
||||
@@ -813,7 +822,7 @@ the `openchange_user_cleanup` script distributed with SOGo. The script
|
||||
can be found in `/usr/share/doc/sogo/` (`/usr/share/sogo-VERSION/` on
|
||||
RHEL).
|
||||
To reset a user, run the script as root:
|
||||
`python openchange_user_cleanup username`. See the usage output for additional options.
|
||||
`openchange_user_cleanup username`. See the usage output for additional options.
|
||||
* The "Out of Office Assistant" will not currently work. This feature
|
||||
has not been implemented.
|
||||
* Creating folders below INBOX (when not normally permitted by the IMAP
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- TODO have the build system take care of this -->
|
||||
<releaseinfo>Version 2.3.0 - June 2015</releaseinfo>
|
||||
<subtitle>for version 2.3.0</subtitle>
|
||||
<date>2015-06-01</date>
|
||||
<releaseinfo>Version 2.3.2 - September 2015</releaseinfo>
|
||||
<subtitle>for version 2.3.</subtitle>
|
||||
<date>2015-09-16</date>
|
||||
|
||||
<legalnotice>
|
||||
<para>Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".</para>
|
||||
|
||||
@@ -13,6 +13,6 @@
|
||||
|
||||
// TODO have the build system take care of this
|
||||
|
||||
:release_version: 2.3.0
|
||||
:release_version: 2.3.2
|
||||
|
||||
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:
|
||||
@@ -1,10 +1,41 @@
|
||||
2.3.1 (2015-06-XX)
|
||||
2.3.2 (2015-09-16)
|
||||
------------------
|
||||
|
||||
Enhancements
|
||||
- improved EAS speed and memory usage, avoiding many IMAP LIST commands (#3294)
|
||||
- improved EAS speed during initial syncing of large mailboxes (#3293)
|
||||
- updated CKEditor to version 4.5.3
|
||||
|
||||
Bug fixes
|
||||
- fixed display of whitelisted attendees in Preferences window on Firefox (#3285)
|
||||
- non-latin subfolder names are displayed correctly on Outlook (Zentyal)
|
||||
- fixed several sync issues on environments with multiple users (Zentyal)
|
||||
- folders from other users will no longer appear on your Outlook (Zentyal)
|
||||
- use right auth in multidomain environments in contacts and calendar from Outlook (Zentyal)
|
||||
- session fix when SOGoEnableDomainBasedUID is enabled but logins are domain-less
|
||||
- less sync issues when setting read flag (Zentyal)
|
||||
- attachments with non-latin filenames sent by Outlook are now received (Zentyal)
|
||||
- support attachments from more mail clients (Zentyal)
|
||||
- avoid conflicting message on saving a draft mail (Zentyal)
|
||||
- less conflicting messages in Outlook while moving messages between folders (Zentyal)
|
||||
- start/end shifting by 1 hour due to timezone change on last Sunday of October 2015 (#3344)
|
||||
- fixed localization of calendar categories with empty profile (#3295)
|
||||
- fixed options availability in contextual menu of Contacts module (#3342)
|
||||
|
||||
2.3.1 (2015-07-23)
|
||||
------------------
|
||||
|
||||
Enhancements
|
||||
- improved EAS speed, especially when fetching big attachments
|
||||
- now always enforce the organizer's default identity in appointments
|
||||
- improved the handling of default calendar categories/colors (#3200)
|
||||
- added support for DeletesAsMoves over EAS
|
||||
- added create-folder subcommand to sogo-tool to create contact and calendar folders
|
||||
- group mail addresses can be used as recipient in Outlook
|
||||
- added 'ActiveSync' module constraints
|
||||
- updated CKEditor to version 4.5.1
|
||||
- added Slovenian translation - thanks to Jens Riecken
|
||||
- added Chinese (Taiwan) translation
|
||||
|
||||
Bug fixes
|
||||
- EAS's GetItemEstimate/ItemOperations now support fetching mails and empty folders
|
||||
@@ -14,6 +45,14 @@ Bug fixes
|
||||
- properly support big characters in EAS and fix encoding QP EAS error for Outlook (#3082)
|
||||
- properly encode id of DOM elements in Address Book module (#3239, #3245)
|
||||
- fixed multi-domain support for sogo-tool backup/restore (#2600)
|
||||
- fixed data ordering in events list of Calendar module (#3261)
|
||||
- fixed data ordering in tasks list of Calendar module (#3267)
|
||||
- Android EAS Lollipop fixes (#3268 and #3269)
|
||||
- improved EAS email flagging handling (#3140)
|
||||
- fixed computation of GlobalObjectId (#3235)
|
||||
- fixed EAS conversation ID issues on BB10 (#3152)
|
||||
- fixed CR/LF printing in event's description (#3228)
|
||||
- optimized Calendar module in multidomain configurations
|
||||
|
||||
2.3.0 (2015-06-01)
|
||||
-------------------
|
||||
|
||||
@@ -33,8 +33,9 @@
|
||||
}
|
||||
|
||||
- (id) authenticatorInContext: (id) context;
|
||||
|
||||
- (MAPIStoreUserContext *) userContext;
|
||||
- (void) setUserContext: (MAPIStoreUserContext *) newContext;
|
||||
- (void) cleanup;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -76,6 +76,11 @@ MAPIApplication *MAPIApp = nil;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (MAPIStoreUserContext *) userContext
|
||||
{
|
||||
return userContext;
|
||||
}
|
||||
|
||||
- (void) setUserContext: (MAPIStoreUserContext *) newContext
|
||||
{
|
||||
/* user contexts must not be retained here ad their holder (mapistore)
|
||||
@@ -88,4 +93,9 @@ MAPIApplication *MAPIApp = nil;
|
||||
return [userContext authenticator];
|
||||
}
|
||||
|
||||
- (void) cleanup
|
||||
{
|
||||
[userContext deactivate];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -63,19 +63,15 @@
|
||||
SOGoAppointmentObject *newEntry;
|
||||
NSString *name;
|
||||
|
||||
//[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
|
||||
[[self userContext] activate];
|
||||
|
||||
name = [NSString stringWithFormat: @"%@.ics",
|
||||
[SOGoObject globallyUniqueObjectId]];
|
||||
newEntry = [SOGoAppointmentObject objectWithName: name
|
||||
inContainer: sogoObject];
|
||||
[newEntry setIsNew: YES];
|
||||
/* the WOContext is required here for resolving notification pages */
|
||||
[newEntry setContext: [[self userContext] woContext]];
|
||||
newMessage = [MAPIStoreCalendarMessage mapiStoreObjectWithSOGoObject: newEntry
|
||||
inContainer: self];
|
||||
|
||||
|
||||
return newMessage;
|
||||
}
|
||||
|
||||
|
||||
@@ -494,6 +494,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
|
||||
folder = [sogoObject container];
|
||||
|
||||
/* reinstantiate the old sogo object and attach it to self */
|
||||
[[self userContext] activate];
|
||||
woContext = [[self userContext] woContext];
|
||||
if (isNew)
|
||||
{
|
||||
@@ -577,7 +578,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) save: (TALLOC_CTX *) memCtx
|
||||
- (void) save: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
// iCalCalendar *vCalendar;
|
||||
// NSCalendarDate *now;
|
||||
@@ -634,7 +635,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
|
||||
withActiveUser: activeUser
|
||||
inMemCtx: memCtx];
|
||||
[self _updateAttachedEvents];
|
||||
[[self userContext] activateWithUser: activeUser];
|
||||
[[self userContext] activate];
|
||||
[sogoObject updateContentWithCalendar: calendar
|
||||
fromRequest: nil];
|
||||
[self updateVersions];
|
||||
@@ -670,7 +671,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
|
||||
return newAttachment;
|
||||
}
|
||||
|
||||
- (int) setReadFlag: (uint8_t) flag
|
||||
- (enum mapistore_error) setReadFlag: (uint8_t) flag
|
||||
{
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#import <Contacts/SOGoContactFolders.h>
|
||||
|
||||
#import "MAPIApplication.h"
|
||||
#import "MAPIStoreUserContext.h"
|
||||
#import "MAPIStoreContactsContext.h"
|
||||
#import "MAPIStoreContactsMessage.h"
|
||||
#import "MAPIStoreContactsMessageTable.h"
|
||||
@@ -58,10 +59,12 @@
|
||||
SOGoContactGCSEntry *newEntry;
|
||||
NSString *name;
|
||||
|
||||
[[self userContext] activate];
|
||||
|
||||
name = [NSString stringWithFormat: @"%@.vcf",
|
||||
[SOGoObject globallyUniqueObjectId]];
|
||||
newEntry = [SOGoContactGCSEntry objectWithName: name
|
||||
inContainer: sogoObject];
|
||||
inContainer: sogoObject];
|
||||
[newEntry setIsNew: YES];
|
||||
newMessage = [MAPIStoreContactsMessage mapiStoreObjectWithSOGoObject: newEntry
|
||||
inContainer: self];
|
||||
@@ -100,7 +103,7 @@
|
||||
rights |= RightsReadItems;
|
||||
if (rights != 0)
|
||||
rights |= RoleNone; /* actually "folder visible" */
|
||||
|
||||
|
||||
return rights;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#import <SOGo/SOGoUser.h>
|
||||
|
||||
#import "MAPIStoreAttachment.h"
|
||||
// #import "MAPIStoreAttachmentTable.h"
|
||||
#import "MAPIStoreFallbackContext.h"
|
||||
#import "MAPIStoreFolder.h"
|
||||
#import "MAPIStoreFolderTable.h"
|
||||
@@ -89,32 +88,31 @@ static NSMutableDictionary *contextClassMapping;
|
||||
currentClass = [classes objectAtIndex: count];
|
||||
moduleName = [currentClass MAPIModuleName];
|
||||
if (moduleName)
|
||||
{
|
||||
[contextClassMapping setObject: currentClass
|
||||
{
|
||||
[contextClassMapping setObject: currentClass
|
||||
forKey: moduleName];
|
||||
NSLog (@" registered class '%@' as handler of '%@' contexts",
|
||||
NSStringFromClass (currentClass), moduleName);
|
||||
}
|
||||
NSLog (@" registered class '%@' as handler of '%@' contexts",
|
||||
NSStringFromClass (currentClass), moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
MAPIStoreFallbackContextK = [MAPIStoreFallbackContext class];
|
||||
}
|
||||
|
||||
+ (struct mapistore_contexts_list *) listAllContextsForUser: (NSString *) userName
|
||||
withIndexing: (struct indexing_context *) indexing
|
||||
withIndexing: (struct indexing_context *) indexing
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
struct mapistore_contexts_list *list, *current;
|
||||
NSArray *classes;
|
||||
Class currentClass;
|
||||
NSUInteger count, max;
|
||||
MAPIStoreUserContext *userContext;
|
||||
|
||||
list = NULL;
|
||||
|
||||
userContext = [MAPIStoreUserContext userContextWithUsername: userName
|
||||
andTDBIndexing: indexing];
|
||||
[userContext activateWithUser: [userContext sogoUser]];
|
||||
// User context is activated on initialization
|
||||
[MAPIStoreUserContext userContextWithUsername: userName
|
||||
andTDBIndexing: indexing];
|
||||
|
||||
classes = GSObjCAllSubclassesOfClass (self);
|
||||
max = [classes count];
|
||||
@@ -122,7 +120,7 @@ static NSMutableDictionary *contextClassMapping;
|
||||
{
|
||||
currentClass = [classes objectAtIndex: count];
|
||||
current = [currentClass listContextsForUser: userName
|
||||
withIndexing: indexing
|
||||
withIndexing: indexing
|
||||
inMemCtx: memCtx];
|
||||
if (current)
|
||||
DLIST_CONCATENATE(list, current, void);
|
||||
@@ -132,7 +130,7 @@ static NSMutableDictionary *contextClassMapping;
|
||||
}
|
||||
|
||||
+ (struct mapistore_contexts_list *) listContextsForUser: (NSString *) userName
|
||||
withIndexing: (struct indexing_context *) indexing
|
||||
withIndexing: (struct indexing_context *) indexing
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
return NULL;
|
||||
@@ -225,8 +223,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
NSURL *baseURL;
|
||||
int rc = MAPISTORE_ERR_NOT_FOUND;
|
||||
|
||||
//NSLog (@"METHOD '%s' (%d) -- uri: '%s'", __FUNCTION__, __LINE__, newUri);
|
||||
|
||||
context = nil;
|
||||
|
||||
baseURL = CompleteURLFromMapistoreURI (newUri);
|
||||
@@ -298,13 +294,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
ASSIGN (userContext,
|
||||
[MAPIStoreUserContext userContextWithUsername: username
|
||||
andTDBIndexing: indexing]);
|
||||
|
||||
#if 0
|
||||
mapistore_mgmt_backend_register_user (newConnInfo,
|
||||
"SOGo",
|
||||
[username UTF8String]);
|
||||
#endif
|
||||
|
||||
connInfo = newConnInfo;
|
||||
username = [NSString stringWithUTF8String: newConnInfo->username];
|
||||
ASSIGN (activeUser, [SOGoUser userWithLogin: username]);
|
||||
@@ -322,12 +311,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
#if 0
|
||||
mapistore_mgmt_backend_unregister_user ([self connectionInfo], "SOGo",
|
||||
[[userContext username]
|
||||
UTF8String]);
|
||||
#endif
|
||||
|
||||
[contextUrl release];
|
||||
[userContext release];
|
||||
[containersBag release];
|
||||
@@ -355,27 +338,16 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
return activeUser;
|
||||
}
|
||||
|
||||
// - (void) logRestriction: (struct mapi_SRestriction *) res
|
||||
// withState: (MAPIRestrictionState) state
|
||||
// {
|
||||
// NSString *resStr;
|
||||
|
||||
// resStr = MAPIStringForRestriction (res);
|
||||
|
||||
// [self logWithFormat: @"%@ --> %@", resStr, MAPIStringForRestrictionState (state)];
|
||||
// }
|
||||
|
||||
- (int) getPath: (char **) path
|
||||
ofFMID: (uint64_t) fmid
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
int rc;
|
||||
NSString *objectURL, *url;
|
||||
// TDB_DATA key, dbuf;
|
||||
|
||||
url = [contextUrl absoluteString];
|
||||
// FIXME transform percent escapes but not for user part of the url
|
||||
//stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
|
||||
//[xxxx stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
|
||||
objectURL = [[userContext mapping] urlFromID: fmid];
|
||||
if (objectURL)
|
||||
{
|
||||
@@ -396,14 +368,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"%s: you should *never* get here", __PRETTY_FUNCTION__];
|
||||
// /* attempt to populate our mapping dict with data from indexing.tdb */
|
||||
// key.dptr = (unsigned char *) talloc_asprintf (memCtx, "0x%.16llx",
|
||||
// (long long unsigned int )fmid);
|
||||
// key.dsize = strlen ((const char *) key.dptr);
|
||||
|
||||
// dbuf = tdb_fetch (memCtx->indexing_list->index_ctx->tdb, key);
|
||||
// talloc_free (key.dptr);
|
||||
// uri = talloc_strndup (memCtx, (const char *)dbuf.dptr, dbuf.dsize);
|
||||
*path = NULL;
|
||||
rc = MAPISTORE_SUCCESS;
|
||||
}
|
||||
@@ -426,7 +390,7 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
NSArray *pathComponents;
|
||||
NSUInteger count, max;
|
||||
|
||||
[userContext activateWithUser: activeUser];
|
||||
[userContext activate];
|
||||
woContext = [userContext woContext];
|
||||
|
||||
[self ensureContextFolder];
|
||||
@@ -488,7 +452,7 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
/* utils */
|
||||
|
||||
- (NSString *) extractChildNameFromURL: (NSString *) objectURL
|
||||
andFolderURLAt: (NSString **) folderURL;
|
||||
andFolderURLAt: (NSString **) folderURL;
|
||||
{
|
||||
NSString *childKey;
|
||||
NSRange lastSlash;
|
||||
@@ -497,15 +461,15 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
if ([objectURL hasSuffix: @"/"])
|
||||
objectURL = [objectURL substringToIndex: [objectURL length] - 2];
|
||||
lastSlash = [objectURL rangeOfString: @"/"
|
||||
options: NSBackwardsSearch];
|
||||
options: NSBackwardsSearch];
|
||||
if (lastSlash.location != NSNotFound)
|
||||
{
|
||||
slashPtr = NSMaxRange (lastSlash);
|
||||
childKey = [objectURL substringFromIndex: slashPtr];
|
||||
if ([childKey length] == 0)
|
||||
childKey = nil;
|
||||
childKey = nil;
|
||||
if (folderURL)
|
||||
*folderURL = [objectURL substringToIndex: slashPtr];
|
||||
*folderURL = [objectURL substringToIndex: slashPtr];
|
||||
}
|
||||
else
|
||||
childKey = nil;
|
||||
@@ -516,11 +480,10 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
- (uint64_t) idForObjectWithKey: (NSString *) key
|
||||
inFolderURL: (NSString *) folderURL
|
||||
{
|
||||
NSString *childURL, *owner;
|
||||
NSString *childURL;
|
||||
MAPIStoreMapping *mapping;
|
||||
uint64_t mappingId;
|
||||
uint32_t contextId;
|
||||
void *rootObject;
|
||||
enum mapistore_error ret;
|
||||
|
||||
if (key)
|
||||
childURL = [NSString stringWithFormat: @"%@%@", folderURL,
|
||||
@@ -531,17 +494,13 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
mappingId = [mapping idFromURL: childURL];
|
||||
if (mappingId == NSNotFound)
|
||||
{
|
||||
//[self warnWithFormat: @"no id exist yet for '%@', requesting one...",
|
||||
// childURL];
|
||||
mapistore_indexing_get_new_folderID (connInfo->mstore_ctx, &mappingId);
|
||||
[mapping registerURL: childURL withID: mappingId];
|
||||
contextId = 0;
|
||||
|
||||
mapistore_search_context_by_uri (connInfo->mstore_ctx, [folderURL UTF8String],
|
||||
&contextId, &rootObject);
|
||||
owner = [userContext username];
|
||||
mapistore_indexing_record_add_mid (connInfo->mstore_ctx, contextId,
|
||||
[owner UTF8String], mappingId);
|
||||
[self logWithFormat: @"No id exist yet for '%@', requesting one", childURL];
|
||||
ret = mapistore_indexing_get_new_folderID (connInfo->mstore_ctx, &mappingId);
|
||||
if (ret == MAPISTORE_SUCCESS)
|
||||
[mapping registerURL: childURL withID: mappingId];
|
||||
else
|
||||
[self errorWithFormat: @"Error trying to get new folder id (%d): %s",
|
||||
ret, mapistore_errstr (ret)];
|
||||
}
|
||||
|
||||
return mappingId;
|
||||
@@ -595,15 +554,14 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
|
||||
|
||||
memCtx = talloc_zero(NULL, TALLOC_CTX);
|
||||
newFMIDs = [NSMutableArray arrayWithCapacity: max];
|
||||
|
||||
|
||||
if (mapistore_indexing_get_new_folderIDs (connInfo->mstore_ctx,
|
||||
memCtx, max, &numbers)
|
||||
!= MAPISTORE_SUCCESS || numbers->cValues != max)
|
||||
abort ();
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
newNumber
|
||||
= [NSString stringWithUnsignedLongLong: numbers->lpui8[count]];
|
||||
newNumber = [NSString stringWithUnsignedLongLong: numbers->lpui8[count]];
|
||||
[newFMIDs addObject: newNumber];
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
else
|
||||
[dbFolder changePathTo: [NSString stringWithFormat: @"/fallback/%@", pathComponent]
|
||||
intoNewContainer: nil];
|
||||
|
||||
|
||||
mapping = [self mapping];
|
||||
|
||||
if (targetFolder)
|
||||
@@ -193,6 +193,8 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
SOGoMAPIDBMessage *fsObject;
|
||||
NSString *newKey;
|
||||
|
||||
[[self userContext] activate];
|
||||
|
||||
newKey = [NSString stringWithFormat: @"%@.plist",
|
||||
[SOGoObject globallyUniqueObjectId]];
|
||||
fsObject = [SOGoMAPIDBMessage objectWithName: newKey
|
||||
@@ -214,10 +216,13 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
ownerUser = [[self userContext] sogoUser];
|
||||
if ([[context activeUser] isEqual: ownerUser]
|
||||
|| [self subscriberCanReadMessages])
|
||||
keys = [(SOGoCacheGCSFolder *) sogoObject childKeysOfType: MAPIMessageCacheObject
|
||||
includeDeleted: NO
|
||||
matchingQualifier: qualifier
|
||||
andSortOrderings: sortOrderings];
|
||||
{
|
||||
[[self userContext] activate];
|
||||
keys = [(SOGoCacheGCSFolder *) sogoObject childKeysOfType: MAPIMessageCacheObject
|
||||
includeDeleted: NO
|
||||
matchingQualifier: qualifier
|
||||
andSortOrderings: sortOrderings];
|
||||
}
|
||||
else
|
||||
keys = [NSArray array];
|
||||
|
||||
@@ -227,6 +232,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
- (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier
|
||||
andSortOrderings: (NSArray *) sortOrderings
|
||||
{
|
||||
[[self userContext] activate];
|
||||
return [dbFolder childKeysOfType: MAPIFolderCacheObject
|
||||
includeDeleted: NO
|
||||
matchingQualifier: qualifier
|
||||
@@ -262,7 +268,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
if ([date laterDate: fileDate] == fileDate)
|
||||
{
|
||||
//[self logWithFormat: @"current date: %@", date];
|
||||
|
||||
|
||||
date = fileDate;
|
||||
}
|
||||
}
|
||||
@@ -326,7 +332,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
rights |= RightsFolderContact;
|
||||
if (rights != 0)
|
||||
rights |= RoleNone; /* actually "folder visible" */
|
||||
|
||||
|
||||
return rights;
|
||||
}
|
||||
|
||||
@@ -361,7 +367,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
subscribed to read an open contained messages in order to enable them to
|
||||
find the "LocalFreebusy" message */
|
||||
[sogoObject reloadIfNeeded];
|
||||
|
||||
|
||||
displayName = [[sogoObject properties]
|
||||
objectForKey: MAPIPropertyKey (PidTagDisplayName)];
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSData.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
@@ -34,6 +35,7 @@
|
||||
#import "MAPIStoreDBFolder.h"
|
||||
#import "MAPIStoreDBMessage.h"
|
||||
#import "MAPIStoreTypes.h"
|
||||
#import "NSData+MAPIStore.h"
|
||||
#import "NSObject+MAPIStore.h"
|
||||
#import "NSString+MAPIStore.h"
|
||||
|
||||
@@ -104,6 +106,105 @@
|
||||
return objectVersion;
|
||||
}
|
||||
|
||||
- (void) _updatePredecessorChangeList
|
||||
{
|
||||
BOOL updated;
|
||||
enum mapistore_error rc;
|
||||
NSData *currentChangeList, *changeKey;
|
||||
NSMutableArray *changeKeys;
|
||||
NSMutableData *newChangeList;
|
||||
NSUInteger count, len;
|
||||
struct SizedXid *changes;
|
||||
struct SPropValue property;
|
||||
struct SRow aRow;
|
||||
struct XID *currentChangeKey;
|
||||
TALLOC_CTX *localMemCtx;
|
||||
uint32_t nChanges;
|
||||
|
||||
localMemCtx = talloc_new (NULL);
|
||||
if (!localMemCtx)
|
||||
{
|
||||
[self errorWithFormat: @"No more memory"];
|
||||
return;
|
||||
}
|
||||
|
||||
changeKey = [self getReplicaKeyFromGlobCnt: [self objectVersion]];
|
||||
|
||||
currentChangeList = [properties objectForKey: MAPIPropertyKey (PidTagPredecessorChangeList)];
|
||||
if (!currentChangeList)
|
||||
{
|
||||
/* Create a new PredecessorChangeList */
|
||||
len = [changeKey length];
|
||||
newChangeList = [NSMutableData dataWithCapacity: len + 1];
|
||||
[newChangeList appendUInt8: len];
|
||||
[newChangeList appendData: changeKey];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Update current predecessor change list with new change key */
|
||||
changes = [currentChangeList asSizedXidArrayInMemCtx: localMemCtx
|
||||
with: &nChanges];
|
||||
|
||||
updated = NO;
|
||||
currentChangeKey = [changeKey asXIDInMemCtx: localMemCtx];
|
||||
for (count = 0; count < nChanges && !updated; count++)
|
||||
{
|
||||
if (GUID_equal(&changes[count].XID.NameSpaceGuid, ¤tChangeKey->NameSpaceGuid))
|
||||
{
|
||||
NSData *globCnt, *oldGlobCnt;
|
||||
oldGlobCnt = [NSData dataWithBytes: changes[count].XID.LocalId.data length: changes[count].XID.LocalId.length];
|
||||
globCnt = [NSData dataWithBytes: currentChangeKey->LocalId.data length: currentChangeKey->LocalId.length];
|
||||
if ([globCnt compare: oldGlobCnt] == NSOrderedDescending)
|
||||
{
|
||||
if ([globCnt length] != [oldGlobCnt length])
|
||||
{
|
||||
[self errorWithFormat: @"Cannot compare globcnt with different length: %@ and %@", globCnt, oldGlobCnt];
|
||||
abort();
|
||||
}
|
||||
memcpy (changes[count].XID.LocalId.data, currentChangeKey->LocalId.data, currentChangeKey->LocalId.length);
|
||||
updated = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Serialise it */
|
||||
changeKeys = [NSMutableArray array];
|
||||
|
||||
if (!updated)
|
||||
[changeKeys addObject: changeKey];
|
||||
|
||||
for (count = 0; count < nChanges; count++)
|
||||
{
|
||||
changeKey = [NSData dataWithXID: &changes[count].XID];
|
||||
[changeKeys addObject: changeKey];
|
||||
}
|
||||
|
||||
[changeKeys sortUsingFunction: MAPIChangeKeyGUIDCompare context: localMemCtx];
|
||||
|
||||
newChangeList = [NSMutableData data];
|
||||
len = [changeKeys count];
|
||||
for (count = 0; count < len; count++)
|
||||
{
|
||||
changeKey = [changeKeys objectAtIndex: count];
|
||||
[newChangeList appendUInt8: [changeKey length]];
|
||||
[newChangeList appendData: changeKey];
|
||||
}
|
||||
}
|
||||
|
||||
if ([newChangeList length] > 0)
|
||||
{
|
||||
property.ulPropTag = PidTagPredecessorChangeList;
|
||||
property.value.bin = *[newChangeList asBinaryInMemCtx: localMemCtx];
|
||||
aRow.cValues = 1;
|
||||
aRow.lpProps = &property;
|
||||
rc = [self addPropertiesFromRow: &aRow];
|
||||
if (rc != MAPISTORE_SUCCESS)
|
||||
[self errorWithFormat: @"Impossible to add a new predecessor change list: %d", rc];
|
||||
}
|
||||
|
||||
talloc_free (localMemCtx);
|
||||
}
|
||||
|
||||
//
|
||||
// FIXME: how this can happen?
|
||||
//
|
||||
@@ -166,6 +267,9 @@
|
||||
[properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion]
|
||||
forKey: @"version"];
|
||||
|
||||
/* Update PredecessorChangeList accordingly */
|
||||
[self _updatePredecessorChangeList];
|
||||
|
||||
[self logWithFormat: @"%d props in dict", [properties count]];
|
||||
|
||||
[sogoObject save];
|
||||
@@ -209,4 +313,36 @@
|
||||
return [sogoObject lastModified];
|
||||
}
|
||||
|
||||
- (enum mapistore_error) setReadFlag: (uint8_t) flag
|
||||
{
|
||||
/* Modify PidTagMessageFlags from SetMessageReadFlag and
|
||||
SyncImportReadStateChanges ROPs */
|
||||
NSNumber *flags;
|
||||
uint32_t newFlag;
|
||||
|
||||
flags = [properties objectForKey: MAPIPropertyKey (PR_MESSAGE_FLAGS)];
|
||||
if (flags)
|
||||
{
|
||||
newFlag = [flags unsignedLongValue];
|
||||
if (flag & SUPPRESS_RECEIPT)
|
||||
newFlag |= MSGFLAG_READ;
|
||||
if (flag & CLEAR_RN_PENDING)
|
||||
newFlag &= ~MSGFLAG_RN_PENDING;
|
||||
if (flag & CLEAR_READ_FLAG)
|
||||
newFlag &= ~MSGFLAG_READ;
|
||||
if (flag & CLEAR_NRN_PENDING)
|
||||
newFlag &= ~MSGFLAG_NRN_PENDING;
|
||||
}
|
||||
else
|
||||
{
|
||||
newFlag = MSGFLAG_READ;
|
||||
if (flag & CLEAR_READ_FLAG)
|
||||
newFlag = 0x0;
|
||||
}
|
||||
[properties setObject: [NSNumber numberWithUnsignedLong: newFlag]
|
||||
forKey: MAPIPropertyKey (PR_MESSAGE_FLAGS)];
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -121,6 +121,7 @@
|
||||
fromFolder: (MAPIStoreFolder *) sourceFolder
|
||||
withMIDs: (uint64_t *) targetMids
|
||||
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
||||
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
|
||||
wantCopy: (uint8_t) want_copy
|
||||
inMemCtx: (TALLOC_CTX *) memCtx;
|
||||
|
||||
|
||||
@@ -120,6 +120,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
folderName = [folderURL host];
|
||||
|
||||
userContext = [self userContext];
|
||||
[userContext activate];
|
||||
[userContext ensureFolderTableExists];
|
||||
|
||||
ASSIGN (dbFolder,
|
||||
@@ -231,30 +232,19 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
- (id) lookupFolder: (NSString *) folderKey
|
||||
{
|
||||
MAPIStoreFolder *childFolder;
|
||||
MAPIStoreFolder *childFolder = nil;
|
||||
SOGoFolder *sogoFolder;
|
||||
WOContext *woContext;
|
||||
|
||||
childFolder = nil;
|
||||
if ([[self folderKeys] containsObject: folderKey])
|
||||
{
|
||||
woContext = [[self userContext] woContext];
|
||||
/* We activate the user for the context using the root folder
|
||||
context as there are times where the active user is not
|
||||
matching with the one stored in the application context
|
||||
and SOGo object is storing cached data with the wrong user */
|
||||
[[self userContext] activateWithUser: [woContext activeUser]];
|
||||
sogoFolder = [sogoObject lookupName: folderKey inContext: woContext
|
||||
[[self userContext] activate];
|
||||
sogoFolder = [sogoObject lookupName: folderKey
|
||||
inContext: nil
|
||||
acquire: NO];
|
||||
if (sogoFolder && ![sogoFolder isKindOfClass: NSExceptionK])
|
||||
{
|
||||
[sogoFolder setContext: woContext];
|
||||
childFolder = [isa mapiStoreObjectWithSOGoObject: sogoFolder
|
||||
inContainer: self];
|
||||
}
|
||||
childFolder = [isa mapiStoreObjectWithSOGoObject: sogoFolder
|
||||
inContainer: self];
|
||||
}
|
||||
else
|
||||
childFolder = nil;
|
||||
|
||||
return childFolder;
|
||||
}
|
||||
@@ -285,6 +275,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
if (messageKey)
|
||||
{
|
||||
[[self userContext] activate];
|
||||
msgObject = [sogoObject lookupName: messageKey
|
||||
inContext: nil
|
||||
acquire: NO];
|
||||
@@ -314,6 +305,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
if (messageKey)
|
||||
{
|
||||
[[self userContext] activate];
|
||||
if ([[self faiMessageKeys] containsObject: messageKey])
|
||||
{
|
||||
msgObject = [dbFolder lookupName: messageKey
|
||||
@@ -546,6 +538,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
context = [self context];
|
||||
ownerUser = [[self userContext] sogoUser];
|
||||
[[self userContext] activate];
|
||||
|
||||
if ([[context activeUser] isEqual: ownerUser]
|
||||
|| (!isAssociated && [self subscriberCanCreateMessages]))
|
||||
@@ -649,6 +642,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
fromFolder: (MAPIStoreFolder *) sourceFolder
|
||||
withMID: (uint64_t) targetMid
|
||||
andChangeKey: (struct Binary_r *) targetChangeKey
|
||||
andPredecessorChangeList: (struct Binary_r *) targetPredecessorChangeList
|
||||
wantCopy: (uint8_t) wantCopy
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
@@ -676,15 +670,18 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
[sourceMsg copyToMessage: destMsg inMemCtx: memCtx];
|
||||
|
||||
if (targetChangeKey)
|
||||
if (targetPredecessorChangeList)
|
||||
{
|
||||
property.ulPropTag = PidTagChangeKey;
|
||||
property.value.bin = *targetChangeKey;
|
||||
property.ulPropTag = PidTagPredecessorChangeList;
|
||||
property.value.bin = *targetPredecessorChangeList;
|
||||
aRow.cValues = 1;
|
||||
aRow.lpProps = &property;
|
||||
rc = [destMsg addPropertiesFromRow: &aRow];
|
||||
if (rc != MAPISTORE_SUCCESS)
|
||||
goto end;
|
||||
{
|
||||
[self errorWithFormat: @"Cannot add PredecessorChangeList on move"];
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
[destMsg save: memCtx];
|
||||
if (!wantCopy)
|
||||
@@ -703,6 +700,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
fromFolder: (MAPIStoreFolder *) sourceFolder
|
||||
withMIDs: (uint64_t *) targetMids
|
||||
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
||||
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
|
||||
wantCopy: (uint8_t) wantCopy
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
@@ -712,7 +710,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
NSString *oldMessageURL;
|
||||
MAPIStoreMapping *mapping;
|
||||
SOGoUser *ownerUser;
|
||||
struct Binary_r *targetChangeKey;
|
||||
struct Binary_r *targetChangeKey, *targetPredecessorChangeList;
|
||||
//TALLOC_CTX *memCtx;
|
||||
|
||||
//memCtx = talloc_zero (NULL, TALLOC_CTX);
|
||||
@@ -733,14 +731,21 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
if (oldMessageURL)
|
||||
{
|
||||
[oldMessageURLs addObject: oldMessageURL];
|
||||
if (targetChangeKeys)
|
||||
targetChangeKey = targetChangeKeys[count];
|
||||
if (targetChangeKeys && targetPredecessorChangeList)
|
||||
{
|
||||
targetChangeKey = targetChangeKeys[count];
|
||||
targetPredecessorChangeList = targetPredecessorChangeLists[count];
|
||||
}
|
||||
else
|
||||
targetChangeKey = NULL;
|
||||
{
|
||||
targetChangeKey = NULL;
|
||||
targetPredecessorChangeList = NULL;
|
||||
}
|
||||
rc = [self _moveCopyMessageWithMID: srcMids[count]
|
||||
fromFolder: sourceFolder
|
||||
withMID: targetMids[count]
|
||||
andChangeKey: targetChangeKey
|
||||
andPredecessorChangeList: targetPredecessorChangeList
|
||||
wantCopy: wantCopy
|
||||
inMemCtx: memCtx];
|
||||
}
|
||||
@@ -758,9 +763,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
}
|
||||
else
|
||||
rc = MAPISTORE_ERR_DENIED;
|
||||
|
||||
|
||||
//talloc_free (memCtx);
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -931,7 +936,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
NSArray *newIDs;
|
||||
uint64_t idNbr;
|
||||
bool softDeleted;
|
||||
|
||||
|
||||
baseURL = [self url];
|
||||
|
||||
mapping = [self mapping];
|
||||
@@ -1060,9 +1065,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
{
|
||||
static enum MAPITAGS bannedProps[] = { PR_MID, PR_FID, PR_PARENT_FID,
|
||||
PR_SOURCE_KEY, PR_PARENT_SOURCE_KEY,
|
||||
PR_CHANGE_KEY, 0x00000000 };
|
||||
PR_CHANGE_KEY, PidTagChangeNumber, 0x00000000 };
|
||||
enum MAPITAGS *currentProp;
|
||||
NSMutableDictionary *propsCopy;
|
||||
uint64_t cn;
|
||||
|
||||
/* TODO: this should no longer be required once mapistore v2 API is in
|
||||
place, when we can then do this from -dealloc below */
|
||||
@@ -1080,6 +1086,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
}
|
||||
|
||||
[properties addEntriesFromDictionary: propsCopy];
|
||||
|
||||
/* Update change number after setting the properties */
|
||||
cn = [[self context] getNewChangeNumber];
|
||||
[properties setObject: [NSNumber numberWithUnsignedLongLong: cn]
|
||||
forKey: MAPIPropertyKey (PidTagChangeNumber)];
|
||||
|
||||
[dbFolder save];
|
||||
}
|
||||
|
||||
@@ -1105,6 +1117,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
- (NSArray *) faiMessageKeysMatchingQualifier: (EOQualifier *) qualifier
|
||||
andSortOrderings: (NSArray *) sortOrderings
|
||||
{
|
||||
[[self userContext] activate];
|
||||
return [dbFolder childKeysOfType: MAPIFAICacheObject
|
||||
includeDeleted: NO
|
||||
matchingQualifier: qualifier
|
||||
@@ -1213,7 +1226,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
/*
|
||||
Possible values are:
|
||||
|
||||
|
||||
0x00000001 Modify
|
||||
0x00000002 Read
|
||||
0x00000004 Delete
|
||||
@@ -1244,7 +1257,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
access |= 0x10;
|
||||
if (userIsOwner)
|
||||
access |= 0x20;
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, access);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -1273,7 +1286,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
rights |= RightsCreateSubfolders;
|
||||
if (userIsOwner)
|
||||
rights |= RightsFolderOwner | RightsFolderContact;
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, rights);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -1309,7 +1322,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
*data = MAPIBoolValue (memCtx, [self supportsSubFolders] && [[self folderKeys] count] > 0);
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1317,7 +1330,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
*data = MAPILongValue (memCtx, [[self folderKeys] count]);
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1419,7 +1432,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
[dbObject setIsNew: YES];
|
||||
newMessage = [MAPIStoreFAIMessageK mapiStoreObjectWithSOGoObject: dbObject
|
||||
inContainer: self];
|
||||
|
||||
|
||||
return newMessage;
|
||||
}
|
||||
|
||||
@@ -1428,6 +1441,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
MAPIStoreMessage *newMessage;
|
||||
WOContext *woContext;
|
||||
|
||||
[[self userContext] activate];
|
||||
|
||||
if (isAssociated)
|
||||
newMessage = [self _createAssociatedMessage];
|
||||
else
|
||||
@@ -1627,7 +1642,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
permissionUser = nil;
|
||||
permissionRoles = nil;
|
||||
|
||||
|
||||
if (currentPermission->PermissionDataFlags == ROW_ADD)
|
||||
isAdd = YES;
|
||||
else if (currentPermission->PermissionDataFlags == ROW_MODIFY)
|
||||
@@ -1778,7 +1793,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
|
||||
return nil;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum
|
||||
|
||||
@@ -121,7 +121,6 @@
|
||||
|
||||
userContext = [MAPIStoreUserContext userContextWithUsername: userName
|
||||
andTDBIndexing: NULL];
|
||||
[MAPIApp setUserContext: userContext];
|
||||
moduleName = [self MAPIModuleName];
|
||||
parentFolder = [[userContext rootFolders] objectForKey: moduleName];
|
||||
nameInContainer = nil;
|
||||
@@ -134,7 +133,6 @@
|
||||
moduleName, nameInContainer];
|
||||
else
|
||||
mapistoreURI = nil;
|
||||
[MAPIApp setUserContext: nil];
|
||||
|
||||
return mapistoreURI;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@
|
||||
/* synchronisation */
|
||||
- (BOOL) synchroniseCache;
|
||||
- (void) updateVersionsForMessageWithKey: (NSString *) messageKey
|
||||
withChangeKey: (NSData *) newChangeKey;
|
||||
withChangeKey: (NSData *) oldChangeKey
|
||||
andPredecessorChangeList: (NSData *) pcl;
|
||||
- (NSNumber *) lastModifiedFromMessageChangeNumber: (NSString *) changeNumber;
|
||||
- (NSString *) changeNumberForMessageWithKey: (NSString *) messageKey;
|
||||
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey;
|
||||
|
||||
@@ -75,6 +75,7 @@ static Class NSNumberK;
|
||||
[SOGoMAPIDBMessage objectWithName: @"versions.plist"
|
||||
inContainer: dbFolder]);
|
||||
[versionsMessage setObjectType: MAPIInternalCacheObject];
|
||||
[versionsMessage reloadIfNeeded];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
@@ -261,7 +262,6 @@ static Class NSNumberK;
|
||||
*/
|
||||
- (void) _setChangeKey: (NSData *) changeKey
|
||||
forMessageEntry: (NSMutableDictionary *) messageEntry
|
||||
inChangeListOnly: (BOOL) inChangeListOnly
|
||||
{
|
||||
struct XID *xid;
|
||||
NSString *guid;
|
||||
@@ -270,19 +270,15 @@ static Class NSNumberK;
|
||||
NSMutableDictionary *changeList;
|
||||
|
||||
xid = [changeKey asXIDInMemCtx: NULL];
|
||||
guid = [NSString stringWithGUID: &xid->GUID];
|
||||
globCnt = [NSData dataWithBytes: xid->Data length: xid->Size];
|
||||
guid = [NSString stringWithGUID: &xid->NameSpaceGuid];
|
||||
globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length];
|
||||
talloc_free (xid);
|
||||
|
||||
if (!inChangeListOnly)
|
||||
{
|
||||
/* 1. set change key association */
|
||||
changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
guid, @"GUID",
|
||||
globCnt, @"LocalId",
|
||||
nil];
|
||||
[messageEntry setObject: changeKeyDict forKey: @"ChangeKey"];
|
||||
}
|
||||
/* 1. set change key association */
|
||||
changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys: guid, @"GUID",
|
||||
globCnt, @"LocalId",
|
||||
nil];
|
||||
[messageEntry setObject: changeKeyDict forKey: @"ChangeKey"];
|
||||
|
||||
/* 2. append/update predecessor change list */
|
||||
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
|
||||
@@ -296,6 +292,77 @@ static Class NSNumberK;
|
||||
[changeList setObject: globCnt forKey: guid];
|
||||
}
|
||||
|
||||
- (void) _updatePredecessorChangeList: (NSData *) predecessorChangeList
|
||||
forMessageEntry: (NSMutableDictionary *) messageEntry
|
||||
withOldChangeKey: (NSData *) oldChangeKey
|
||||
{
|
||||
NSData *globCnt, *oldGlobCnt;
|
||||
NSDictionary *changeKeyDict;
|
||||
NSString *guid;
|
||||
NSMutableDictionary *changeList;
|
||||
struct SizedXid *sizedXIDList;
|
||||
struct XID xid, *givenChangeKey;
|
||||
TALLOC_CTX *localMemCtx;
|
||||
uint32_t i, length;
|
||||
|
||||
localMemCtx = talloc_new (NULL);
|
||||
if (!localMemCtx)
|
||||
{
|
||||
[self errorWithFormat: @"No more memory"];
|
||||
return;
|
||||
}
|
||||
|
||||
if (predecessorChangeList)
|
||||
{
|
||||
sizedXIDList = [predecessorChangeList asSizedXidArrayInMemCtx: localMemCtx with: &length];
|
||||
|
||||
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
|
||||
if (!changeList)
|
||||
{
|
||||
changeList = [NSMutableDictionary new];
|
||||
[messageEntry setObject: changeList
|
||||
forKey: @"PredecessorChangeList"];
|
||||
[changeList release];
|
||||
}
|
||||
|
||||
if (sizedXIDList) {
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
xid = sizedXIDList[i].XID;
|
||||
guid = [NSString stringWithGUID: &xid.NameSpaceGuid];
|
||||
globCnt = [NSData dataWithBytes: xid.LocalId.data length: xid.LocalId.length];
|
||||
oldGlobCnt = [changeList objectForKey: guid];
|
||||
if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending))
|
||||
[changeList setObject: globCnt forKey: guid];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oldChangeKey)
|
||||
{
|
||||
givenChangeKey = [oldChangeKey asXIDInMemCtx: localMemCtx];
|
||||
if (givenChangeKey) {
|
||||
guid = [NSString stringWithGUID: &givenChangeKey->NameSpaceGuid];
|
||||
globCnt = [NSData dataWithBytes: givenChangeKey->LocalId.data length: givenChangeKey->LocalId.length];
|
||||
|
||||
changeKeyDict = [messageEntry objectForKey: @"ChangeKey"];
|
||||
if (!changeKeyDict ||
|
||||
([guid isEqualToString: [changeKeyDict objectForKey: @"GUID"]]
|
||||
&& ([globCnt compare: [changeKeyDict objectForKey: @"LocalId"]] == NSOrderedDescending)))
|
||||
{
|
||||
/* The given change key is greater than current one stored in
|
||||
metadata or it does not exist */
|
||||
[messageEntry setObject: [NSDictionary dictionaryWithObjectsAndKeys: guid, @"GUID",
|
||||
globCnt, @"LocalId",
|
||||
nil]
|
||||
forKey: @"ChangeKey"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
talloc_free (localMemCtx);
|
||||
}
|
||||
|
||||
- (EOQualifier *) componentQualifier
|
||||
{
|
||||
if (!componentQualifier)
|
||||
@@ -465,8 +532,7 @@ static Class NSNumberK;
|
||||
// A GLOBCNT structure is a 6-byte global namespace counter,
|
||||
// we strip the first 2 bytes. The first two bytes is the ReplicaId
|
||||
changeKey = [self getReplicaKeyFromGlobCnt: newChangeNum >> 16];
|
||||
[self _setChangeKey: changeKey forMessageEntry: messageEntry
|
||||
inChangeListOnly: NO];
|
||||
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
|
||||
}
|
||||
|
||||
now = [NSCalendarDate date];
|
||||
@@ -483,12 +549,13 @@ static Class NSNumberK;
|
||||
}
|
||||
|
||||
- (void) updateVersionsForMessageWithKey: (NSString *) messageKey
|
||||
withChangeKey: (NSData *) newChangeKey
|
||||
withChangeKey: (NSData *) oldChangeKey
|
||||
andPredecessorChangeList: (NSData *) pcl
|
||||
{
|
||||
NSMutableDictionary *messages, *messageEntry;
|
||||
|
||||
[self synchroniseCache];
|
||||
if (newChangeKey)
|
||||
if (oldChangeKey || pcl)
|
||||
{
|
||||
messages = [[versionsMessage properties] objectForKey: @"Messages"];
|
||||
messageEntry = [messages objectForKey: messageKey];
|
||||
@@ -496,8 +563,8 @@ static Class NSNumberK;
|
||||
[NSException raise: @"MAPIStoreIOException"
|
||||
format: @"no version record found for message '%@'",
|
||||
messageKey];
|
||||
[self _setChangeKey: newChangeKey forMessageEntry: messageEntry
|
||||
inChangeListOnly: YES];
|
||||
[self _updatePredecessorChangeList: pcl forMessageEntry: messageEntry
|
||||
withOldChangeKey: oldChangeKey];
|
||||
[versionsMessage save];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,13 +209,16 @@
|
||||
|
||||
- (void) updateVersions
|
||||
{
|
||||
NSData *newChangeKey;
|
||||
/* Update ChangeKey and PredecessorChangeList on message's save */
|
||||
NSData *newChangeKey, *predecessorChangeList;
|
||||
|
||||
newChangeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)];
|
||||
predecessorChangeList = [properties objectForKey: MAPIPropertyKey (PR_PREDECESSOR_CHANGE_LIST)];
|
||||
|
||||
[(MAPIStoreGCSFolder *) container
|
||||
updateVersionsForMessageWithKey: [self nameInContainer]
|
||||
withChangeKey: newChangeKey];
|
||||
updateVersionsForMessageWithKey: [self nameInContainer]
|
||||
withChangeKey: newChangeKey
|
||||
andPredecessorChangeList: predecessorChangeList];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -30,6 +30,7 @@
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <Mailer/SOGoMailBodyPart.h>
|
||||
#import <Mailer/SOGoMailObject.h>
|
||||
#import <Mailer/NSDictionary+Mail.h>
|
||||
|
||||
#import "MAPIStoreTypes.h"
|
||||
#import "MAPIStoreMailMessage.h"
|
||||
@@ -108,7 +109,7 @@
|
||||
static char recordBytes[] = {0xd9, 0xd8, 0x11, 0xa3, 0xe2, 0x90, 0x18, 0x41,
|
||||
0x9e, 0x04, 0x58, 0x46, 0x9d, 0x6d, 0x1b,
|
||||
0x68};
|
||||
|
||||
|
||||
*data = [[NSData dataWithBytes: recordBytes length: 16]
|
||||
asBinaryInMemCtx: memCtx];
|
||||
|
||||
@@ -117,19 +118,7 @@
|
||||
|
||||
- (NSString *) _fileName
|
||||
{
|
||||
NSString *fileName;
|
||||
NSDictionary *parameters;
|
||||
|
||||
fileName = [[bodyInfo objectForKey: @"parameterList"]
|
||||
objectForKey: @"name"];
|
||||
if (!fileName)
|
||||
{
|
||||
parameters = [[bodyInfo objectForKey: @"disposition"]
|
||||
objectForKey: @"parameterList"];
|
||||
fileName = [parameters objectForKey: @"filename"];
|
||||
}
|
||||
|
||||
return fileName;
|
||||
return [bodyInfo filename];
|
||||
}
|
||||
|
||||
- (int) getPidTagAttachLongFilename: (void **) data
|
||||
@@ -178,7 +167,7 @@
|
||||
|
||||
- (int) getPidTagAttachContentId: (void **) data
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
{
|
||||
*data = [[bodyInfo objectForKey: @"bodyId"]
|
||||
asUnicodeInMemCtx: memCtx];
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ MakeDisplayFolderName (NSString *folderName)
|
||||
NSArray *parts;
|
||||
NSString *lastFolder;
|
||||
NSUInteger max;
|
||||
|
||||
|
||||
parts = [folderName componentsSeparatedByString: @"/"];
|
||||
max = [parts count];
|
||||
if (max > 1)
|
||||
@@ -198,7 +198,6 @@ MakeDisplayFolderName (NSString *folderName)
|
||||
|
||||
userContext = [MAPIStoreUserContext userContextWithUsername: userName
|
||||
andTDBIndexing: NULL];
|
||||
[MAPIApp setUserContext: userContext];
|
||||
accountFolder = [[userContext rootFolders] objectForKey: @"mail"];
|
||||
folderName = [NSString stringWithFormat: @"folder%@",
|
||||
[newFolderName asCSSIdentifier]];
|
||||
@@ -213,7 +212,6 @@ MakeDisplayFolderName (NSString *folderName)
|
||||
[[folderName stringByEncodingImap4FolderName] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
|
||||
else
|
||||
mapistoreURI = nil;
|
||||
[MAPIApp setUserContext: nil];
|
||||
|
||||
return mapistoreURI;
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
- (NSString *) changeNumberForMessageUID: (NSString *) messageUid;
|
||||
- (void) setChangeKey: (NSData *) changeKey
|
||||
forMessageWithKey: (NSString *) messageKey;
|
||||
- (BOOL) updatePredecessorChangeListWith: (NSData *) changeKey
|
||||
forMessageWithKey: (NSString *) messageKey;
|
||||
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey;
|
||||
- (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey;
|
||||
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
|
||||
static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
|
||||
#include <gen_ndr/exchange.h>
|
||||
|
||||
#undef DEBUG
|
||||
#include <util/attr.h>
|
||||
#include <libmapi/libmapi.h>
|
||||
@@ -109,6 +111,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
[SOGoMAPIDBMessage objectWithName: @"versions.plist"
|
||||
inContainer: dbFolder]);
|
||||
[versionsMessage setObjectType: MAPIInternalCacheObject];
|
||||
[versionsMessage reloadIfNeeded];
|
||||
}
|
||||
|
||||
- (BOOL) ensureFolderExists
|
||||
@@ -139,7 +142,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
[[self mapping] updateID: fid withURL: [self url]];
|
||||
[dbFolder setNameInContainer: newNameInContainer];
|
||||
[self cleanupCaches];
|
||||
|
||||
|
||||
propsCopy = [newProperties mutableCopy];
|
||||
[propsCopy removeObjectForKey: key];
|
||||
[propsCopy autorelease];
|
||||
@@ -186,10 +189,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
nameInContainer = [NSString stringWithFormat: @"folder%@",
|
||||
[[folderName stringByEncodingImap4FolderName] asCSSIdentifier]];
|
||||
|
||||
/* it may be the operation is interleaved with operations
|
||||
from other users having cached information in the thread
|
||||
with the other user, so it'd better activate the user again here... */
|
||||
[[self userContext] activateWithUser: [[[self userContext] woContext] activeUser]];
|
||||
[[self userContext] activate];
|
||||
|
||||
newFolder = [SOGoMailFolderK objectWithName: nameInContainer
|
||||
inContainer: sogoObject];
|
||||
@@ -245,7 +245,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
sortOrdering: nil]
|
||||
count];
|
||||
*data = MAPILongValue (memCtx, longValue);
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
*data = [@"IPF.Note" asUnicodeInMemCtx: memCtx];
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
if (!nonDeletedQualifier)
|
||||
{
|
||||
deletedQualifier
|
||||
= [[EOKeyValueQualifier alloc]
|
||||
= [[EOKeyValueQualifier alloc]
|
||||
initWithKey: @"FLAGS"
|
||||
operatorSelector: EOQualifierOperatorContains
|
||||
value: [NSArray arrayWithObject: @"Deleted"]];
|
||||
@@ -378,7 +378,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
[self warnWithFormat: @"qualifier is only used for folders with name"];
|
||||
if (sortOrderings)
|
||||
[self errorWithFormat: @"sort orderings are not used for folders"];
|
||||
|
||||
|
||||
/* FIXME: Flush any cache before retrieving the hierarchy, this
|
||||
slows things down but it is safer */
|
||||
if (!qualifier)
|
||||
@@ -472,7 +472,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
}
|
||||
else
|
||||
supportsSubFolders = YES;
|
||||
|
||||
|
||||
return supportsSubFolders;
|
||||
}
|
||||
|
||||
@@ -519,6 +519,44 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
return [modseq1 compare: modseq2];
|
||||
}
|
||||
|
||||
- (void) _updatePredecessorChangeListWith: (NSData *) predecessorChangeList
|
||||
forMessageEntry: (NSMutableDictionary *) messageEntry
|
||||
{
|
||||
NSData *globCnt, *oldGlobCnt;
|
||||
NSMutableDictionary *changeList;
|
||||
NSString *guid;
|
||||
struct SizedXid *sizedXIDList;
|
||||
struct XID xid;
|
||||
uint32_t i, length;
|
||||
|
||||
sizedXIDList = [predecessorChangeList asSizedXidArrayInMemCtx: NULL with: &length];
|
||||
|
||||
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
|
||||
if (!changeList)
|
||||
{
|
||||
changeList = [NSMutableDictionary new];
|
||||
[messageEntry setObject: changeList
|
||||
forKey: @"PredecessorChangeList"];
|
||||
[changeList release];
|
||||
}
|
||||
|
||||
if (sizedXIDList) {
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
xid = sizedXIDList[i].XID;
|
||||
guid = [NSString stringWithGUID: &xid.NameSpaceGuid];
|
||||
globCnt = [NSData dataWithBytes: xid.LocalId.data length: xid.LocalId.length];
|
||||
oldGlobCnt = [changeList objectForKey: guid];
|
||||
if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending))
|
||||
[changeList setObject: globCnt forKey: guid];
|
||||
}
|
||||
|
||||
talloc_free (sizedXIDList);
|
||||
}
|
||||
|
||||
[versionsMessage save];
|
||||
}
|
||||
|
||||
- (void) _setChangeKey: (NSData *) changeKey
|
||||
forMessageEntry: (NSMutableDictionary *) messageEntry
|
||||
{
|
||||
@@ -529,8 +567,8 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
NSMutableDictionary *changeList;
|
||||
|
||||
xid = [changeKey asXIDInMemCtx: NULL];
|
||||
guid = [NSString stringWithGUID: &xid->GUID];
|
||||
globCnt = [NSData dataWithBytes: xid->Data length: xid->Size];
|
||||
guid = [NSString stringWithGUID: &xid->NameSpaceGuid];
|
||||
globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length];
|
||||
talloc_free (xid);
|
||||
|
||||
/* 1. set change key association */
|
||||
@@ -641,7 +679,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
fetchResults
|
||||
= [fetchResults sortedArrayUsingFunction: _compareFetchResultsByMODSEQ
|
||||
context: NULL];
|
||||
|
||||
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
result = [fetchResults objectAtIndex: count];
|
||||
@@ -927,8 +965,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
return changeNumber;
|
||||
}
|
||||
|
||||
- (void) setChangeKey: (NSData *) changeKey
|
||||
forMessageWithKey: (NSString *) messageKey
|
||||
- (NSMutableDictionary *) _messageEntryFromMessageKey: (NSString *) messageKey
|
||||
{
|
||||
NSMutableDictionary *messages, *messageEntry;
|
||||
NSString *messageUid;
|
||||
@@ -939,7 +976,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
messageEntry = [messages objectForKey: messageUid];
|
||||
if (!messageEntry)
|
||||
{
|
||||
[self warnWithFormat: @"attempting to synchronise to set the change key for "
|
||||
[self warnWithFormat: @"attempting to synchronise to get the message entry for "
|
||||
@"this message %@", messageKey];
|
||||
synced = [self synchroniseCacheForUID: messageUid];
|
||||
if (synced)
|
||||
@@ -950,11 +987,57 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
|
||||
|
||||
|
||||
return messageEntry;
|
||||
}
|
||||
|
||||
- (void) setChangeKey: (NSData *) changeKey
|
||||
forMessageWithKey: (NSString *) messageKey
|
||||
{
|
||||
[self _setChangeKey: changeKey
|
||||
forMessageEntry: [self _messageEntryFromMessageKey: messageKey]];
|
||||
|
||||
[versionsMessage save];
|
||||
}
|
||||
|
||||
- (BOOL) updatePredecessorChangeListWith: (NSData *) changeKey
|
||||
forMessageWithKey: (NSString *) messageKey
|
||||
{
|
||||
/* Update predecessor change list property given the change key. It
|
||||
returns if the change key has been added to the list or not */
|
||||
BOOL added = NO;
|
||||
NSData *globCnt, *oldGlobCnt;
|
||||
NSDictionary *messageEntry;
|
||||
NSMutableDictionary *changeList;
|
||||
NSString *guid;
|
||||
struct XID *xid;
|
||||
|
||||
xid = [changeKey asXIDInMemCtx: NULL];
|
||||
guid = [NSString stringWithGUID: &xid->NameSpaceGuid];
|
||||
globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length];
|
||||
talloc_free (xid);
|
||||
|
||||
messageEntry = [self _messageEntryFromMessageKey: messageKey];
|
||||
if (messageEntry)
|
||||
{
|
||||
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
|
||||
if (changeList)
|
||||
{
|
||||
oldGlobCnt = [changeList objectForKey: guid];
|
||||
if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending))
|
||||
{
|
||||
[changeList setObject: globCnt forKey: guid];
|
||||
[versionsMessage save];
|
||||
added = YES;
|
||||
}
|
||||
}
|
||||
else
|
||||
[self errorWithFormat: @"Missing predecessor change list to update"];
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey
|
||||
{
|
||||
NSDictionary *messages, *changeKeyDict;
|
||||
@@ -1178,7 +1261,7 @@ _parseIMAPRange (const unichar *uniString, NSArray **UIDsP)
|
||||
count++;
|
||||
}
|
||||
*UIDsP = UIDs;
|
||||
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -1220,6 +1303,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
fromFolder: (MAPIStoreFolder *) sourceFolder
|
||||
withMIDs: (uint64_t *) targetMids
|
||||
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
||||
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
|
||||
wantCopy: (uint8_t) wantCopy
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
|
||||
@@ -1234,12 +1318,13 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
NSDictionary *result;
|
||||
NSUInteger count;
|
||||
NSArray *a;
|
||||
NSData *changeKey;
|
||||
NSData *changeList;
|
||||
|
||||
if (![sourceFolder isKindOfClass: [MAPIStoreMailFolder class]])
|
||||
return [super moveCopyMessagesWithMIDs: srcMids andCount: midCount
|
||||
fromFolder: sourceFolder withMIDs: targetMids
|
||||
andChangeKeys: targetChangeKeys
|
||||
andPredecessorChangeLists: targetPredecessorChangeLists
|
||||
wantCopy: wantCopy
|
||||
inMemCtx: memCtx];
|
||||
|
||||
@@ -1328,11 +1413,11 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
[self synchroniseCache];
|
||||
for (count = 0; count < midCount; count++)
|
||||
{
|
||||
changeKey = [NSData dataWithBinary: targetChangeKeys[count]];
|
||||
changeList = [NSData dataWithBinary: targetPredecessorChangeLists[count]];
|
||||
messageKey = [NSString stringWithFormat: @"%@.eml",
|
||||
[destUIDs objectAtIndex: count]];
|
||||
[self setChangeKey: changeKey
|
||||
forMessageWithKey: messageKey];
|
||||
[self _updatePredecessorChangeListWith: changeList
|
||||
forMessageEntry: [self _messageEntryFromMessageKey: messageKey]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1456,7 +1541,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
[uids addObject: [self messageUIDFromMessageKey: childKey]];
|
||||
}
|
||||
|
||||
result = [client copyUids: uids
|
||||
result = [client copyUids: uids
|
||||
toFolder: newFolderIMAPName];
|
||||
if ([[result objectForKey: @"result"] boolValue])
|
||||
{
|
||||
@@ -1495,9 +1580,10 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
{
|
||||
SOGoCacheObject *childObject;
|
||||
|
||||
childObject = [SOGoCacheObject objectWithName: [SOGoCacheObject
|
||||
globallyUniqueObjectId]
|
||||
inContainer: sogoObject];
|
||||
[[[self context] userContext] activate];
|
||||
|
||||
childObject = [SOGoCacheObject objectWithName: [SOGoCacheObject globallyUniqueObjectId]
|
||||
inContainer: sogoObject];
|
||||
return [MAPIStoreMailVolatileMessage
|
||||
mapiStoreObjectWithSOGoObject: childObject
|
||||
inContainer: self];
|
||||
@@ -1573,7 +1659,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
rights |= RoleNone; /* actually "folder visible" */
|
||||
|
||||
// [self logWithFormat: @"rights for roles (%@) = %.8x", roles, rights];
|
||||
|
||||
|
||||
return rights;
|
||||
}
|
||||
|
||||
@@ -1624,7 +1710,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
client = [[(SOGoMailFolder *) sogoObject imap4Connection] client];
|
||||
[client select: [sogoObject absoluteImap4Name]];
|
||||
response = [client fetchUids: [keyAssoc allKeys]
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#import <Mailer/NSData+Mail.h>
|
||||
#import <Mailer/SOGoMailBodyPart.h>
|
||||
#import <Mailer/SOGoMailObject.h>
|
||||
#import <Mailer/NSDictionary+Mail.h>
|
||||
|
||||
#import "Codepages.h"
|
||||
#import "NSData+MAPIStore.h"
|
||||
@@ -196,7 +197,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
count1 = [keys indexOfObject: data1];
|
||||
data2 = [entry2 objectForKey: @"mimeType"];
|
||||
count2 = [keys indexOfObject: data2];
|
||||
|
||||
|
||||
if (count1 == count2)
|
||||
{
|
||||
data1 = [entry1 objectForKey: @"key"];
|
||||
@@ -529,7 +530,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
else
|
||||
stringValue = @"";
|
||||
*data = [stringValue asUnicodeInMemCtx: memCtx];
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -624,7 +625,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
NSDictionary *coreInfos;
|
||||
NSArray *flags;
|
||||
unsigned int v = 0;
|
||||
|
||||
|
||||
coreInfos = [sogoObject fetchCoreInfos];
|
||||
flags = [coreInfos objectForKey: @"flags"];
|
||||
|
||||
@@ -636,7 +637,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
if ([[self attachmentKeys]
|
||||
count] > 0)
|
||||
v |= MSGFLAG_HASATTACH;
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, v);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -656,7 +657,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
v = 2;
|
||||
else
|
||||
v = 0;
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, v);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -668,15 +669,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
NSDictionary *coreInfos;
|
||||
NSArray *flags;
|
||||
unsigned int v;
|
||||
|
||||
|
||||
coreInfos = [sogoObject fetchCoreInfos];
|
||||
|
||||
|
||||
flags = [coreInfos objectForKey: @"flags"];
|
||||
if ([flags containsObject: @"flagged"])
|
||||
v = 6;
|
||||
else
|
||||
v = 0;
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, v);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -755,7 +756,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
if ([ngAddress isKindOfClass: [NGMailAddress class]])
|
||||
{
|
||||
cn = [ngAddress displayName];
|
||||
|
||||
|
||||
// If we don't have a displayName, we use the email address instead. This
|
||||
// avoid bug #2119 - where Outlook won't display anything in the "From" field,
|
||||
// nor in the recipient field if we reply to the email.
|
||||
@@ -809,7 +810,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
entryId = MAPIStoreExternalEntryId (cn, email);
|
||||
|
||||
*data = [entryId asBinaryInMemCtx: memCtx];
|
||||
|
||||
|
||||
rc = MAPISTORE_SUCCESS;
|
||||
}
|
||||
else
|
||||
@@ -966,15 +967,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
{
|
||||
uint32_t v;
|
||||
NSString *s;
|
||||
|
||||
|
||||
s = [[sogoObject mailHeaders] objectForKey: @"x-priority"];
|
||||
v = 0x1;
|
||||
|
||||
|
||||
if ([s hasPrefix: @"1"]) v = 0x2;
|
||||
else if ([s hasPrefix: @"2"]) v = 0x2;
|
||||
else if ([s hasPrefix: @"4"]) v = 0x0;
|
||||
else if ([s hasPrefix: @"5"]) v = 0x0;
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, v);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -1163,14 +1164,14 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
|
||||
if (!headerSetup)
|
||||
[self _fetchHeaderData];
|
||||
|
||||
|
||||
if ([headerMimeType isEqualToString: @"text/plain"])
|
||||
format = EDITOR_FORMAT_PLAINTEXT;
|
||||
else if ([headerMimeType isEqualToString: @"text/html"])
|
||||
format = EDITOR_FORMAT_HTML;
|
||||
else
|
||||
format = 0; /* EDITOR_FORMAT_DONTKNOW */
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, format);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -1517,7 +1518,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
p = 0;
|
||||
recipient->data = talloc_array (msgData, void *, msgData->columns->cValues);
|
||||
memset (recipient->data, 0, msgData->columns->cValues * sizeof (void *));
|
||||
|
||||
|
||||
// PR_OBJECT_TYPE = MAPI_MAILUSER (see MAPI_OBJTYPE)
|
||||
recipient->data[p] = MAPILongValue (msgData, MAPI_MAILUSER);
|
||||
p++;
|
||||
@@ -1525,7 +1526,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
// PR_DISPLAY_TYPE = DT_MAILUSER (see MS-NSPI)
|
||||
recipient->data[p] = MAPILongValue (msgData, 0);
|
||||
p++;
|
||||
|
||||
|
||||
// PR_7BIT_DISPLAY_NAME_UNICODE
|
||||
recipient->data[p] = [cn asUnicodeInMemCtx: msgData];
|
||||
p++;
|
||||
@@ -1533,7 +1534,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
// PR_SMTP_ADDRESS_UNICODE
|
||||
recipient->data[p] = [email asUnicodeInMemCtx: msgData];
|
||||
p++;
|
||||
|
||||
|
||||
// PR_SEND_INTERNET_ENCODING = 0x00060000 (plain text, see OXCMAIL)
|
||||
recipient->data[p] = MAPILongValue (msgData, 0x00060000);
|
||||
p++;
|
||||
@@ -1566,12 +1567,9 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
withPrefix: (NSString *) keyPrefix
|
||||
{
|
||||
NSArray *parts;
|
||||
NSDictionary *parameters;
|
||||
NSUInteger count, max;
|
||||
|
||||
parameters = [[bodyInfo objectForKey: @"disposition"]
|
||||
objectForKey: @"parameterList"];
|
||||
if ([[parameters objectForKey: @"filename"] length] > 0)
|
||||
if ([[bodyInfo filename] length] > 0)
|
||||
{
|
||||
if ([keyPrefix length] == 0)
|
||||
keyPrefix = @"0";
|
||||
@@ -1614,6 +1612,8 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
max = [keyParts count];
|
||||
if (max > 0)
|
||||
{
|
||||
[[self userContext] activate];
|
||||
|
||||
currentPart = [sogoObject lookupName: [keyParts objectAtIndex: 0]
|
||||
inContext: nil
|
||||
acquire: NO];
|
||||
@@ -1643,15 +1643,29 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
return attachment;
|
||||
}
|
||||
|
||||
- (int) setReadFlag: (uint8_t) flag
|
||||
- (enum mapistore_error) setReadFlag: (uint8_t) flag
|
||||
{
|
||||
BOOL modified = NO;
|
||||
BOOL alreadyRead = NO;
|
||||
NSString *imapFlag = @"\\Seen";
|
||||
|
||||
alreadyRead = [[[sogoObject fetchCoreInfos] objectForKey: @"flags"]
|
||||
containsObject: @"seen"];
|
||||
|
||||
/* TODO: notifications should probably be emitted from here */
|
||||
if (flag & CLEAR_READ_FLAG)
|
||||
[sogoObject removeFlags: imapFlag];
|
||||
{
|
||||
[sogoObject removeFlags: imapFlag];
|
||||
modified = alreadyRead;
|
||||
}
|
||||
else
|
||||
[sogoObject addFlags: imapFlag];
|
||||
{
|
||||
[sogoObject addFlags: imapFlag];
|
||||
modified = !alreadyRead;
|
||||
}
|
||||
|
||||
if (modified)
|
||||
[(MAPIStoreMailFolder *)[self container] synchroniseCache];
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
@@ -1692,7 +1706,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void) save: (TALLOC_CTX *) memCtx
|
||||
- (void) save: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
NSNumber *value;
|
||||
|
||||
|
||||
@@ -161,15 +161,30 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK;
|
||||
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
|
||||
//[self logWithFormat: @" modseq: %.16lx", [modseq unsignedLongLongValue]];
|
||||
if (modseq)
|
||||
modseq = [NSNumber numberWithUnsignedLongLong:
|
||||
[modseq unsignedLongLongValue] + 1];
|
||||
{
|
||||
if (res->relop == RELOP_GT)
|
||||
modseq = [NSNumber numberWithUnsignedLongLong:
|
||||
[modseq unsignedLongLongValue] + 1];
|
||||
|
||||
}
|
||||
else
|
||||
modseq = [NSNumber numberWithUnsignedLongLong: 0];
|
||||
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"MODSEQ"
|
||||
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
|
||||
value: modseq];
|
||||
[*qualifier autorelease];
|
||||
rc = MAPIRestrictionStateNeedsEval;
|
||||
|
||||
if (res->relop == RELOP_GT || res->relop == RELOP_GE)
|
||||
{
|
||||
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"MODSEQ"
|
||||
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
|
||||
value: modseq];
|
||||
[*qualifier autorelease];
|
||||
rc = MAPIRestrictionStateNeedsEval;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Ignore other operations as IMAP only support MODSEQ >= X */
|
||||
[self warnWithFormat: @"Ignoring %@ as only supported operators are > and >=",
|
||||
[self operatorFromRestrictionOperator: res->relop]];
|
||||
rc = MAPIRestrictionStateAlwaysTrue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
#import <NGExtensions/NGHashMap.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSObject+Values.h>
|
||||
#import <NGExtensions/NSString+Encoding.h>
|
||||
#import <NGMime/NGMimeBodyPart.h>
|
||||
#import <NGMime/NGMimeMultipartBody.h>
|
||||
@@ -285,7 +286,7 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
|
||||
version = [properties objectForKey: @"version"];
|
||||
|
||||
return (version
|
||||
? exchange_globcnt ([version unsignedLongLongValue])
|
||||
? [version unsignedLongLongValue]
|
||||
: ULLONG_MAX);
|
||||
}
|
||||
|
||||
@@ -771,6 +772,12 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
|
||||
subjectData = [mailProperties objectForKey: MAPIPropertyKey (PR_NORMALIZED_SUBJECT_UNICODE)];
|
||||
if (subjectData)
|
||||
[subject appendString: subjectData];
|
||||
if ([subject length] == 0)
|
||||
{
|
||||
subjectData = [mailProperties objectForKey: MAPIPropertyKey (PR_SUBJECT_UNICODE)];
|
||||
if (subjectData)
|
||||
[subject appendString: subjectData];
|
||||
}
|
||||
[headers setObject: [subject asQPSubjectString: @"utf-8"] forKey: @"subject"];
|
||||
|
||||
messageId = [mailProperties objectForKey: MAPIPropertyKey (PR_INTERNET_MESSAGE_ID_UNICODE)];
|
||||
@@ -1077,6 +1084,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
|
||||
dd = [activeUser domainDefaults];
|
||||
from = [[activeUser allEmails] objectAtIndex: 0];
|
||||
|
||||
[[self userContext] activate];
|
||||
woContext = [[self userContext] woContext];
|
||||
authenticator = [sogoObject authenticatorInContext: woContext];
|
||||
error = [[SOGoMailer mailerWithDomainDefaults: dd]
|
||||
@@ -1103,7 +1111,8 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
|
||||
|
||||
- (void) save: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
NSString *folderName, *flag, *newIdString, *messageKey;
|
||||
BOOL updatedMetadata;
|
||||
NSString *folderName, *flag, *newIdString, *messageKey, *changeNumber;
|
||||
NSData *changeKey, *messageData;
|
||||
NGImap4Connection *connection;
|
||||
NGImap4Client *client;
|
||||
@@ -1139,21 +1148,33 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
|
||||
[sogoObject setNameInContainer: messageKey];
|
||||
[mapping registerURL: [self url] withID: mid];
|
||||
|
||||
/* synchronise the cache and update the change key with the one provided
|
||||
by the client. Before doing this, lets issue a unselect/select combo
|
||||
because of timing issues with Dovecot in obtaining the latest modseq.
|
||||
Sometimes, Dovecot doesn't return the newly appended UID if we do
|
||||
a "UID SORT (DATE) UTF-8 (MODSEQ XYZ) (NOT DELETED)" command (where
|
||||
XYZ is the HIGHESTMODSEQ+1) immediately after IMAP APPEND */
|
||||
/* synchronise the cache and update the predecessor change list
|
||||
with the change key provided by the client. Before doing
|
||||
this, lets issue a unselect/select combo because of timing
|
||||
issues with Dovecot in obtaining the latest modseq.
|
||||
Sometimes, Dovecot doesn't return the newly appended UID if
|
||||
we do a "UID SORT (DATE) UTF-8 (MODSEQ XYZ) (NOT DELETED)"
|
||||
command (where XYZ is the HIGHESTMODSEQ+1) immediately after
|
||||
IMAP APPEND */
|
||||
[client unselect];
|
||||
[client select: folderName];
|
||||
|
||||
[(MAPIStoreMailFolder *) container synchroniseCache];
|
||||
changeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)];
|
||||
if (changeKey)
|
||||
[(MAPIStoreMailFolder *) container
|
||||
setChangeKey: changeKey
|
||||
forMessageWithKey: messageKey];
|
||||
{
|
||||
updatedMetadata = [(MAPIStoreMailFolder *) container updatePredecessorChangeListWith: changeKey
|
||||
forMessageWithKey: messageKey];
|
||||
if (!updatedMetadata)
|
||||
[self warnWithFormat: @"Predecessor change list not updated with client data"];
|
||||
}
|
||||
|
||||
/* Update version property (PR_CHANGE_KEY indeed) as it is
|
||||
requested once it is saved */
|
||||
changeNumber = [(MAPIStoreMailFolder *) container changeNumberForMessageUID: newIdString];
|
||||
if (changeNumber)
|
||||
[properties setObject: [NSNumber numberWithUnsignedLongLong: [changeNumber unsignedLongLongValue] >> 16]
|
||||
forKey: @"version"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
withAID: (uint32_t) aid;
|
||||
- (int) getAttachmentTable: (MAPIStoreAttachmentTable **) tablePtr
|
||||
andRowCount: (uint32_t *) countPtr;
|
||||
- (int) setReadFlag: (uint8_t) flag;
|
||||
- (enum mapistore_error) setReadFlag: (uint8_t) flag;
|
||||
- (enum mapistore_error) saveMessage: (TALLOC_CTX *) memCtx;
|
||||
|
||||
- (NSArray *) activeContainerMessageTables;
|
||||
|
||||
@@ -178,56 +178,101 @@ rtf2html (NSData *compressedRTF)
|
||||
andColumns: (struct SPropTagArray *) columns
|
||||
{
|
||||
NSMutableDictionary *recipientProperties;
|
||||
enum MAPITAGS prop_tag;
|
||||
char *displayName = NULL;
|
||||
char *email = NULL;
|
||||
enum MAPI_OBJTYPE object_type = 0;
|
||||
char *smtpAddress = NULL;
|
||||
SOGoUser *recipientUser;
|
||||
NSUInteger count;
|
||||
NSString *recipientEmail = nil;
|
||||
NSString *recipientFullName = nil;
|
||||
id value;
|
||||
|
||||
recipientProperties = [NSMutableDictionary dictionaryWithCapacity: columns->cValues + 2];
|
||||
|
||||
for (count = 0; count < columns->cValues; count++)
|
||||
{
|
||||
prop_tag = columns->aulPropTag[count];
|
||||
switch(prop_tag) {
|
||||
case PidTagDisplayName:
|
||||
displayName = recipient->data[count];
|
||||
break;
|
||||
case PidTagEmailAddress:
|
||||
email = recipient->data[count];
|
||||
break;
|
||||
case PidTagObjectType:
|
||||
if (recipient->data[count])
|
||||
object_type = *((uint8_t*) recipient->data[count]);
|
||||
break;
|
||||
case PidTagSmtpAddress:
|
||||
smtpAddress = recipient->data[count];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (recipient->data[count])
|
||||
{
|
||||
value = NSObjectFromValuePointer (prop_tag,
|
||||
recipient->data[count]);
|
||||
if (value)
|
||||
[recipientProperties setObject: value
|
||||
forKey: MAPIPropertyKey (prop_tag)];
|
||||
}
|
||||
}
|
||||
|
||||
if (recipient->username)
|
||||
{
|
||||
value = [NSString stringWithUTF8String: recipient->username];
|
||||
[recipientProperties setObject: value forKey: @"x500dn"];
|
||||
}
|
||||
|
||||
if (object_type == MAPI_MAILUSER && recipient->username)
|
||||
{
|
||||
/* values from user object have priority over data sent by the client */
|
||||
recipientUser = [SOGoUser userWithLogin: [value lowercaseString]];
|
||||
if (recipientUser)
|
||||
{
|
||||
value = [recipientUser cn];
|
||||
if ([value length] > 0)
|
||||
[recipientProperties setObject: value forKey: @"fullName"];
|
||||
recipientFullName = value;
|
||||
|
||||
value = [[recipientUser allEmails] objectAtIndex: 0];
|
||||
if ([value length] > 0)
|
||||
[recipientProperties setObject: value forKey: @"email"];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (recipient->data[0])
|
||||
{
|
||||
value = [NSString stringWithUTF8String: recipient->data[0]];
|
||||
if ([value length] > 0)
|
||||
[recipientProperties setObject: value forKey: @"fullName"];
|
||||
}
|
||||
if (recipient->data[1])
|
||||
{
|
||||
value = [NSString stringWithUTF8String: recipient->data[1]];
|
||||
if ([value length] > 0)
|
||||
[recipientProperties setObject: value forKey: @"email"];
|
||||
}
|
||||
recipientEmail = value;
|
||||
}
|
||||
}
|
||||
|
||||
for (count = 0; count < columns->cValues; count++)
|
||||
/* If we do not have values from the user object we try to get them from the parameters */
|
||||
if (!recipientFullName && displayName)
|
||||
{
|
||||
if (recipient->data[count])
|
||||
{
|
||||
value = NSObjectFromValuePointer (columns->aulPropTag[count],
|
||||
recipient->data[count]);
|
||||
if (value)
|
||||
[recipientProperties setObject: value
|
||||
forKey: MAPIPropertyKey (columns->aulPropTag[count])];
|
||||
}
|
||||
value = [NSString stringWithUTF8String: displayName];
|
||||
if ([value length] > 0)
|
||||
recipientFullName = value;
|
||||
}
|
||||
|
||||
if (!recipientEmail && email)
|
||||
{
|
||||
value = [NSString stringWithUTF8String: email];
|
||||
if ([value length] > 0)
|
||||
recipientEmail = value;
|
||||
}
|
||||
|
||||
if (!recipientEmail && smtpAddress)
|
||||
{
|
||||
value = [NSString stringWithUTF8String: smtpAddress];
|
||||
if ([value length] > 0)
|
||||
recipientEmail = value;
|
||||
}
|
||||
|
||||
/* Now we can set the properties if we have them */
|
||||
if (recipientFullName)
|
||||
[recipientProperties setObject: recipientFullName forKey: @"fullName"];
|
||||
|
||||
if (recipientEmail)
|
||||
[recipientProperties setObject: recipientEmail forKey: @"email"];
|
||||
|
||||
return recipientProperties;
|
||||
}
|
||||
|
||||
@@ -504,11 +549,12 @@ rtf2html (NSData *compressedRTF)
|
||||
}
|
||||
|
||||
[self save: memCtx];
|
||||
/* We make sure that any change-related properties are removes from the
|
||||
/* We make sure that any change-related properties are removed from the
|
||||
properties dictionary, to make sure that related methods will be
|
||||
invoked the next time they are requested. */
|
||||
[properties removeObjectForKey: MAPIPropertyKey (PidTagChangeKey)];
|
||||
[properties removeObjectForKey: MAPIPropertyKey (PidTagChangeNumber)];
|
||||
[properties removeObjectForKey: MAPIPropertyKey (PidTagPredecessorChangeList)];
|
||||
|
||||
if ([container isKindOfClass: MAPIStoreFolderK])
|
||||
{
|
||||
@@ -873,7 +919,7 @@ rtf2html (NSData *compressedRTF)
|
||||
return [self getNo: data inMemCtx: memCtx];;
|
||||
}
|
||||
|
||||
- (int) setReadFlag: (uint8_t) flag
|
||||
- (enum mapistore_error) setReadFlag: (uint8_t) flag
|
||||
{
|
||||
// [self subclassResponsibility: _cmd];
|
||||
|
||||
|
||||
+37
-117
@@ -61,20 +61,25 @@ static BOOL initialization_done = NO;
|
||||
if (!initialization_done) { \
|
||||
OC_DEBUG(5, "[SOGo] You should call sogo_backend_init() first. Current thread: %p, pid: %d\n", \
|
||||
GSCurrentThread(), getpid()); \
|
||||
}
|
||||
} \
|
||||
OC_DEBUG(5, "[SOGo] --->");
|
||||
|
||||
#define NS_CURRENT_THREAD_TRY_UNREGISTER() \
|
||||
if (__nsrct_thread_registered) { \
|
||||
GSUnregisterCurrentThread(); \
|
||||
}
|
||||
} \
|
||||
OC_DEBUG(6, "[SOGo] <---");
|
||||
|
||||
#define TRYCATCH_START @try {
|
||||
#define TRYCATCH_END(pool) \
|
||||
} @catch (NSException * e) { \
|
||||
enum mapistore_error ret = sogo_backend_handle_objc_exception(e, __PRETTY_FUNCTION__, __LINE__); \
|
||||
mapiapp_cleanup(); \
|
||||
[pool release]; \
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(); \
|
||||
return ret; \
|
||||
}
|
||||
} \
|
||||
mapiapp_cleanup();
|
||||
|
||||
|
||||
static enum mapistore_error
|
||||
@@ -196,12 +201,28 @@ sogo_backend_init (void)
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
\details Cleanup operation to execute after an action has been performed
|
||||
so there won't be any conflicts with future calls.
|
||||
In practice this will deactivate the current user context set on MAPIApp
|
||||
(which is the current WOApplication), this means two things: (1) set nil
|
||||
as current user context on MAPIApp and (2) remove woContext from current
|
||||
thread dictionary (this is used on WOContext.m).
|
||||
*/
|
||||
static void mapiapp_cleanup(void)
|
||||
{
|
||||
Class MAPIApplicationK;
|
||||
MAPIApplicationK = NSClassFromString (@"MAPIApplication");
|
||||
if (MAPIApplicationK)
|
||||
[[MAPIApplicationK application] cleanup];
|
||||
}
|
||||
|
||||
/**
|
||||
\details Create a connection context to the sogo backend
|
||||
|
||||
\param mem_ctx pointer to the memory context
|
||||
\param uri pointer to the sogo path
|
||||
\param private_data pointer to the private backend context
|
||||
\param private_data pointer to the private backend context
|
||||
*/
|
||||
|
||||
static enum mapistore_error
|
||||
@@ -214,8 +235,6 @@ sogo_backend_create_context(TALLOC_CTX *mem_ctx,
|
||||
MAPIStoreContext *context;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
NS_CURRENT_THREAD_REGISTER();
|
||||
pool = [NSAutoreleasePool new];
|
||||
|
||||
@@ -251,8 +270,6 @@ sogo_backend_create_root_folder (const char *username,
|
||||
NSString *mapistoreUri;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
NS_CURRENT_THREAD_REGISTER();
|
||||
pool = [NSAutoreleasePool new];
|
||||
|
||||
@@ -288,8 +305,6 @@ sogo_backend_list_contexts(const char *username, struct indexing_context *indexi
|
||||
NSString *userName;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
NS_CURRENT_THREAD_REGISTER();
|
||||
pool = [NSAutoreleasePool new];
|
||||
|
||||
@@ -336,8 +351,6 @@ sogo_context_get_path(void *backend_object, TALLOC_CTX *mem_ctx,
|
||||
MAPIStoreContext *context;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (backend_object)
|
||||
{
|
||||
wrapper = backend_object;
|
||||
@@ -370,8 +383,6 @@ sogo_context_get_root_folder(void *backend_object, TALLOC_CTX *mem_ctx,
|
||||
MAPIStoreFolder *folder;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (backend_object)
|
||||
{
|
||||
wrapper = backend_object;
|
||||
@@ -413,8 +424,6 @@ sogo_folder_open_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid,
|
||||
MAPIStoreFolder *folder, *childFolder;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -442,7 +451,7 @@ sogo_folder_open_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid,
|
||||
|
||||
/**
|
||||
\details Create a folder in the sogo backend
|
||||
|
||||
|
||||
\param private_data pointer to the current sogo context
|
||||
|
||||
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR
|
||||
@@ -457,8 +466,6 @@ sogo_folder_create_folder(void *folder_object, TALLOC_CTX *mem_ctx,
|
||||
MAPIStoreFolder *folder, *childFolder;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -500,8 +507,6 @@ sogo_folder_delete(void *folder_object)
|
||||
MAPIStoreFolder *folder;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -532,8 +537,6 @@ sogo_folder_get_child_count(void *folder_object, enum mapistore_table_type table
|
||||
MAPIStoreFolder *folder;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -568,8 +571,6 @@ sogo_folder_open_message(void *folder_object,
|
||||
MAPIStoreMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -610,8 +611,6 @@ sogo_folder_create_message(void *folder_object,
|
||||
MAPIStoreMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -622,7 +621,7 @@ sogo_folder_create_message(void *folder_object,
|
||||
TRYCATCH_START
|
||||
rc = [folder createMessage: &message
|
||||
withMID: mid
|
||||
isAssociated: associated];
|
||||
isAssociated: associated];
|
||||
if (rc == MAPISTORE_SUCCESS)
|
||||
*message_object = [message tallocWrapper: mem_ctx];
|
||||
TRYCATCH_END(pool)
|
||||
@@ -646,8 +645,6 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags)
|
||||
MAPIStoreFolder *folder;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -677,6 +674,7 @@ sogo_folder_move_copy_messages(void *folder_object,
|
||||
uint32_t mid_count,
|
||||
uint64_t *src_mids, uint64_t *t_mids,
|
||||
struct Binary_r **target_change_keys,
|
||||
struct Binary_r **target_predecessor_change_lists,
|
||||
uint8_t want_copy)
|
||||
{
|
||||
MAPIStoreFolder *sourceFolder, *targetFolder;
|
||||
@@ -684,8 +682,6 @@ sogo_folder_move_copy_messages(void *folder_object,
|
||||
struct MAPIStoreTallocWrapper *wrapper;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -703,6 +699,7 @@ sogo_folder_move_copy_messages(void *folder_object,
|
||||
fromFolder: sourceFolder
|
||||
withMIDs: t_mids
|
||||
andChangeKeys: target_change_keys
|
||||
andPredecessorChangeLists: target_predecessor_change_lists
|
||||
wantCopy: want_copy
|
||||
inMemCtx: mem_ctx];
|
||||
TRYCATCH_END(pool)
|
||||
@@ -728,8 +725,6 @@ sogo_folder_move_folder(void *folder_object, void *target_folder_object,
|
||||
struct MAPIStoreTallocWrapper *wrapper;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -778,8 +773,6 @@ sogo_folder_copy_folder(void *folder_object, void *target_folder_object, TALLOC_
|
||||
struct MAPIStoreTallocWrapper *wrapper;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -822,8 +815,6 @@ sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx,
|
||||
MAPIStoreFolder *folder;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -861,8 +852,6 @@ sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx,
|
||||
MAPIStoreTable *table;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -900,8 +889,6 @@ sogo_folder_modify_permissions(void *folder_object, uint8_t flags,
|
||||
MAPIStoreFolder *folder;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -934,8 +921,6 @@ sogo_folder_preload_message_bodies(void *folder_object, enum mapistore_table_typ
|
||||
MAPIStoreFolder *folder;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (folder_object)
|
||||
{
|
||||
wrapper = folder_object;
|
||||
@@ -969,8 +954,6 @@ sogo_message_get_message_data(void *message_object,
|
||||
MAPIStoreMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
wrapper = message_object;
|
||||
@@ -1004,8 +987,6 @@ sogo_message_create_attachment (void *message_object, TALLOC_CTX *mem_ctx, void
|
||||
MAPIStoreAttachment *attachment;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
wrapper = message_object;
|
||||
@@ -1017,7 +998,6 @@ sogo_message_create_attachment (void *message_object, TALLOC_CTX *mem_ctx, void
|
||||
rc = [message createAttachment: &attachment inAID: aidp];
|
||||
if (rc == MAPISTORE_SUCCESS)
|
||||
*attachment_object = [attachment tallocWrapper: mem_ctx];
|
||||
// [context tearDownRequest];
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
@@ -1041,8 +1021,6 @@ sogo_message_open_attachment (void *message_object, TALLOC_CTX *mem_ctx,
|
||||
MAPIStoreAttachment *attachment;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
wrapper = message_object;
|
||||
@@ -1054,7 +1032,6 @@ sogo_message_open_attachment (void *message_object, TALLOC_CTX *mem_ctx,
|
||||
rc = [message getAttachment: &attachment withAID: aid];
|
||||
if (rc == MAPISTORE_SUCCESS)
|
||||
*attachment_object = [attachment tallocWrapper: mem_ctx];
|
||||
// [context tearDownRequest];
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
@@ -1077,8 +1054,6 @@ sogo_message_get_attachment_table (void *message_object, TALLOC_CTX *mem_ctx, vo
|
||||
MAPIStoreAttachmentTable *table;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
wrapper = message_object;
|
||||
@@ -1091,7 +1066,6 @@ sogo_message_get_attachment_table (void *message_object, TALLOC_CTX *mem_ctx, vo
|
||||
andRowCount: row_count];
|
||||
if (rc == MAPISTORE_SUCCESS)
|
||||
*table_object = [table tallocWrapper: mem_ctx];
|
||||
// [context tearDownRequest];
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
@@ -1116,9 +1090,6 @@ sogo_message_modify_recipients (void *message_object,
|
||||
MAPIStoreMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
wrapper = message_object;
|
||||
@@ -1130,7 +1101,6 @@ sogo_message_modify_recipients (void *message_object,
|
||||
rc = [message modifyRecipientsWithRecipients: recipients
|
||||
andCount: count
|
||||
andColumns: columns];
|
||||
// [context tearDownRequest];
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
@@ -1150,10 +1120,7 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
|
||||
struct MAPIStoreTallocWrapper *wrapper;
|
||||
NSAutoreleasePool *pool;
|
||||
MAPIStoreMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
enum mapistore_error rc;
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
@@ -1164,7 +1131,6 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
|
||||
|
||||
TRYCATCH_START
|
||||
rc = [message setReadFlag: flag];
|
||||
// [context tearDownRequest];
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
@@ -1186,9 +1152,6 @@ sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx)
|
||||
MAPIStoreMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
wrapper = message_object;
|
||||
@@ -1198,7 +1161,6 @@ sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx)
|
||||
|
||||
TRYCATCH_START
|
||||
rc = [message saveMessage: mem_ctx];
|
||||
// [context tearDownRequest];
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
@@ -1220,9 +1182,6 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags)
|
||||
MAPIStoreMailVolatileMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
wrapper = message_object;
|
||||
@@ -1232,7 +1191,6 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags)
|
||||
|
||||
TRYCATCH_START
|
||||
rc = [message submitWithFlags: flags];
|
||||
// [context tearDownRequest];
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
@@ -1259,9 +1217,6 @@ sogo_message_attachment_open_embedded_message (void *attachment_object,
|
||||
MAPIStoreEmbeddedMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (attachment_object)
|
||||
{
|
||||
wrapper = attachment_object;
|
||||
@@ -1301,9 +1256,6 @@ sogo_message_attachment_create_embedded_message (void *attachment_object,
|
||||
MAPIStoreEmbeddedMessage *message;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (attachment_object)
|
||||
{
|
||||
wrapper = attachment_object;
|
||||
@@ -1338,9 +1290,6 @@ static enum mapistore_error sogo_table_get_available_properties(void *table_obje
|
||||
MAPIStoreTable *table;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (table_object)
|
||||
{
|
||||
wrapper = table_object;
|
||||
@@ -1371,9 +1320,6 @@ sogo_table_set_columns (void *table_object, uint16_t count, enum MAPITAGS *prope
|
||||
MAPIStoreTable *table;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (table_object)
|
||||
{
|
||||
wrapper = table_object;
|
||||
@@ -1405,9 +1351,6 @@ sogo_table_set_restrictions (void *table_object, struct mapi_SRestriction *restr
|
||||
MAPIStoreTable *table;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (table_object)
|
||||
{
|
||||
wrapper = table_object;
|
||||
@@ -1441,9 +1384,6 @@ sogo_table_set_sort_order (void *table_object, struct SSortOrderSet *sort_order,
|
||||
MAPIStoreTable *table;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (table_object)
|
||||
{
|
||||
wrapper = table_object;
|
||||
@@ -1479,9 +1419,6 @@ sogo_table_get_row (void *table_object, TALLOC_CTX *mem_ctx,
|
||||
MAPIStoreTable *table;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (table_object)
|
||||
{
|
||||
wrapper = table_object;
|
||||
@@ -1515,9 +1452,6 @@ sogo_table_get_row_count (void *table_object,
|
||||
MAPIStoreTable *table;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (table_object)
|
||||
{
|
||||
wrapper = table_object;
|
||||
@@ -1549,9 +1483,6 @@ sogo_table_handle_destructor (void *table_object, uint32_t handle_id)
|
||||
MAPIStoreTable *table;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (table_object)
|
||||
{
|
||||
wrapper = table_object;
|
||||
@@ -1584,9 +1515,6 @@ static enum mapistore_error sogo_properties_get_available_properties(void *objec
|
||||
MAPIStoreObject *propObject;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (object)
|
||||
{
|
||||
wrapper = object;
|
||||
@@ -1620,9 +1548,6 @@ sogo_properties_get_properties (void *object,
|
||||
MAPIStoreObject *propObject;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (object)
|
||||
{
|
||||
wrapper = object;
|
||||
@@ -1655,9 +1580,6 @@ sogo_properties_set_properties (void *object, struct SRow *aRow)
|
||||
MAPIStoreObject *propObject;
|
||||
int rc;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
|
||||
if (object)
|
||||
{
|
||||
wrapper = object;
|
||||
@@ -1681,18 +1603,16 @@ sogo_properties_set_properties (void *object, struct SRow *aRow)
|
||||
}
|
||||
|
||||
static enum mapistore_error
|
||||
sogo_manager_generate_uri (TALLOC_CTX *mem_ctx,
|
||||
const char *user,
|
||||
const char *folder,
|
||||
const char *message,
|
||||
sogo_manager_generate_uri (TALLOC_CTX *mem_ctx,
|
||||
const char *user,
|
||||
const char *folder,
|
||||
const char *message,
|
||||
const char *rootURI,
|
||||
char **uri)
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
NSString *partialURLString, *username, *directory;
|
||||
|
||||
OC_DEBUG(5, "[SOGo]");
|
||||
|
||||
if (uri == NULL) return MAPISTORE_ERR_INVALID_PARAMETER;
|
||||
|
||||
/* This fixes a crash occurring during the instantiation of the
|
||||
@@ -1738,9 +1658,9 @@ sogo_manager_generate_uri (TALLOC_CTX *mem_ctx,
|
||||
*/
|
||||
int mapistore_init_backend(void)
|
||||
{
|
||||
struct mapistore_backend backend;
|
||||
int ret;
|
||||
static BOOL registered = NO;
|
||||
struct mapistore_backend backend;
|
||||
int ret;
|
||||
static BOOL registered = NO;
|
||||
|
||||
if (registered)
|
||||
ret = MAPISTORE_SUCCESS;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#import <Appointments/SOGoTaskObject.h>
|
||||
|
||||
#import "MAPIApplication.h"
|
||||
#import "MAPIStoreUserContext.h"
|
||||
#import "MAPIStoreTasksContext.h"
|
||||
#import "MAPIStoreTasksMessage.h"
|
||||
#import "MAPIStoreTasksMessageTable.h"
|
||||
@@ -61,6 +62,7 @@
|
||||
SOGoTaskObject *newEntry;
|
||||
NSString *name;
|
||||
|
||||
[[[self context] userContext] activate];
|
||||
name = [NSString stringWithFormat: @"%@.ics",
|
||||
[SOGoObject globallyUniqueObjectId]];
|
||||
newEntry = [SOGoTaskObject objectWithName: name
|
||||
@@ -69,7 +71,7 @@
|
||||
newMessage = [MAPIStoreTasksMessage mapiStoreObjectWithSOGoObject: newEntry
|
||||
inContainer: self];
|
||||
|
||||
|
||||
|
||||
return newMessage;
|
||||
}
|
||||
|
||||
@@ -116,7 +118,7 @@
|
||||
rights |= RightsReadItems;
|
||||
if (rights != 0)
|
||||
rights |= RoleNone; /* actually "folder visible" */
|
||||
|
||||
|
||||
return rights;
|
||||
}
|
||||
|
||||
|
||||
@@ -531,7 +531,7 @@
|
||||
}
|
||||
[vToDo setTimeStampAsDate: now];
|
||||
|
||||
[sogoObject saveComponent: vCalendar];
|
||||
[sogoObject saveCalendar: vCalendar];
|
||||
|
||||
[self updateVersions];
|
||||
}
|
||||
|
||||
@@ -86,6 +86,8 @@
|
||||
|
||||
/* SOGo hacky magic */
|
||||
- (void) activateWithUser: (SOGoUser *) activeUser;
|
||||
- (void) activate;
|
||||
- (void) deactivate;
|
||||
- (MAPIStoreAuthenticator *) authenticator;
|
||||
- (WOContext *) woContext;
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <Mailer/SOGoMailAccount.h>
|
||||
#import <Mailer/SOGoMailAccounts.h>
|
||||
|
||||
@@ -158,6 +159,8 @@ static NSMapTable *contextsTable = nil;
|
||||
if ([userPassword length] == 0)
|
||||
userPassword = username;
|
||||
[authenticator setPassword: userPassword];
|
||||
// Activate the profile on initialization
|
||||
[self activate];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -214,7 +217,7 @@ static NSMapTable *contextsTable = nil;
|
||||
if (!userFolder)
|
||||
{
|
||||
userFolder = [SOGoUserFolder objectWithName: username
|
||||
inContainer: MAPIApp];
|
||||
inContainer: nil];
|
||||
[userFolder retain];
|
||||
}
|
||||
|
||||
@@ -232,7 +235,8 @@ static NSMapTable *contextsTable = nil;
|
||||
if (!rootFolders)
|
||||
{
|
||||
rootFolders = [NSMutableDictionary new];
|
||||
[self userFolder];
|
||||
[self activate];
|
||||
[self userFolder]; // force lazy initialization
|
||||
[woContext setClientObject: userFolder];
|
||||
|
||||
/* Calendar */
|
||||
@@ -257,10 +261,10 @@ static NSMapTable *contextsTable = nil;
|
||||
acquire: NO];
|
||||
[containersBag addObject: accountsFolder];
|
||||
[woContext setClientObject: accountsFolder];
|
||||
|
||||
currentFolder = [accountsFolder lookupName: @"0"
|
||||
inContext: woContext
|
||||
acquire: NO];
|
||||
|
||||
[rootFolders setObject: currentFolder
|
||||
forKey: @"mail"];
|
||||
connection = [currentFolder imap4Connection];
|
||||
@@ -268,8 +272,7 @@ static NSMapTable *contextsTable = nil;
|
||||
|
||||
/* ensure the folder cache is filled */
|
||||
[currentFolder toManyRelationshipKeysWithNamespaces: YES];
|
||||
hierarchy = [connection
|
||||
cachedHierarchyResultsForURL: [currentFolder imap4URL]];
|
||||
hierarchy = [connection cachedHierarchyResultsForURL: [currentFolder imap4URL]];
|
||||
flags = [[hierarchy objectForKey: @"list"] objectForKey: @"/INBOX"];
|
||||
inboxHasNoInferiors = [flags containsObject: @"noinferiors"];
|
||||
}
|
||||
@@ -338,7 +341,7 @@ static NSMapTable *contextsTable = nil;
|
||||
|
||||
cm = [GCSChannelManager defaultChannelManager];
|
||||
channel = [cm acquireOpenChannelForURL: folderTableURL];
|
||||
|
||||
|
||||
/* FIXME: make use of [EOChannelAdaptor describeTableNames] instead */
|
||||
tableName = [[folderTableURL path] lastPathComponent];
|
||||
if ([channel evaluateExpressionX:
|
||||
@@ -355,7 +358,7 @@ static NSMapTable *contextsTable = nil;
|
||||
[channel cancelFetch];
|
||||
|
||||
|
||||
[cm releaseChannel: channel];
|
||||
[cm releaseChannel: channel];
|
||||
}
|
||||
|
||||
/* SOGo context objects */
|
||||
@@ -369,6 +372,11 @@ static NSMapTable *contextsTable = nil;
|
||||
return authenticator;
|
||||
}
|
||||
|
||||
- (void) activate
|
||||
{
|
||||
[self activateWithUser: [self sogoUser]];
|
||||
}
|
||||
|
||||
- (void) activateWithUser: (SOGoUser *) activeUser;
|
||||
{
|
||||
NSMutableDictionary *info;
|
||||
@@ -379,4 +387,24 @@ static NSMapTable *contextsTable = nil;
|
||||
[info setObject: woContext forKey: @"WOContext"];
|
||||
}
|
||||
|
||||
- (void) deactivate
|
||||
{
|
||||
NSMutableDictionary *info;
|
||||
|
||||
if (self == [MAPIApp userContext])
|
||||
[MAPIApp setUserContext: nil];
|
||||
else
|
||||
[self errorWithFormat: @"Error: Tried to deactivate an user context "
|
||||
@"not enabled (%@ vs %@)",
|
||||
[self username], [[MAPIApp userContext] username]];
|
||||
|
||||
info = [[NSThread currentThread] threadDictionary];
|
||||
if (woContext == [info objectForKey: @"WOContext"])
|
||||
[info removeObjectForKey: @"WOContext"];
|
||||
else
|
||||
[self errorWithFormat: @"Error: Tried to deactivate a WOContext "
|
||||
@"not enabled (%@ vs %@)",
|
||||
woContext, [info objectForKey: @"WOContext"]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -41,6 +41,8 @@
|
||||
|
||||
+ (id) dataWithXID: (const struct XID *) xid;
|
||||
- (struct XID *) asXIDInMemCtx: (void *) memCtx;
|
||||
- (struct SizedXid *) asSizedXidArrayInMemCtx: (void *) memCtx
|
||||
with: (uint32_t *) length;
|
||||
|
||||
+ (id) dataWithChangeKeyGUID: (NSString *) guidString
|
||||
andCnt: (NSData *) globCnt;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import "MAPIStoreTypes.h"
|
||||
#import "NSObject+MAPIStore.h"
|
||||
#import "NSString+MAPIStore.h"
|
||||
|
||||
@@ -29,6 +30,7 @@
|
||||
|
||||
#undef DEBUG
|
||||
#include <stdbool.h>
|
||||
#include <libmapi/libmapi.h>
|
||||
#include <talloc.h>
|
||||
#include <util/time.h>
|
||||
#include <gen_ndr/exchange.h>
|
||||
@@ -136,11 +138,11 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
|
||||
NSMutableData *xidData;
|
||||
struct FlatUID_r flatUID;
|
||||
|
||||
_fillFlatUIDWithGUID (&flatUID, &xid->GUID);
|
||||
_fillFlatUIDWithGUID (&flatUID, &xid->NameSpaceGuid);
|
||||
|
||||
xidData = [NSMutableData dataWithCapacity: 16 + xid->Size];
|
||||
xidData = [NSMutableData dataWithCapacity: 16 + xid->LocalId.length];
|
||||
[xidData appendBytes: flatUID.ab length: 16];
|
||||
[xidData appendBytes: xid->Data length: xid->Size];
|
||||
[xidData appendBytes: xid->LocalId.data length: xid->LocalId.length];
|
||||
|
||||
return xidData;
|
||||
}
|
||||
@@ -156,12 +158,12 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
|
||||
{
|
||||
xid = talloc_zero (memCtx, struct XID);
|
||||
|
||||
[self _extractGUID: &xid->GUID];
|
||||
[self _extractGUID: &xid->NameSpaceGuid];
|
||||
|
||||
xid->Size = max - 16;
|
||||
xid->LocalId.length = max - 16;
|
||||
|
||||
bytes = (uint8_t *) [self bytes];
|
||||
xid->Data = talloc_memdup (xid, (bytes+16), xid->Size);
|
||||
xid->LocalId.data = talloc_memdup (xid, (bytes+16), xid->LocalId.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -172,6 +174,38 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
|
||||
return xid;
|
||||
}
|
||||
|
||||
- (struct SizedXid *) asSizedXidArrayInMemCtx: (void *) memCtx
|
||||
with: (uint32_t *) length
|
||||
{
|
||||
struct Binary_r bin;
|
||||
struct SizedXid *sizedXIDArray;
|
||||
|
||||
bin.cb = [self length];
|
||||
bin.lpb = (uint8_t *)[self bytes];
|
||||
|
||||
sizedXIDArray = get_SizedXidArray(memCtx, &bin, length);
|
||||
if (!sizedXIDArray)
|
||||
{
|
||||
NSLog (@"Impossible to parse SizedXID array");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sizedXIDArray;
|
||||
}
|
||||
|
||||
- (NSComparisonResult) compare: (NSData *) otherGlobCnt
|
||||
{
|
||||
uint64_t globCnt = 0, oGlobCnt = 0;
|
||||
|
||||
if ([self length] > 0)
|
||||
globCnt = *(uint64_t *) [self bytes];
|
||||
|
||||
if ([otherGlobCnt length] > 0)
|
||||
oGlobCnt = *(uint64_t *) [otherGlobCnt bytes];
|
||||
|
||||
return MAPICNCompare (globCnt, oGlobCnt, NULL);
|
||||
}
|
||||
|
||||
+ (id) dataWithChangeKeyGUID: (NSString *) guidString
|
||||
andCnt: (NSData *) globCnt;
|
||||
{
|
||||
|
||||
@@ -161,8 +161,11 @@
|
||||
minute: [tzStart minuteOfHour] second: 0
|
||||
timeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
|
||||
|
||||
tmpDate = [tmpDate addYear: 0 month: ((pos > 0) ? 0 : 1)
|
||||
day: 0 hour: 0 minute: 0
|
||||
tmpDate = [tmpDate addYear: 0
|
||||
month: ((pos > 0) ? 0 : 1)
|
||||
day: 0
|
||||
hour: 0
|
||||
minute: 0
|
||||
second: 0];
|
||||
|
||||
/* If the day of the time change is "-XSU", we need to determine whether the
|
||||
@@ -197,12 +200,41 @@
|
||||
END:STANDARD
|
||||
END:VTIMEZONE
|
||||
|
||||
The time changes occure on a Sunday, but in March, the 1st is a Sunday itself and in November
|
||||
The time changes occur on a Sunday, but in March, the 1st is a Sunday itself and in November
|
||||
the 1st is also a Sunday. If we don't decrement "pos" by one, tmpDate (which is set to March or November 1st
|
||||
because of "day: 1" will have 14 more days added for March and 7 more days added for November - which will
|
||||
effectively shift the time change by a whole week.
|
||||
|
||||
In Europe/Berlin, we have a different use-case for November. In 2015, November 1st is a Sunday.
|
||||
The time change in November must occur on October 25th but since tmpDate will be November 1st,
|
||||
so a Sunday, dateDayOfWeek will be 0 and dayOfWeek will also be 0 we would decrement tmpDate by 14 days,
|
||||
which is incorrect because it would shift the timezone change one week earlier. We take care about this
|
||||
one with check if pos is greater or equal than 0 and if so, we don't decrement it.
|
||||
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:-//Inverse inc.//NONSGML Olson 2014g//EN
|
||||
VERSION:2.0
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:Europe/Berlin
|
||||
X-LIC-LOCATION:Europe/Berlin
|
||||
BEGIN:DAYLIGHT
|
||||
TZOFFSETFROM:+0100
|
||||
TZOFFSETTO:+0200
|
||||
TZNAME:CEST
|
||||
DTSTART:19700329T020000
|
||||
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
|
||||
END:DAYLIGHT
|
||||
BEGIN:STANDARD
|
||||
TZOFFSETFROM:+0200
|
||||
TZOFFSETTO:+0100
|
||||
TZNAME:CET
|
||||
DTSTART:19701025T030000
|
||||
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
|
||||
END:STANDARD
|
||||
END:VTIMEZONE
|
||||
END:VCALENDAR
|
||||
*/
|
||||
if (dayOfWeek == dateDayOfWeek)
|
||||
if (dayOfWeek == dateDayOfWeek && pos >= 0)
|
||||
pos--;
|
||||
|
||||
offset = (dayOfWeek - dateDayOfWeek) + (pos * 7);
|
||||
|
||||
Executable
+82
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
DEBUG=False
|
||||
|
||||
dir_mappings = {"../UI/Templates":"../UI/Common",
|
||||
"../UI/Templates/AdministrationUI":"../UI/AdministrationUI",
|
||||
"../UI/Templates/Appointments":"../SoObjects/Appointments",
|
||||
"../UI/Templates/ContactsUI":"../UI/Contacts",
|
||||
"../UI/Templates/MailerUI":"../UI/MailerUI",
|
||||
"../UI/Templates/MailPartViewers":"../UI/MailPartViewers",
|
||||
"../UI/Templates/MainUI":"../UI/MainUI",
|
||||
"../UI/Templates/PreferencesUI":"../UI/PreferencesUI",
|
||||
"../UI/Templates/SchedulerUI":"../UI/Scheduler"
|
||||
}
|
||||
|
||||
def get_translations(path):
|
||||
try:
|
||||
transpath = dir_mappings.get(path, path)
|
||||
transname = transpath + '/English.lproj/Localizable.strings'
|
||||
transall = open(transname).read()
|
||||
except:
|
||||
transall = ""
|
||||
return transall
|
||||
|
||||
|
||||
def find_missing_translations(rootdir='.', extention='', recomp=None, greylist=()):
|
||||
for path, dirs, files in os.walk(rootdir):
|
||||
filelist = [f for f in files if f[(-1 * len(extention)):] == extention]
|
||||
if filelist:
|
||||
for filename in filelist:
|
||||
if filename in greylist:
|
||||
print "%s is greylisted -- SKIPPING" % filename
|
||||
continue
|
||||
pathname = path + '/' + filename
|
||||
lines = open(pathname).read().split("\n")
|
||||
values = [r.groups()[0] for r in [recomp.search(l) for l in lines] if r]
|
||||
if values:
|
||||
#- Get the current english translations for the path
|
||||
transgood = get_translations(path)
|
||||
if not transgood:
|
||||
print "No translation file found for %s, skipping %s" % (path, pathname)
|
||||
continue
|
||||
notfound = list()
|
||||
if DEBUG:print pathname
|
||||
for value in values:
|
||||
#- Try to find the value from the source file in the translation file
|
||||
escaped_value = re.escape(value)
|
||||
found = re.search('(%s|"%s")\s*=\s*"(.*?)";' % (escaped_value, escaped_value), transgood)
|
||||
if found:
|
||||
if DEBUG: print "\t", '[%s] FOUND -- "%s"' % found.groups()
|
||||
else:
|
||||
notfound.append("-->\t[%s] ==== Not Found ====" % value)
|
||||
if notfound:
|
||||
if not DEBUG:print pathname
|
||||
print "\n".join(notfound)
|
||||
|
||||
|
||||
def main():
|
||||
#- Only one option...
|
||||
if len(sys.argv) > 1:
|
||||
if sys.argv[1] == '-g':
|
||||
global DEBUG
|
||||
DEBUG = True
|
||||
else:
|
||||
print 'Usage:', sys.argv[0], '[-g]\n\t\t-g: debug will show matching also'
|
||||
sys.exit(1)
|
||||
|
||||
greylist = ('UIxFilterEditor.wox')
|
||||
|
||||
#- Get only the label:value from all lines
|
||||
recomp = re.compile(' label:[^=]*="(.*?)"')
|
||||
find_missing_translations('../UI', 'wox', recomp, greylist)
|
||||
|
||||
#- [self labelForKey: @"Issuer"]
|
||||
recomp = re.compile('\[self labelForKey: @"(.*?)"\]')
|
||||
find_missing_translations('../UI', 'm', recomp, ())
|
||||
|
||||
main()
|
||||
@@ -11,16 +11,16 @@ vtodo_class2 = "(مهمة سرية)";
|
||||
"The event \"%{Summary}\" was created" = "أُنشِئ الحدث \"%{Summary}\"";
|
||||
"The event \"%{Summary}\" was deleted" = "حُذِفَ الحدث \"%{Summary}\"";
|
||||
"The event \"%{Summary}\" was updated" = "حُدِّث الحدث \"%{Summary}\"";
|
||||
"The following attendees(s) were notified:" = "تم ابلاغ المدعو (المدعويين) الأتي أسماءهم:";
|
||||
"The following attendees(s) were added:" = "تم أضافة المدعو (المدعويين) الأتي أسماءهم:";
|
||||
"The following attendees(s) were removed:" = "تم مسح المدعو (المدعويين) الأتي أسماءهم:";
|
||||
"The following attendees(s) were notified" = "تم ابلاغ المدعو (المدعويين) الأتي أسماءهم";
|
||||
"The following attendees(s) were added" = "تم أضافة المدعو (المدعويين) الأتي أسماءهم";
|
||||
"The following attendees(s) were removed" = "تم مسح المدعو (المدعويين) الأتي أسماءهم";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "التقويم:";
|
||||
"startDate_label" = "البداية:";
|
||||
"endDate_label" = "النهاية:";
|
||||
"calendar_label" = "التقويم";
|
||||
"startDate_label" = "البداية";
|
||||
"endDate_label" = "النهاية";
|
||||
"due_label" = "تاريخ الاستحقاق:";
|
||||
"location_label" = "المكان:";
|
||||
"location_label" = "المكان";
|
||||
"summary_label" = "الملخص:";
|
||||
"comment_label" = "التعليق:";
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Isilpeko egitekoa)";
|
||||
"The event \"%{Summary}\" was created" = "\"%{Summary}\" ekitaldia sortu da";
|
||||
"The event \"%{Summary}\" was deleted" = "\"%{Summary}\" ekitaldia ezabatu da";
|
||||
"The event \"%{Summary}\" was updated" = "\"%{Summary}\" ekitaldia eguneratu da";
|
||||
"The following attendees(s) were notified:" = "Ondorengo partaidea(k) jakinarazi d(ir)a:";
|
||||
"The following attendees(s) were added:" = "Ondorengo partaidea(k) gehitu d(ir)a:";
|
||||
"The following attendees(s) were removed:" = "Ondorengo partaidea(k) ezabatu d(ir)a:";
|
||||
"The following attendees(s) were notified" = "Ondorengo partaidea(k) jakinarazi d(ir)a";
|
||||
"The following attendees(s) were added" = "Ondorengo partaidea(k) gehitu d(ir)a";
|
||||
"The following attendees(s) were removed" = "Ondorengo partaidea(k) ezabatu d(ir)a";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Egutegia";
|
||||
"startDate_label" = "Hasi:";
|
||||
"endDate_label" = "Amaitu:";
|
||||
"startDate_label" = "Hasi";
|
||||
"endDate_label" = "Amaitu";
|
||||
"due_label" = "Epemuga:";
|
||||
"location_label" = "Kokapena:";
|
||||
"location_label" = "Kokapena";
|
||||
"summary_label" = "Laburpena:";
|
||||
"comment_label" = "Iruzkina:";
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Tarefa Confidencial)";
|
||||
"The event \"%{Summary}\" was created" = "O evento \"%{Summary}\" foi criado";
|
||||
"The event \"%{Summary}\" was deleted" = "O evento \"%{Summary}\" foi removido";
|
||||
"The event \"%{Summary}\" was updated" = "O evento \"%{Summary}\" foi atualizado";
|
||||
"The following attendees(s) were notified:" = "Estes participantes foram notificados:";
|
||||
"The following attendees(s) were added:" = "Estes participantes foram adicionados:";
|
||||
"The following attendees(s) were removed:" = "Estes participantes foram removidos:";
|
||||
"The following attendees(s) were notified" = "Estes participantes foram notificados";
|
||||
"The following attendees(s) were added" = "Estes participantes foram adicionados";
|
||||
"The following attendees(s) were removed" = "Estes participantes foram removidos";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Calendário:";
|
||||
"startDate_label" = "Início:";
|
||||
"endDate_label" = "Fim:";
|
||||
"calendar_label" = "Calendário";
|
||||
"startDate_label" = "Início";
|
||||
"endDate_label" = "Fim";
|
||||
"due_label" = "Data de Vencimento:";
|
||||
"location_label" = "Local:";
|
||||
"location_label" = "Local";
|
||||
"summary_label" = "Resumo:";
|
||||
"comment_label" = "Comentário:";
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Tasca confidencial)";
|
||||
"The event \"%{Summary}\" was created" = "Es va crear l'esdeveniment \"%{Summary}\" ";
|
||||
"The event \"%{Summary}\" was deleted" = "Es va esborrar l'esdeveniment \"%{Summary}\" ";
|
||||
"The event \"%{Summary}\" was updated" = "Es va modificar l'esdeveniment \"%{Summary}\" ";
|
||||
"The following attendees(s) were notified:" = "I va notificar als següents participants: ";
|
||||
"The following attendees(s) were added:" = "Es van agregar els següents participants: ";
|
||||
"The following attendees(s) were removed:" = "Heu suprimit els assistents següents:";
|
||||
"The following attendees(s) were notified" = "I va notificar als següents participants ";
|
||||
"The following attendees(s) were added" = "Es van agregar els següents participants ";
|
||||
"The following attendees(s) were removed" = "Heu suprimit els assistents següents";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Calendari:";
|
||||
"startDate_label" = "Inici:";
|
||||
"endDate_label" = "Final:";
|
||||
"calendar_label" = "Calendari";
|
||||
"startDate_label" = "Inici";
|
||||
"endDate_label" = "Final";
|
||||
"due_label" = "Data límit:";
|
||||
"location_label" = "Lloc:";
|
||||
"location_label" = "Lloc";
|
||||
"summary_label" = "Resum:";
|
||||
"comment_label" = "Comentari:";
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
"Inviting the following persons is prohibited:" = "禁止邀請以下人士:";
|
||||
"Personal Calendar" = "個人行事曆";
|
||||
vevent_class0 = "(公開事件)";
|
||||
vevent_class1 = "(私人事件)";
|
||||
vevent_class2 = "(機密事件)";
|
||||
|
||||
vtodo_class0 = "(公開任務)";
|
||||
vtodo_class1 = "(私人任務)";
|
||||
vtodo_class2 = "(機密任務)";
|
||||
|
||||
/* Receipts */
|
||||
"The event \"%{Summary}\" was created" = "事件 \"%{Summary}\" 已建立";
|
||||
"The event \"%{Summary}\" was deleted" = "事件\"%{Summary}\" 已刪除";
|
||||
"The event \"%{Summary}\" was updated" = "事件\"%{Summary}\" 已異動";
|
||||
"The following attendees(s) were notified" = "已通知下列出席者";
|
||||
"The following attendees(s) were added" = "已增加下列出席者";
|
||||
"The following attendees(s) were removed" = "已移除下列出席者";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "行事曆";
|
||||
"startDate_label" = "開始";
|
||||
"endDate_label" = "結束";
|
||||
"due_label" = "截止日期:";
|
||||
"location_label" = "地點";
|
||||
"summary_label" = "事件主題:";
|
||||
"comment_label" = "備註:";
|
||||
|
||||
/* Invitation */
|
||||
"Event Invitation: \"%{Summary}\"" = "邀請事件: \"%{Summary}\"";
|
||||
"(sent by %{SentBy}) " = "(來自 %{SentBy})";
|
||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText} 邀請您參加 %{Summary}。\n\n起始日期: %{StartDate}\n結束日期: %{EndDate}\n備註說明: %{Description}";
|
||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText} 邀請您參加 %{Summary}。\n\n起始時間: %{StartDate} %{StartTime}\n結束時間: %{EndDate} %{EndTime}\n備註說明: %{Description}";
|
||||
|
||||
/* Deletion */
|
||||
"Event Cancelled: \"%{Summary}\"" = "取消事件 : \"%{Summary}\"";
|
||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
|
||||
= "%{Organizer} %{SentByText} 己取消事件: %{Summary}。\n\n起始日期: %{StartDate}\n結束日期: %{EndDate}\n備註說明: %{Description}";
|
||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
|
||||
= "%{Organizer} %{SentByText} 己取消了事件: %{Summary}。\n\n起始時間: %{StartDate} %{StartTime}\n結束時間: %{EndDate} %{EndTime}\n備註說明: %{Description}";
|
||||
|
||||
/* Update */
|
||||
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
|
||||
= " 安排於%{OldStartDate} 的事件 \"%{Summary}\" 已變更";
|
||||
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
|
||||
= "安排於 %{OldStartDate} %{OldStartTime} 的事件 \"%{Summary}\" 已變更";
|
||||
"The following parameters have changed in the \"%{Summary}\" meeting:"
|
||||
= "已變更會議 \"%{Summary}\" 下列參數:";
|
||||
"Please accept or decline those changes."
|
||||
= "請接受或拒絶這些變更。";
|
||||
|
||||
/* Reply */
|
||||
"Accepted invitation: \"%{Summary}\"" = "接受邀請: \"%{Summary}\"";
|
||||
"Declined invitation: \"%{Summary}\"" = "拒絶邀請: \"%{Summary}\"";
|
||||
"Delegated invitation: \"%{Summary}\"" = "\"委派出席: \"%{Summary}\"";
|
||||
"Not yet decided on invitation: \"%{Summary}\"" = "未處理的邀請: \"%{Summary}\"";
|
||||
"%{Attendee} %{SentByText}has accepted your event invitation."
|
||||
= "\"%{Attendee} %{SentByText}已接受了您的邀請。";
|
||||
"%{Attendee} %{SentByText}has declined your event invitation."
|
||||
= "\"%{Attendee} %{SentByText}已拒絶了您的邀請。";
|
||||
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
|
||||
= "\"%{Attendee} %{SentByText}已將您的邀請委任給%{Delegate}。";
|
||||
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
|
||||
= "%{Attendee} %{SentByText}還沒有決定是否接受您的邀請。";
|
||||
|
||||
/* Resources */
|
||||
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "無法讀取資源: \"%{Cn} %{SystemEmail}\"";
|
||||
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "\"%{Cn} %{SystemEmail}\" 的衝突事件己達上限 ( %{NumberOfSimultaneousBookings} )。衝突事件 \"%{EventTitle}\" 的起始日期為 %{StartDate}。";
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Skrytý úkol)";
|
||||
"The event \"%{Summary}\" was created" = "Událost \"%{Summary}\" byla vytvořena";
|
||||
"The event \"%{Summary}\" was deleted" = "Událost \"%{Summary}\" byla smazána";
|
||||
"The event \"%{Summary}\" was updated" = "Událost \"%{Summary}\" byla upravena";
|
||||
"The following attendees(s) were notified:" = "Následující účastníci byli upozorněni:";
|
||||
"The following attendees(s) were added:" = "Následující účastníci byli přidáni:";
|
||||
"The following attendees(s) were removed:" = "Následující účastníci byli odebráni:";
|
||||
"The following attendees(s) were notified" = "Následující účastníci byli upozorněni";
|
||||
"The following attendees(s) were added" = "Následující účastníci byli přidáni";
|
||||
"The following attendees(s) were removed" = "Následující účastníci byli odebráni";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Kalendář:";
|
||||
"startDate_label" = "Začátek:";
|
||||
"endDate_label" = "Konec:";
|
||||
"calendar_label" = "Kalendář";
|
||||
"startDate_label" = "Začátek";
|
||||
"endDate_label" = "Konec";
|
||||
"due_label" = "Termín:";
|
||||
"location_label" = "Místo:";
|
||||
"location_label" = "Místo";
|
||||
"summary_label" = "Název:";
|
||||
"comment_label" = "Komentář:";
|
||||
|
||||
|
||||
@@ -11,16 +11,16 @@ vtodo_class2 = "(Hemmelig opgave)";
|
||||
"The event \"%{Summary}\" was created" = "Begivenheden \"%{Summary}\" blev oprettet";
|
||||
"The event \"%{Summary}\" was deleted" = "Begivenheden \"%{Summary}\" blev slettet";
|
||||
"The event \"%{Summary}\" was updated" = "Begivenheden \"%{Summary}\" blev opdateret";
|
||||
"The following attendees(s) were notified:" = "Følgende deltager(e) blev underrettet:";
|
||||
"The following attendees(s) were added:" = "Følgende deltager(e) blev tilføjet:";
|
||||
"The following attendees(s) were removed:" = "Følgende deltager(e) blev fjernet:";
|
||||
"The following attendees(s) were notified" = "Følgende deltager(e) blev underrettet";
|
||||
"The following attendees(s) were added" = "Følgende deltager(e) blev tilføjet";
|
||||
"The following attendees(s) were removed" = "Følgende deltager(e) blev fjernet";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Kalender:";
|
||||
"startDate_label" = "Start:";
|
||||
"endDate_label" = "Slut:";
|
||||
"calendar_label" = "Kalender";
|
||||
"startDate_label" = "Start";
|
||||
"endDate_label" = "Slut";
|
||||
"due_label" = "Forfaldsdato:";
|
||||
"location_label" = "Sted:";
|
||||
"location_label" = "Sted";
|
||||
"summary_label" = "Resumé:";
|
||||
"comment_label" = "Kommentér:";
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Vertrouwelijke taak)";
|
||||
"The event \"%{Summary}\" was created" = "De gebeurtenis \"%{Summary}\" is aangemaakt";
|
||||
"The event \"%{Summary}\" was deleted" = "De gebeurtenis \"%{Summary}\" is verwijderd";
|
||||
"The event \"%{Summary}\" was updated" = "De gebeurtenis \"%{Summary}\" is gewijzigd";
|
||||
"The following attendees(s) were notified:" = "De volgende deelnemers zijn in kennis gesteld:";
|
||||
"The following attendees(s) were added:" = "De volgende deelnemers zijn toegevoegd:";
|
||||
"The following attendees(s) were removed:" = "De volgende deelnemers zijn verwijderd:";
|
||||
"The following attendees(s) were notified" = "De volgende deelnemers zijn in kennis gesteld";
|
||||
"The following attendees(s) were added" = "De volgende deelnemers zijn toegevoegd";
|
||||
"The following attendees(s) were removed" = "De volgende deelnemers zijn verwijderd";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Agenda:";
|
||||
"startDate_label" = "Start:";
|
||||
"endDate_label" = "Einde:";
|
||||
"calendar_label" = "Agenda";
|
||||
"startDate_label" = "Start";
|
||||
"endDate_label" = "Einde";
|
||||
"due_label" = "Vervaldag:";
|
||||
"location_label" = "Locatie:";
|
||||
"location_label" = "Locatie";
|
||||
"summary_label" = "Samenvatting:";
|
||||
"comment_label" = "Commentaar:";
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Confidential task)";
|
||||
"The event \"%{Summary}\" was created" = "The event \"%{Summary}\" was created";
|
||||
"The event \"%{Summary}\" was deleted" = "The event \"%{Summary}\" was deleted";
|
||||
"The event \"%{Summary}\" was updated" = "The event \"%{Summary}\" was updated";
|
||||
"The following attendees(s) were notified:" = "The following attendee(s) were notified:";
|
||||
"The following attendees(s) were added:" = "The following attendee(s) were added:";
|
||||
"The following attendees(s) were removed:" = "The following attendee(s) were removed:";
|
||||
"The following attendees(s) were notified" = "The following attendee(s) were notified";
|
||||
"The following attendees(s) were added" = "The following attendee(s) were added";
|
||||
"The following attendees(s) were removed" = "The following attendee(s) were removed";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Calendar:";
|
||||
"startDate_label" = "Start:";
|
||||
"endDate_label" = "End:";
|
||||
"calendar_label" = "Calendar";
|
||||
"startDate_label" = "Start";
|
||||
"endDate_label" = "End";
|
||||
"due_label" = "Due Date:";
|
||||
"location_label" = "Location:";
|
||||
"location_label" = "Location";
|
||||
"summary_label" = "Summary:";
|
||||
"comment_label" = "Comment:";
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Luottamuksellinen tehtävä)";
|
||||
"The event \"%{Summary}\" was created" = "Tapahtuma \"%{Summary}\" luotiin";
|
||||
"The event \"%{Summary}\" was deleted" = "Tapahtuma \"%{Summary}\" poistettiin";
|
||||
"The event \"%{Summary}\" was updated" = "Tapahtuma \"%{Summary}\" päivitettiin";
|
||||
"The following attendees(s) were notified:" = "Seuraava(t) osallistuja(t) on informoitu:";
|
||||
"The following attendees(s) were added:" = "Seuraava(t) osalllistuja(t) on lisätty:";
|
||||
"The following attendees(s) were removed:" = "Seuraava(t) osalllistuja(t) poistettiin:";
|
||||
"The following attendees(s) were notified" = "Seuraava(t) osallistuja(t) on informoitu";
|
||||
"The following attendees(s) were added" = "Seuraava(t) osalllistuja(t) on lisätty";
|
||||
"The following attendees(s) were removed" = "Seuraava(t) osalllistuja(t) poistettiin";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Kalenteri:";
|
||||
"startDate_label" = "Alkaa:";
|
||||
"endDate_label" = "Päättyy:";
|
||||
"calendar_label" = "Kalenteri";
|
||||
"startDate_label" = "Alkaa";
|
||||
"endDate_label" = "Päättyy";
|
||||
"due_label" = "Määräpäivä:";
|
||||
"location_label" = "Sijainti:";
|
||||
"location_label" = "Sijainti";
|
||||
"summary_label" = "Yhteenveto:";
|
||||
"comment_label" = "Kommentti:";
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Tâche confidentielle)";
|
||||
"The event \"%{Summary}\" was created" = "L'événement «%{Summary}» a été créé";
|
||||
"The event \"%{Summary}\" was deleted" = "L'événement «%{Summary}» a été effacé";
|
||||
"The event \"%{Summary}\" was updated" = "L'événement «%{Summary}» a été modifié";
|
||||
"The following attendees(s) were notified:" = "Les invités suivants ont été avisés :";
|
||||
"The following attendees(s) were added:" = "Les invités suivants ont été ajoutés :";
|
||||
"The following attendees(s) were removed:" = "Les invités suivants ont été supprimés :";
|
||||
"The following attendees(s) were notified" = "Les invités suivants ont été avisés ";
|
||||
"The following attendees(s) were added" = "Les invités suivants ont été ajoutés ";
|
||||
"The following attendees(s) were removed" = "Les invités suivants ont été supprimés ";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Agenda :";
|
||||
"startDate_label" = "Début :";
|
||||
"endDate_label" = "Fin :";
|
||||
"calendar_label" = "Agenda ";
|
||||
"startDate_label" = "Début ";
|
||||
"endDate_label" = "Fin ";
|
||||
"due_label" = "Fin prévue :";
|
||||
"location_label" = "Lieu :";
|
||||
"location_label" = "Lieu ";
|
||||
"summary_label" = "Titre :";
|
||||
"comment_label" = "Description :";
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ Appointments_RESOURCE_FILES += \
|
||||
MSExchangeFreeBusySOAPResponseMap.plist \
|
||||
MSExchangeFreeBusySOAPRequest.wo
|
||||
|
||||
Appointments_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
||||
Appointments_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan ChineseTaiwan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak Slovenian SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
||||
|
||||
Appointments_LOCALIZED_RESOURCE_FILES = Localizable.strings
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Vertrauliche Aufgabe)";
|
||||
"The event \"%{Summary}\" was created" = "Der Termin \"%{Summary}\" wurde angelegt";
|
||||
"The event \"%{Summary}\" was deleted" = "Der Termin \"%{Summary}\" wurde gelöscht";
|
||||
"The event \"%{Summary}\" was updated" = "Der Termin \"%{Summary}\" wurde geändert";
|
||||
"The following attendees(s) were notified:" = "Die folgenden Teilnehmer wurden benachrichtigt:";
|
||||
"The following attendees(s) were added:" = "Die folgenden Teilnehmer wurden hinzugefügt:";
|
||||
"The following attendees(s) were removed:" = "Die folgenden Teilnehmer wurden entfernt:";
|
||||
"The following attendees(s) were notified" = "Die folgenden Teilnehmer wurden benachrichtigt";
|
||||
"The following attendees(s) were added" = "Die folgenden Teilnehmer wurden hinzugefügt";
|
||||
"The following attendees(s) were removed" = "Die folgenden Teilnehmer wurden entfernt";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Kalender:";
|
||||
"startDate_label" = "Beginn:";
|
||||
"endDate_label" = "Ende:";
|
||||
"calendar_label" = "Kalender";
|
||||
"startDate_label" = "Beginn";
|
||||
"endDate_label" = "Ende";
|
||||
"due_label" = "Fälligkeit:";
|
||||
"location_label" = "Ort:";
|
||||
"location_label" = "Ort";
|
||||
"summary_label" = "Zusammenfassung:";
|
||||
"comment_label" = "Kommentar:";
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Bizalmas feladat)";
|
||||
"The event \"%{Summary}\" was created" = "A \"%{Summary}\" esemény létre lett hozva";
|
||||
"The event \"%{Summary}\" was deleted" = "A \"%{Summary}\" esemény törölve lett";
|
||||
"The event \"%{Summary}\" was updated" = "A \"%{Summary}\" esemény módosítva lett";
|
||||
"The following attendees(s) were notified:" = "Az alábbi résztvevők lettek értesítve:";
|
||||
"The following attendees(s) were added:" = "Az alábbi résztvevők lettek hozzáadva:";
|
||||
"The following attendees(s) were removed:" = "Az alábbi résztvevők lettek eltávolítva:";
|
||||
"The following attendees(s) were notified" = "Az alábbi résztvevők lettek értesítve";
|
||||
"The following attendees(s) were added" = "Az alábbi résztvevők lettek hozzáadva";
|
||||
"The following attendees(s) were removed" = "Az alábbi résztvevők lettek eltávolítva";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Naptár:";
|
||||
"startDate_label" = "Kezdete:";
|
||||
"endDate_label" = "Vége:";
|
||||
"calendar_label" = "Naptár";
|
||||
"startDate_label" = "Kezdete";
|
||||
"endDate_label" = "Vége";
|
||||
"due_label" = "Lejárat napja:";
|
||||
"location_label" = "Hely:";
|
||||
"location_label" = "Hely";
|
||||
"summary_label" = "Összegzés:";
|
||||
"comment_label" = "Megjegyzés:";
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ vtodo_class2 = "(Verkefni er trúnaðarmál)";
|
||||
"... from the following event:" = "... af eftirfarandi viðburði:";
|
||||
|
||||
/* IMIP messages */
|
||||
"startDate_label" = "Byrjun:";
|
||||
"endDate_label" = "Endir:";
|
||||
"startDate_label" = "Byrjun";
|
||||
"endDate_label" = "Endir";
|
||||
"due_label" = "Lokadagur:";
|
||||
"location_label" = "Staðsetning:";
|
||||
"location_label" = "Staðsetning";
|
||||
"summary_label" = "Samantekt:";
|
||||
"comment_label" = "Athugasemd:";
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ vtodo_class2 = "(Attività confidenziale)";
|
||||
"... from the following event:" = "... dal seguente evento:";
|
||||
|
||||
/* IMIP messages */
|
||||
"startDate_label" = "Inizio:";
|
||||
"endDate_label" = "Fine:";
|
||||
"startDate_label" = "Inizio";
|
||||
"endDate_label" = "Fine";
|
||||
"due_label" = "Scadenza:";
|
||||
"location_label" = "Luogo:";
|
||||
"location_label" = "Luogo";
|
||||
"summary_label" = "Summario:";
|
||||
"comment_label" = "Commento:";
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Konfidensiell oppgave)";
|
||||
"The event \"%{Summary}\" was created" = "Hendelsen \"%{Summary}\" ble opprettet";
|
||||
"The event \"%{Summary}\" was deleted" = "Hendelsen \"%{Summary}\" ble slettet";
|
||||
"The event \"%{Summary}\" was updated" = "Hendelsen \"%{Summary}\" ble oppdatert";
|
||||
"The following attendees(s) were notified:" = "Følgende deltaker(e) ble varslet:";
|
||||
"The following attendees(s) were added:" = "Følgende deltaker(e) ble lagt til:";
|
||||
"The following attendees(s) were removed:" = "Følgende deltaker(e) ble fjernet:";
|
||||
"The following attendees(s) were notified" = "Følgende deltaker(e) ble varslet";
|
||||
"The following attendees(s) were added" = "Følgende deltaker(e) ble lagt til";
|
||||
"The following attendees(s) were removed" = "Følgende deltaker(e) ble fjernet";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Kalender:";
|
||||
"startDate_label" = "Start:";
|
||||
"endDate_label" = "Slutt:";
|
||||
"calendar_label" = "Kalender";
|
||||
"startDate_label" = "Start";
|
||||
"endDate_label" = "Slutt";
|
||||
"due_label" = "Forfallsdato:";
|
||||
"location_label" = "Sted:";
|
||||
"location_label" = "Sted";
|
||||
"summary_label" = "Sammendrag:";
|
||||
"comment_label" = "Kommentar:";
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ vtodo_class2 = "(Konfidensiell oppgave)";
|
||||
"... from the following event:" = "... fra følgende hendelse:";
|
||||
|
||||
/* IMIP messages */
|
||||
"startDate_label" = "Start:";
|
||||
"endDate_label" = "End:";
|
||||
"startDate_label" = "Start";
|
||||
"endDate_label" = "End";
|
||||
"due_label" = "Due Date:";
|
||||
"location_label" = "Location:";
|
||||
"location_label" = "Location";
|
||||
"summary_label" = "Summary:";
|
||||
"comment_label" = "Comment:";
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Zadanie poufne)";
|
||||
"The event \"%{Summary}\" was created" = "Utworzono wydarzenie \"%{Summary}\"";
|
||||
"The event \"%{Summary}\" was deleted" = "Skasowano wydarzenie \"%{Summary}\"";
|
||||
"The event \"%{Summary}\" was updated" = "Zaktualizowano wydarzenie \"%{Summary}\"";
|
||||
"The following attendees(s) were notified:" = "Następujący uczestnicy zostali powiadomieni:";
|
||||
"The following attendees(s) were added:" = "Następujący uczestnicy zostali dodani:";
|
||||
"The following attendees(s) were removed:" = "Następujący uczestnicy zostali usunięci:";
|
||||
"The following attendees(s) were notified" = "Następujący uczestnicy zostali powiadomieni";
|
||||
"The following attendees(s) were added" = "Następujący uczestnicy zostali dodani";
|
||||
"The following attendees(s) were removed" = "Następujący uczestnicy zostali usunięci";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Kalendarz:";
|
||||
"startDate_label" = "Początek:";
|
||||
"endDate_label" = "Koniec:";
|
||||
"calendar_label" = "Kalendarz";
|
||||
"startDate_label" = "Początek";
|
||||
"endDate_label" = "Koniec";
|
||||
"due_label" = "Termin:";
|
||||
"location_label" = "Miejsce:";
|
||||
"location_label" = "Miejsce";
|
||||
"summary_label" = "Podsumowanie:";
|
||||
"comment_label" = "Komentarz:";
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Конфиденциальная задача)";
|
||||
"The event \"%{Summary}\" was created" = "Было создано мероприятие \"%{Summary}\"";
|
||||
"The event \"%{Summary}\" was deleted" = "Мероприятие \"%{Summary}\" было удалено";
|
||||
"The event \"%{Summary}\" was updated" = "Мероприятие \"%{Summary}\" было обновлено";
|
||||
"The following attendees(s) were notified:" = "Следующие приглашенные были оповещены:";
|
||||
"The following attendees(s) were added:" = "Следующие люди были добавлены в список приглашенных:";
|
||||
"The following attendees(s) were removed:" = "Следующие люди были исключены из списка приглашенных:";
|
||||
"The following attendees(s) were notified" = "Следующие приглашенные были оповещены";
|
||||
"The following attendees(s) were added" = "Следующие люди были добавлены в список приглашенных";
|
||||
"The following attendees(s) were removed" = "Следующие люди были исключены из списка приглашенных";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Календарь:";
|
||||
"startDate_label" = "Начало:";
|
||||
"endDate_label" = "Конец:";
|
||||
"calendar_label" = "Календарь";
|
||||
"startDate_label" = "Начало";
|
||||
"endDate_label" = "Конец";
|
||||
"due_label" = "Должно быть готово к:";
|
||||
"location_label" = "Местонахождение:";
|
||||
"location_label" = "Местонахождение";
|
||||
"summary_label" = "Краткое содержание:";
|
||||
"comment_label" = "Комментарий:";
|
||||
|
||||
|
||||
@@ -2980,7 +2980,10 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
|
||||
theUser = [SOGoUser userWithLogin: theUID];
|
||||
aParent = [theUser calendarsFolderInContext: context];
|
||||
|
||||
|
||||
if ([aParent isKindOfClass: [NSException class]])
|
||||
return nil;
|
||||
|
||||
aFolders = [aParent subFolders];
|
||||
e = [aFolders objectEnumerator];
|
||||
while ((aFolder = [e nextObject]))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2007-2014 Inverse inc.
|
||||
Copyright (C) 2007-2015 Inverse inc.
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOGo
|
||||
@@ -317,7 +317,7 @@
|
||||
enumerator = [attendees objectEnumerator];
|
||||
while ((currentAttendee = [enumerator nextObject]))
|
||||
{
|
||||
currentUID = [currentAttendee uid];
|
||||
currentUID = [currentAttendee uidInContext: context];
|
||||
if (currentUID)
|
||||
[self _removeEventFromUID: currentUID
|
||||
owner: owner
|
||||
@@ -398,7 +398,7 @@
|
||||
enumerator = [updateAttendees objectEnumerator];
|
||||
while ((currentAttendee = [enumerator nextObject]))
|
||||
{
|
||||
currentUID = [currentAttendee uid];
|
||||
currentUID = [currentAttendee uidInContext: context];
|
||||
if (currentUID)
|
||||
[self _addOrUpdateEvent: newEvent
|
||||
forUID: currentUID
|
||||
@@ -438,7 +438,7 @@
|
||||
|
||||
while ((currentAttendee = [enumerator nextObject]))
|
||||
{
|
||||
currentUID = [currentAttendee uid];
|
||||
currentUID = [currentAttendee uidInContext: context];
|
||||
|
||||
if (currentUID)
|
||||
{
|
||||
@@ -520,7 +520,7 @@
|
||||
enumerator = [theAttendees objectEnumerator];
|
||||
while ((currentAttendee = [enumerator nextObject]))
|
||||
{
|
||||
currentUID = [currentAttendee uid];
|
||||
currentUID = [currentAttendee uidInContext: context];
|
||||
if (currentUID)
|
||||
{
|
||||
[attendees addObject: currentUID];
|
||||
@@ -635,7 +635,7 @@
|
||||
for (i = 0; i < [theAttendees count]; i++)
|
||||
{
|
||||
currentAttendee = [theAttendees objectAtIndex: i];
|
||||
if ([[currentAttendee uid] isEqualToString: currentUID])
|
||||
if ([[currentAttendee uidInContext: context] isEqualToString: currentUID])
|
||||
break;
|
||||
else
|
||||
currentAttendee = nil;
|
||||
@@ -713,7 +713,7 @@
|
||||
enumerator = [attendees objectEnumerator];
|
||||
while ((currentAttendee = [enumerator nextObject]))
|
||||
{
|
||||
currentUID = [currentAttendee uid];
|
||||
currentUID = [currentAttendee uidInContext: context];
|
||||
if (currentUID)
|
||||
[self _addOrUpdateEvent: newEvent
|
||||
forUID: currentUID
|
||||
@@ -838,7 +838,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
enumerator = [updatedAttendees objectEnumerator];
|
||||
while ((currentAttendee = [enumerator nextObject]))
|
||||
{
|
||||
currentUID = [currentAttendee uid];
|
||||
currentUID = [currentAttendee uidInContext: context];
|
||||
if (currentUID)
|
||||
[self _addOrUpdateEvent: newEvent
|
||||
forUID: currentUID
|
||||
@@ -1215,7 +1215,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
{
|
||||
[delegates addObject: otherDelegate];
|
||||
|
||||
delegatedUID = [otherDelegate uid];
|
||||
delegatedUID = [otherDelegate uidInContext: context];
|
||||
if (delegatedUID)
|
||||
// Delegate attendee is a local user; remove event from their calendar
|
||||
[self _removeEventFromUID: delegatedUID
|
||||
@@ -1244,7 +1244,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
|
||||
if (addDelegate)
|
||||
{
|
||||
delegatedUID = [delegate uid];
|
||||
delegatedUID = [delegate uidInContext: context];
|
||||
delegates = [NSArray arrayWithObject: delegate];
|
||||
[event addToAttendees: delegate];
|
||||
|
||||
@@ -1271,11 +1271,11 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
[self sendResponseToOrganizer: event
|
||||
from: ownerUser];
|
||||
|
||||
organizerUID = [[event organizer] uid];
|
||||
organizerUID = [[event organizer] uidInContext: context];
|
||||
|
||||
// Event is an exception to a recurring event; retrieve organizer from master event
|
||||
if (!organizerUID)
|
||||
organizerUID = [[(iCalEntityObject*)[[event parent] firstChildWithTag: [self componentTag]] organizer] uid];
|
||||
organizerUID = [[(iCalEntityObject*)[[event parent] firstChildWithTag: [self componentTag]] organizer] uidInContext: context];
|
||||
|
||||
if (organizerUID)
|
||||
// Update the attendee in organizer's calendar.
|
||||
@@ -1302,7 +1302,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
for (i = 0; i < [attendees count]; i++)
|
||||
{
|
||||
att = [attendees objectAtIndex: i];
|
||||
uid = [att uid];
|
||||
uid = [att uidInContext: context];
|
||||
if (uid && att != attendee && ![uid isEqualToString: delegatedUID])
|
||||
[self _updateAttendee: attendee
|
||||
withDelegate: delegate
|
||||
@@ -1461,7 +1461,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
{
|
||||
if (delegate && ![[delegate email] isEqualToString: [attendee delegatedTo]])
|
||||
{
|
||||
delegatedUid = [delegate uid];
|
||||
delegatedUid = [delegate uidInContext: context];
|
||||
if (delegatedUid)
|
||||
delegatedUser = [SOGoUser userWithLogin: delegatedUid];
|
||||
if (delegatedUser != nil && [event userIsOrganizer: delegatedUser])
|
||||
@@ -1831,7 +1831,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
|
||||
// We now make sure that the organizer, if managed by SOGo, is using
|
||||
// its default email when creating events and inviting attendees.
|
||||
uid = [[SOGoUserManager sharedUserManager] getUIDForEmail: [[event organizer] rfc822Email]];
|
||||
uid = [[event organizer] uidInContext: context];
|
||||
if (uid)
|
||||
{
|
||||
NSDictionary *defaultIdentity;
|
||||
@@ -2131,32 +2131,23 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
|
||||
//
|
||||
if ([[newEvent attendees] count] || [[oldEvent attendees] count])
|
||||
{
|
||||
NSString *uid;
|
||||
|
||||
BOOL userIsOrganizer;
|
||||
|
||||
// newEvent might be nil here, if we're deleting a RECURRENCE-ID with attendees
|
||||
// If that's the case, we use the oldEvent for now just to obtain the organizer
|
||||
// and we'll swap it back to nil once we're done.
|
||||
if (!newEvent)
|
||||
newEvent = oldEvent;
|
||||
|
||||
// We fetch the organizer's uid. Sometimes, the recurrence-id will
|
||||
// have it, sometimes not. If it doesn't, we fetch it from the master event.
|
||||
uid = [[newEvent organizer] uid];
|
||||
|
||||
if (!uid && !recurrenceId)
|
||||
uid = [[[[[newEvent parent] events] objectAtIndex: 0] organizer] uid];
|
||||
|
||||
// If that's the case, we use the oldEvent to obtain the organizer
|
||||
if (newEvent)
|
||||
userIsOrganizer = [newEvent userIsOrganizer: ownerUser];
|
||||
else
|
||||
userIsOrganizer = [oldEvent userIsOrganizer: ownerUser];
|
||||
|
||||
// With Thunderbird 10, if you create a recurring event with an exception
|
||||
// occurence, and invite someone, the PUT will have the organizer in the
|
||||
// recurrence-id and not in the master event. We must fix this, otherwise
|
||||
// SOGo will break.
|
||||
if (!recurrenceId && ![[[[[newEvent parent] events] objectAtIndex: 0] organizer] uid])
|
||||
if (!recurrenceId && ![[[[[newEvent parent] events] objectAtIndex: 0] organizer] uidInContext: context])
|
||||
[[[[newEvent parent] events] objectAtIndex: 0] setOrganizer: [newEvent organizer]];
|
||||
|
||||
if (newEvent == oldEvent)
|
||||
newEvent = nil;
|
||||
|
||||
if (uid && [uid caseInsensitiveCompare: owner] == NSOrderedSame)
|
||||
|
||||
if (userIsOrganizer)
|
||||
{
|
||||
// A RECCURENCE-ID was removed
|
||||
if (!newEvent && oldEvent)
|
||||
|
||||
@@ -11,16 +11,16 @@ vtodo_class2 = "(Dôverná úloha)";
|
||||
"The event \"%{Summary}\" was created" = "Udalosť \"%{Summary}\" bola vytvorená";
|
||||
"The event \"%{Summary}\" was deleted" = "Udalosť \"%{Summary}\" bola vymazaná";
|
||||
"The event \"%{Summary}\" was updated" = "Udalosť \"%{Summary}\" bola aktualizovaná";
|
||||
"The following attendees(s) were notified:" = "Nasledujúci účastník(ci) bol upozornený:";
|
||||
"The following attendees(s) were added:" = "Nasledujúci účastník(ci) bol pridaný:";
|
||||
"The following attendees(s) were removed:" = "Nasledujúci účastník(ci) bol odstránený:";
|
||||
"The following attendees(s) were notified" = "Nasledujúci účastník(ci) bol upozornený";
|
||||
"The following attendees(s) were added" = "Nasledujúci účastník(ci) bol pridaný";
|
||||
"The following attendees(s) were removed" = "Nasledujúci účastník(ci) bol odstránený";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Kalendár:";
|
||||
"startDate_label" = "Začiatok:";
|
||||
"endDate_label" = "Koniec:";
|
||||
"calendar_label" = "Kalendár";
|
||||
"startDate_label" = "Začiatok";
|
||||
"endDate_label" = "Koniec";
|
||||
"due_label" = "Platnosť:";
|
||||
"location_label" = "Miesto:";
|
||||
"location_label" = "Miesto";
|
||||
"summary_label" = "Zhrnutie:";
|
||||
"comment_label" = "Komentár:";
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
"Inviting the following persons is prohibited:" = "Povabilo za naslednje osebe je prepovedano:";
|
||||
"Personal Calendar" = "Osebni koledar";
|
||||
vevent_class0 = "(Javni dogodek)";
|
||||
vevent_class1 = "(Osebni dogodek)";
|
||||
vevent_class2 = "(Zaupni dogodek)";
|
||||
|
||||
vtodo_class0 = "(Javno opravilo)";
|
||||
vtodo_class1 = "(Osebno opravilo)";
|
||||
vtodo_class2 = "(Zaupno opravilo)";
|
||||
|
||||
/* Receipts */
|
||||
"The event \"%{Summary}\" was created" = "Dogodek \"%{Summary}\" je bil ustvarjen";
|
||||
"The event \"%{Summary}\" was deleted" = "Dogodek \"%{Summary}\" je bil izbrisan";
|
||||
"The event \"%{Summary}\" was updated" = "Dogodek \"%{Summary}\" je bil posodobljen";
|
||||
"The following attendees(s) were notified" = "Naslednji udeleženci so bili obveščeni";
|
||||
"The following attendees(s) were added" = "Naslednji udeleženci so bili dodani";
|
||||
"The following attendees(s) were removed" = "Naslednji udeleženci so bili odstranjeni";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Koledar";
|
||||
"startDate_label" = "Začetek";
|
||||
"endDate_label" = "Konec";
|
||||
"due_label" = "Datum zapadlosti:";
|
||||
"location_label" = "Mesto";
|
||||
"summary_label" = "Povzetek:";
|
||||
"comment_label" = "Komentar:";
|
||||
|
||||
/* Invitation */
|
||||
"Event Invitation: \"%{Summary}\"" = "Povabila na dogodek: \"%{Summary}\"";
|
||||
"(sent by %{SentBy}) " = "(posladno od %{SentBy})";
|
||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText} te je povabil na %{Summary}.\n\n\nZačetek: %{StartDate}\nKonec: %{EndDate}\nOpis: %{Description}";
|
||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText} te je povabil na %{Summary}.\n\n\nZačetek: %{StartDate} at %{StartTime}\nKonec: %{EndDate} at %{EndTime}\nOpis: %{Description}";
|
||||
|
||||
/* Deletion */
|
||||
"Event Cancelled: \"%{Summary}\"" = "Dogodek odpovedan: \"%{Summary}\"";
|
||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
|
||||
= "%{Organizer} %{SentByText} je odpovedal ta dogodek: %{Summary}.\n\n\nZačetek: %{StartDate}\nKonec: %{EndDate}\nOpis: %{Description}";
|
||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
|
||||
= "%{Organizer} %{SentByText} je odpovedal ta dogodek: %{Summary}.\n\n\nZačetek: %{StartDate} at %{StartTime}\nKonec: %{EndDate} at %{EndTime}\nOpis: %{Description}";
|
||||
|
||||
/* Update */
|
||||
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
|
||||
= "Sestanek \"%{Summary}\" za %{OldStartDate} se je spremenil";
|
||||
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
|
||||
= "Sestanek \"%{Summary}\" za %{OldStartDate} at %{OldStartTime} se je spremenil";
|
||||
"The following parameters have changed in the \"%{Summary}\" meeting:"
|
||||
= "Naslednji parametri so se spremenil v \"%{Summary}\" srečanju:";
|
||||
"Please accept or decline those changes."
|
||||
= "Prosim sprejmi ali zavrni te spremembe.";
|
||||
|
||||
/* Reply */
|
||||
"Accepted invitation: \"%{Summary}\"" = "Sprejeto povabilo: \"%{Summary}\"";
|
||||
"Declined invitation: \"%{Summary}\"" = "Zavrnjeno povabilo: \"%{Summary}\"";
|
||||
"Delegated invitation: \"%{Summary}\"" = "Dodeljeno povabilo: \"%{Summary}\"";
|
||||
"Not yet decided on invitation: \"%{Summary}\"" = "Še neodločeno glede povabila: \"%{Summary}\"";
|
||||
"%{Attendee} %{SentByText}has accepted your event invitation."
|
||||
= "%{Attendee} %{SentByText} je sprejel tvoje povabilo.";
|
||||
"%{Attendee} %{SentByText}has declined your event invitation."
|
||||
= "%{Attendee} %{SentByText} je zavrnil tvoje povabilo.";
|
||||
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
|
||||
= "%{Attendee} %{SentByText} je posredoval povabilo k %{Delegate}.";
|
||||
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
|
||||
= "%{Attendee} %{SentByText} se še ni odločil glede tvojega povabila.";
|
||||
|
||||
/* Resources */
|
||||
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "Ne morem dostopati do vira: \"%{Cn} %{SystemEmail}\"";
|
||||
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "Doseženo je največje število sočasnih rezervacij (%{NumberOfSimultaneousBookings}) za vir \"%{Cn} %{SystemEmail}\". Konfliktni dogodek je \"%{EventTitle}\", začel se je %{StartDate}.";
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Tarea confidencial)";
|
||||
"The event \"%{Summary}\" was created" = "Se creó el evento \"%{Summary}\"";
|
||||
"The event \"%{Summary}\" was deleted" = "Se borró el evento \"%{Summary}\"";
|
||||
"The event \"%{Summary}\" was updated" = "Se actualizó la información del evento \"%{Summary}\"";
|
||||
"The following attendees(s) were notified:" = "Se notificó a los siguientes participantes:";
|
||||
"The following attendees(s) were added:" = "Se agregaron los siguientes participantes:";
|
||||
"The following attendees(s) were removed:" = "Se removieron los siguientes participantes:";
|
||||
"The following attendees(s) were notified" = "Se notificó a los siguientes participantes";
|
||||
"The following attendees(s) were added" = "Se agregaron los siguientes participantes";
|
||||
"The following attendees(s) were removed" = "Se removieron los siguientes participantes";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Calendario:";
|
||||
"startDate_label" = "Inicio:";
|
||||
"endDate_label" = "Fin:";
|
||||
"calendar_label" = "Calendario";
|
||||
"startDate_label" = "Inicio";
|
||||
"endDate_label" = "Fin";
|
||||
"due_label" = "Fecha de finalización:";
|
||||
"location_label" = "Lugar:";
|
||||
"location_label" = "Lugar";
|
||||
"summary_label" = "Resumen:";
|
||||
"comment_label" = "Comentario:";
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ vtodo_class2 = "(Tarea confidencial)";
|
||||
"The event \"%{Summary}\" was created" = "El evento \"%{Summary}\" ha sido creado";
|
||||
"The event \"%{Summary}\" was deleted" = "El evento \"%{Summary}\" ha sido borrado";
|
||||
"The event \"%{Summary}\" was updated" = "El evento \"%{Summary}\" ha sido actualizado";
|
||||
"The following attendees(s) were notified:" = "Los invitados siguientes han sido notificado:";
|
||||
"The following attendees(s) were added:" = "Los invitados siguientes han sido añadido:";
|
||||
"The following attendees(s) were removed:" = "Los invitados siguientes han sido quitado:";
|
||||
"The following attendees(s) were notified" = "Los invitados siguientes han sido notificado";
|
||||
"The following attendees(s) were added" = "Los invitados siguientes han sido añadido";
|
||||
"The following attendees(s) were removed" = "Los invitados siguientes han sido quitado";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Calendario:";
|
||||
"startDate_label" = "Inicio:";
|
||||
"endDate_label" = "Fin:";
|
||||
"calendar_label" = "Calendario";
|
||||
"startDate_label" = "Inicio";
|
||||
"endDate_label" = "Fin";
|
||||
"due_label" = "Fecha Fin:";
|
||||
"location_label" = "Localización:";
|
||||
"location_label" = "Localización";
|
||||
"summary_label" = "Resumen:";
|
||||
"comment_label" = "Comentario:";
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ vtodo_class2 = "(Konfidentiell uppgift)";
|
||||
"... from the following event:" = "... från följande händelse:";
|
||||
|
||||
/* IMIP messages */
|
||||
"startDate_label" = "Startdatum:";
|
||||
"endDate_label" = "Slutdatum:";
|
||||
"startDate_label" = "Startdatum";
|
||||
"endDate_label" = "Slutdatum";
|
||||
"due_label" = "Datum:";
|
||||
"location_label" = "Plats:";
|
||||
"location_label" = "Plats";
|
||||
"summary_label" = "Sammanfattning:";
|
||||
"comment_label" = "Kommentar:";
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ vtodo_class2 = "(Конфіденційне завдання)";
|
||||
"... from the following event:" = "... з участі в події:";
|
||||
|
||||
/* IMIP messages */
|
||||
"startDate_label" = "Початок:";
|
||||
"endDate_label" = "Кінець:";
|
||||
"startDate_label" = "Початок";
|
||||
"endDate_label" = "Кінець";
|
||||
"due_label" = "Триватиме до:";
|
||||
"location_label" = "Місце:";
|
||||
"location_label" = "Місце";
|
||||
"summary_label" = "Резюме:";
|
||||
"comment_label" = "Коментар:";
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ vtodo_class2 = "(Tasg gyfrinachol)";
|
||||
"... from the following event:" = "... from the following event:";
|
||||
|
||||
/* IMIP messages */
|
||||
"startDate_label" = "Start:";
|
||||
"endDate_label" = "End:";
|
||||
"startDate_label" = "Start";
|
||||
"endDate_label" = "End";
|
||||
"due_label" = "Due Date:";
|
||||
"location_label" = "Location:";
|
||||
"location_label" = "Location";
|
||||
"summary_label" = "Summary:";
|
||||
"comment_label" = "Comment:";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* iCalAlarm+SOGo.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2014 Inverse inc.
|
||||
* Copyright (C) 2015 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
|
||||
@@ -20,11 +20,11 @@
|
||||
|
||||
#import <NGCards/iCalAlarm.h>
|
||||
|
||||
@class iCalRepeatableEntityObject;
|
||||
@class iCalEntityObject;
|
||||
|
||||
@interface iCalAlarm (SOGoExtensions)
|
||||
|
||||
+ (id) alarmForEvent: (iCalRepeatableEntityObject *) theEntity
|
||||
+ (id) alarmForEvent: (iCalEntityObject *) theEntity
|
||||
owner: (NSString *) theOwner
|
||||
action: (NSString *) reminderAction
|
||||
unit: (NSString *) reminderUnit
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* iCalAlarm+SOGo.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2014 Inverse inc.
|
||||
* Copyright (C) 2015 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
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
#import <NGCards/iCalEntityObject.h>
|
||||
|
||||
@implementation iCalAlarm (SOGoExtensions)
|
||||
|
||||
@@ -65,7 +66,7 @@
|
||||
[alarm addChild: aAttendee];
|
||||
}
|
||||
|
||||
+ (id) alarmForEvent: (iCalRepeatableEntityObject *) theEntity
|
||||
+ (id) alarmForEvent: (iCalEntityObject *) theEntity
|
||||
owner: (NSString *) theOwner
|
||||
action: (NSString *) reminderAction
|
||||
unit: (NSString *) reminderUnit
|
||||
|
||||
@@ -184,16 +184,17 @@ NSNumber *iCalDistantFutureNumber = nil;
|
||||
NSArray *oldAttendees;
|
||||
unsigned int count, max;
|
||||
iCalPerson *currentAttendee;
|
||||
NSString *userID;
|
||||
NSString *userID, *domain;
|
||||
|
||||
userID = [user login];
|
||||
domain = [user domain];
|
||||
oldAttendees = [self attendees];
|
||||
max = [oldAttendees count];
|
||||
newAttendees = [NSMutableArray arrayWithCapacity: max];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
currentAttendee = [oldAttendees objectAtIndex: count];
|
||||
if (![[currentAttendee uid] isEqualToString: userID])
|
||||
if (![[currentAttendee uidInDomain: domain] isEqualToString: userID])
|
||||
[newAttendees addObject: currentAttendee];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
/* iCalPerson+SOGo.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2012 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
* Copyright (C) 2007-2015 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,6 +29,8 @@
|
||||
|
||||
- (NSString *) mailAddress;
|
||||
- (NSString *) uid;
|
||||
- (NSString *) uidInDomain: (NSString *) domain;
|
||||
- (NSString *) uidInContext: (WOContext *) context;
|
||||
- (NSString *) contactIDInContext: (WOContext *) context;
|
||||
- (BOOL) hasSentBy;
|
||||
- (NSString *) sentBy;
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
/* iCalPerson+SOGo.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2012 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
* Copyright (C) 2007-2015 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
|
||||
@@ -67,6 +64,31 @@ static SOGoUserManager *um = nil;
|
||||
return [um getUIDForEmail: [self rfc822Email]];
|
||||
}
|
||||
|
||||
- (NSString *) uidInContext: (WOContext *) context
|
||||
{
|
||||
NSString *domain;
|
||||
|
||||
domain = [[context activeUser] domain];
|
||||
|
||||
return [self uidInDomain: domain];
|
||||
}
|
||||
|
||||
- (NSString *) uidInDomain: (NSString *) domain
|
||||
{
|
||||
NSDictionary *contact;
|
||||
NSString *uid;
|
||||
|
||||
if (!um)
|
||||
um = [SOGoUserManager sharedUserManager];
|
||||
|
||||
uid = nil;
|
||||
contact = [um contactInfosForUserWithUIDorEmail: [self rfc822Email] inDomain: domain];
|
||||
if (contact)
|
||||
uid = [contact valueForKey: @"c_uid"];
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
- (NSString *) contactIDInContext: (WOContext *) context
|
||||
{
|
||||
NSString *domain, *uid;
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
"Personal Address Book" = "個人通訊錄";
|
||||
"Collected Address Book" = "公用通訊錄";
|
||||
@@ -27,7 +27,7 @@ Contacts_OBJC_FILES = \
|
||||
Contacts_RESOURCE_FILES += \
|
||||
product.plist \
|
||||
|
||||
Contacts_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
||||
Contacts_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan ChineseTaiwan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak Slovenian SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
||||
|
||||
Contacts_LOCALIZED_RESOURCE_FILES = Localizable.strings
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
"Personal Address Book" = "Osebni adresar";
|
||||
"Collected Address Book" = "Zbrani adresar";
|
||||
@@ -0,0 +1,2 @@
|
||||
"OtherUsersFolderName" = "其他使用者";
|
||||
"SharedFoldersName" = "共用資料匣";
|
||||
@@ -50,6 +50,8 @@ Mailer_RESOURCE_FILES += \
|
||||
SOGoMailBrazilianPortugueseReply.wo \
|
||||
SOGoMailCatalanForward.wo \
|
||||
SOGoMailCatalanReply.wo \
|
||||
SOGoMailChineseTaiwanForward.wo \
|
||||
SOGoMailChineseTaiwanReply.wo \
|
||||
SOGoMailCzechForward.wo \
|
||||
SOGoMailCzechReply.wo \
|
||||
SOGoMailDanishForward.wo \
|
||||
@@ -80,6 +82,8 @@ Mailer_RESOURCE_FILES += \
|
||||
SOGoMailRussianReply.wo \
|
||||
SOGoMailSlovakForward.wo \
|
||||
SOGoMailSlovakReply.wo \
|
||||
SOGoMailSlovenianForward.wo \
|
||||
SOGoMailSlovenianReply.wo \
|
||||
SOGoMailSpanishSpainForward.wo \
|
||||
SOGoMailSpanishSpainReply.wo \
|
||||
SOGoMailSpanishArgentinaForward.wo \
|
||||
@@ -91,8 +95,7 @@ Mailer_RESOURCE_FILES += \
|
||||
SOGoMailWelshForward.wo \
|
||||
SOGoMailWelshReply.wo
|
||||
|
||||
|
||||
Mailer_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
||||
Mailer_LANGUAGES = Arabic Basque BrazilianPortuguese ChineseTaiwan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovenian Slovenian SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
||||
|
||||
Mailer_LOCALIZED_RESOURCE_FILES = Localizable.strings
|
||||
|
||||
|
||||
@@ -86,12 +86,3 @@ signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
|
||||
signaturePlacementOnTop: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
}
|
||||
|
||||
signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<#newLine/>
|
||||
<#newLine/>
|
||||
<#signaturePlacementOnTop><#newLine/>
|
||||
<#signature/><#newLine/></#signaturePlacementOnTop>
|
||||
-------- 原始信件 --------<#newLine/>
|
||||
主旨: <#subject/><#newLine/>
|
||||
日期: <#date/><#newLine/>
|
||||
寄件者: <#from/><#newLine/>
|
||||
<#hasReplyTo>回覆帳號: <#replyTo/></#hasReplyTo><#hasOrganization>公司: <#organization/></#hasOrganization>收件者: <#to/><#newLine/>
|
||||
<#hasCc>副本: <#cc/></#hasCc><#hasNewsGroups>新聞群組: <#newsgroups/></#hasNewsGroups><#hasReferences>參考: <#references/></#hasReferences><#newLine/>
|
||||
<#newLine/>
|
||||
<#messageBody/><#newLine/>
|
||||
<#signaturePlacementOnBottom><#newLine/>
|
||||
<#newLine/>
|
||||
<#signature/></#signaturePlacementOnBottom>
|
||||
<#newLine/>
|
||||
@@ -0,0 +1,88 @@
|
||||
subject: WOString {
|
||||
value = subject;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
date: WOString {
|
||||
value = date;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
from: WOString {
|
||||
value = from;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
newLine: WOString {
|
||||
value = newLine;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReplyTo: WOConditional {
|
||||
condition = hasReplyTo;
|
||||
}
|
||||
|
||||
replyTo: WOString {
|
||||
value = replyTo;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasOrganization: WOConditional {
|
||||
condition = hasOrganization;
|
||||
}
|
||||
|
||||
organization: WOString {
|
||||
value = organization;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
to: WOString {
|
||||
value = to;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasCc: WOConditional {
|
||||
condition = hasCc;
|
||||
}
|
||||
|
||||
cc: WOString {
|
||||
value = cc;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasNewsGroups: WOConditional {
|
||||
condition = hasNewsGroups;
|
||||
}
|
||||
|
||||
newsgroups: WOString {
|
||||
value = newsgroups;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReferences: WOConditional {
|
||||
condition = hasReferences;
|
||||
}
|
||||
|
||||
references: WOString {
|
||||
value = references;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
messageBody: WOString {
|
||||
value = messageBody;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signature: WOString {
|
||||
value = signature;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signaturePlacementOnTop: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
}
|
||||
|
||||
signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<#replyPlacementOnTop><#newLine/>
|
||||
<#newLine/>
|
||||
</#replyPlacementOnTop><#signaturePlacementOnTop><#newLine/>
|
||||
<#signature/><#newLine/>
|
||||
</#signaturePlacementOnTop><#outlookMode>-------- 原始信件 --------<#newLine/>
|
||||
主旨: <#subject/><#newLine/>
|
||||
日期: <#date/><#newLine/>
|
||||
寄件者: <#from/><#newLine/>
|
||||
<#hasReplyTo>回覆帳號: <#replyTo/></#hasReplyTo><#hasOrganization>公司: <#organization/></#hasOrganization>收件者: <#to/><#newLine/>
|
||||
<#hasCc>副本: <#cc/></#hasCc><#hasNewsGroups>新聞群組: <#newsgroups/></#hasNewsGroups><#hasReferences>參考: <#references/></#hasReferences></#outlookMode><#newLine/>
|
||||
<#standardMode>日期 <#date/>, <#from/> 編輯:</#standardMode><#newLine/>
|
||||
<#newLine/>
|
||||
<#messageBody/><#newLine/>
|
||||
<#replyPlacementOnBottom><#newLine/>
|
||||
<#newLine/>
|
||||
</#replyPlacementOnBottom><#signaturePlacementOnBottom><#signature/></#signaturePlacementOnBottom><#newLine/>
|
||||
@@ -0,0 +1,106 @@
|
||||
outlookMode: WOConditional {
|
||||
condition = outlookMode;
|
||||
}
|
||||
|
||||
standardMode: WOConditional {
|
||||
condition = outlookMode;
|
||||
negate = YES;
|
||||
}
|
||||
|
||||
subject: WOString {
|
||||
value = subject;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
date: WOString {
|
||||
value = date;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
from: WOString {
|
||||
value = from;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
newLine: WOString {
|
||||
value = newLine;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReplyTo: WOConditional {
|
||||
condition = hasReplyTo;
|
||||
}
|
||||
|
||||
replyTo: WOString {
|
||||
value = replyTo;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasOrganization: WOConditional {
|
||||
condition = hasOrganization;
|
||||
}
|
||||
|
||||
organization: WOString {
|
||||
value = organization;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
to: WOString {
|
||||
value = to;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasCc: WOConditional {
|
||||
condition = hasCc;
|
||||
}
|
||||
|
||||
cc: WOString {
|
||||
value = cc;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasNewsGroups: WOConditional {
|
||||
condition = hasNewsGroups;
|
||||
}
|
||||
|
||||
newsgroups: WOString {
|
||||
value = newsgroups;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReferences: WOConditional {
|
||||
condition = hasReferences;
|
||||
}
|
||||
|
||||
references: WOString {
|
||||
value = references;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
messageBody: WOString {
|
||||
value = messageBody;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signature: WOString {
|
||||
value = signature;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
replyPlacementOnTop: WOConditional {
|
||||
condition = replyPlacementOnTop;
|
||||
}
|
||||
|
||||
replyPlacementOnBottom: WOConditional {
|
||||
condition = replyPlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
|
||||
signaturePlacementOnTop: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
}
|
||||
|
||||
signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
@@ -86,12 +86,3 @@ signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
|
||||
signaturePlacementOnTop: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
}
|
||||
|
||||
signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
@@ -98,7 +98,8 @@
|
||||
|
||||
- (NSArray *) syncTokenFieldsWithProperties: (NSDictionary *) properties
|
||||
matchingSyncToken: (NSString *) syncToken
|
||||
fromDate: (NSCalendarDate *) theStartDate;
|
||||
fromDate: (NSCalendarDate *) theStartDate
|
||||
initialLoad: (BOOL) initialLoadInProgress;
|
||||
|
||||
/* flags */
|
||||
|
||||
|
||||
@@ -1553,7 +1553,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
|
||||
- (NSString *) displayName
|
||||
{
|
||||
return [self relativeImap4Name];
|
||||
return [[self relativeImap4Name] stringByDecodingImap4FolderName];
|
||||
}
|
||||
|
||||
- (NSDictionary *) davIMAPFieldsTable
|
||||
@@ -2090,6 +2090,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
- (NSArray *) syncTokenFieldsWithProperties: (NSArray *) theProperties
|
||||
matchingSyncToken: (NSString *) theSyncToken
|
||||
fromDate: (NSCalendarDate *) theStartDate
|
||||
initialLoad: (BOOL) initialLoadInProgress
|
||||
{
|
||||
EOQualifier *searchQualifier;
|
||||
NSMutableArray *allTokens;
|
||||
@@ -2166,6 +2167,9 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
|
||||
for (i = 0; i < [fetchResults count]; i++)
|
||||
{
|
||||
if ([[[fetchResults objectAtIndex: i] objectForKey: @"flags"] containsObject: @"deleted"] && initialLoadInProgress)
|
||||
continue;
|
||||
|
||||
d = [NSDictionary dictionaryWithObject: ([[[fetchResults objectAtIndex: i] objectForKey: @"flags"] containsObject: @"deleted"]) ? [NSNull null] : [[fetchResults objectAtIndex: i] objectForKey: @"modseq"]
|
||||
forKey: [[[fetchResults objectAtIndex: i] objectForKey: @"uid"] stringValue]];
|
||||
[allTokens addObject: d];
|
||||
@@ -2176,7 +2180,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
if (highestmodseq == 0)
|
||||
highestmodseq = 1;
|
||||
|
||||
if (highestmodseq > 0)
|
||||
if (highestmodseq > 0 && !initialLoadInProgress)
|
||||
{
|
||||
id uid;
|
||||
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
@interface SOGoMailCatalanForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
@interface SOGoMailChineseTaiwanForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
@interface SOGoMailCzechForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
@@ -103,6 +106,9 @@
|
||||
@interface SOGoMailSlovakForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
@interface SOGoMailSlovenianForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
@interface SOGoMailUkrainianForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
|
||||
@@ -260,6 +260,9 @@
|
||||
@implementation SOGoMailCatalanForward
|
||||
@end
|
||||
|
||||
@implementation SOGoMailChineseTaiwanForward
|
||||
@end
|
||||
|
||||
@implementation SOGoMailCzechForward
|
||||
@end
|
||||
|
||||
@@ -314,6 +317,9 @@
|
||||
@implementation SOGoMailSlovakForward
|
||||
@end
|
||||
|
||||
@implementation SOGoMailSlovenianForward
|
||||
@end
|
||||
|
||||
@implementation SOGoMailUkrainianForward
|
||||
@end
|
||||
|
||||
|
||||
@@ -777,8 +777,6 @@ static BOOL debugSoParts = NO;
|
||||
filename = [NSString stringWithFormat: @"unknown_%@", path];
|
||||
else if ([mimeType isEqualToString: @"message/rfc822"])
|
||||
filename = [NSString stringWithFormat: @"email_%@.eml", path];
|
||||
else if ([mimeType isEqualToString: @"text/calendar"])
|
||||
filename = [NSString stringWithFormat: @"calendar_%@.ics", path];
|
||||
|
||||
|
||||
if (filename)
|
||||
|
||||
@@ -48,6 +48,9 @@
|
||||
@interface SOGoMailCatalanReply : SOGoMailReply
|
||||
@end
|
||||
|
||||
@interface SOGoMailChineseTaiwanReply : SOGoMailReply
|
||||
@end
|
||||
|
||||
@interface SOGoMailCzechReply : SOGoMailReply
|
||||
@end
|
||||
|
||||
@@ -102,6 +105,9 @@
|
||||
@interface SOGoMailSlovakReply : SOGoMailReply
|
||||
@end
|
||||
|
||||
@interface SOGoMailSlovenianReply : SOGoMailReply
|
||||
@end
|
||||
|
||||
@interface SOGoMailUkrainianReply : SOGoMailReply
|
||||
@end
|
||||
|
||||
|
||||
@@ -98,6 +98,9 @@
|
||||
@implementation SOGoMailCatalanReply
|
||||
@end
|
||||
|
||||
@implementation SOGoMailChineseTaiwanReply
|
||||
@end
|
||||
|
||||
@implementation SOGoMailCzechReply
|
||||
@end
|
||||
|
||||
@@ -152,6 +155,9 @@
|
||||
@implementation SOGoMailSlovakReply
|
||||
@end
|
||||
|
||||
@implementation SOGoMailSlovenianReply
|
||||
@end
|
||||
|
||||
@implementation SOGoMailUkrainianReply
|
||||
@end
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<#newLine/>
|
||||
<#newLine/>
|
||||
<#signaturePlacementOnTop><#newLine/>
|
||||
<#signature/><#newLine/></#signaturePlacementOnTop>
|
||||
-------- Original Message --------<#newLine/>
|
||||
Zadeva: <#subject/><#newLine/>
|
||||
Datum: <#date/><#newLine/>
|
||||
Od: <#from/><#newLine/>
|
||||
<#hasReplyTo>Odgovori: <#replyTo/></#hasReplyTo><#hasOrganization>Organizacija: <#organization/></#hasOrganization>Za: <#to/><#newLine/>
|
||||
<#hasCc>KP: <#cc/></#hasCc><#hasNewsGroups>Novicarske skupine: <#newsgroups/></#hasNewsGroups><#hasReferences>Reference: <#references/></#hasReferences><#newLine/>
|
||||
<#newLine/>
|
||||
<#messageBody/><#newLine/>
|
||||
<#signaturePlacementOnBottom><#newLine/>
|
||||
<#newLine/>
|
||||
<#signature/></#signaturePlacementOnBottom>
|
||||
<#newLine/>
|
||||
@@ -0,0 +1,88 @@
|
||||
subject: WOString {
|
||||
value = subject;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
date: WOString {
|
||||
value = date;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
from: WOString {
|
||||
value = from;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
newLine: WOString {
|
||||
value = newLine;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReplyTo: WOConditional {
|
||||
condition = hasReplyTo;
|
||||
}
|
||||
|
||||
replyTo: WOString {
|
||||
value = replyTo;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasOrganization: WOConditional {
|
||||
condition = hasOrganization;
|
||||
}
|
||||
|
||||
organization: WOString {
|
||||
value = organization;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
to: WOString {
|
||||
value = to;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasCc: WOConditional {
|
||||
condition = hasCc;
|
||||
}
|
||||
|
||||
cc: WOString {
|
||||
value = cc;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasNewsGroups: WOConditional {
|
||||
condition = hasNewsGroups;
|
||||
}
|
||||
|
||||
newsgroups: WOString {
|
||||
value = newsgroups;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReferences: WOConditional {
|
||||
condition = hasReferences;
|
||||
}
|
||||
|
||||
references: WOString {
|
||||
value = references;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
messageBody: WOString {
|
||||
value = messageBody;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signature: WOString {
|
||||
value = signature;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signaturePlacementOnTop: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
}
|
||||
|
||||
signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<#replyPlacementOnTop><#newLine/>
|
||||
<#newLine/>
|
||||
</#replyPlacementOnTop><#signaturePlacementOnTop><#newLine/>
|
||||
<#signature/><#newLine/>
|
||||
</#signaturePlacementOnTop><#outlookMode>-------- Izvorno sporocilo --------<#newLine/>
|
||||
Zadeva: <#subject/><#newLine/>
|
||||
Datum: <#date/><#newLine/>
|
||||
Od: <#from/><#newLine/>
|
||||
<#hasReplyTo>Odgovori: <#replyTo/></#hasReplyTo><#hasOrganization>Organizacija: <#organization/></#hasOrganization>Za: <#to/><#newLine/>
|
||||
<#hasCc>KP: <#cc/></#hasCc><#hasNewsGroups>Novicarske skupine: <#newsgroups/></#hasNewsGroups><#hasReferences>Reference: <#references/></#hasReferences></#outlookMode><#newLine/>
|
||||
<#standardMode>Dne <#date/>, je <#from/> napisal-a:</#standardMode><#newLine/>
|
||||
<#newLine/>
|
||||
<#messageBody/><#newLine/>
|
||||
<#replyPlacementOnBottom><#newLine/>
|
||||
<#newLine/>
|
||||
</#replyPlacementOnBottom><#signaturePlacementOnBottom><#signature/></#signaturePlacementOnBottom><#newLine/>
|
||||
@@ -0,0 +1,106 @@
|
||||
outlookMode: WOConditional {
|
||||
condition = outlookMode;
|
||||
}
|
||||
|
||||
standardMode: WOConditional {
|
||||
condition = outlookMode;
|
||||
negate = YES;
|
||||
}
|
||||
|
||||
subject: WOString {
|
||||
value = subject;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
date: WOString {
|
||||
value = date;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
from: WOString {
|
||||
value = from;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
newLine: WOString {
|
||||
value = newLine;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReplyTo: WOConditional {
|
||||
condition = hasReplyTo;
|
||||
}
|
||||
|
||||
replyTo: WOString {
|
||||
value = replyTo;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasOrganization: WOConditional {
|
||||
condition = hasOrganization;
|
||||
}
|
||||
|
||||
organization: WOString {
|
||||
value = organization;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
to: WOString {
|
||||
value = to;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasCc: WOConditional {
|
||||
condition = hasCc;
|
||||
}
|
||||
|
||||
cc: WOString {
|
||||
value = cc;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasNewsGroups: WOConditional {
|
||||
condition = hasNewsGroups;
|
||||
}
|
||||
|
||||
newsgroups: WOString {
|
||||
value = newsgroups;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReferences: WOConditional {
|
||||
condition = hasReferences;
|
||||
}
|
||||
|
||||
references: WOString {
|
||||
value = references;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
messageBody: WOString {
|
||||
value = messageBody;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signature: WOString {
|
||||
value = signature;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
replyPlacementOnTop: WOConditional {
|
||||
condition = replyPlacementOnTop;
|
||||
}
|
||||
|
||||
replyPlacementOnBottom: WOConditional {
|
||||
condition = replyPlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
|
||||
signaturePlacementOnTop: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
}
|
||||
|
||||
signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
Loaded 100 of 373 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user