Compare commits

..
Author SHA1 Message Date
Ludovic Marcotte 74b27a771a Merge to 2.2.14 2015-01-20 08:35:54 -05:00
Ludovic Marcotte 2ae326c41f Merge to 2.2.13 2014-12-30 08:01:52 -05:00
Ludovic Marcotte 562d3db1a6 Merge to 2.2.12a 2014-12-19 09:04:01 -05:00
Ludovic Marcotte d3914ae8a8 Merge to 2.2.12 2014-12-18 08:57:15 -05:00
Ludovic Marcotte 97135f2afa Merge to 2.2.11a 2014-12-10 15:24:12 -05:00
Ludovic Marcotte 3e14825fe2 Merge to 2.2.11a 2014-12-10 14:25:11 -05:00
Ludovic Marcotte 93d190060e Merge to 2.2.11 2014-12-09 09:09:58 -05:00
Ludovic Marcotte 1f299c7a1a Merge to 2.2.10
Conflicts:
	NEWS
	Version
2014-11-21 09:17:28 -05:00
Ludovic Marcotte 74cfb901fd Updated for the 2.2.9a release 2014-09-29 15:20:22 -04:00
Ludovic Marcotte 065fd5d9b5 Simplified even more -safeString 2014-09-29 15:17:05 -04:00
Ludovic Marcotte bf547dd3fe Fixed sanitization char skipping and #2936 2014-09-29 15:15:30 -04:00
Francis Lachapelle 81e47c59cd Fix URL in documentation 2014-09-29 15:15:23 -04:00
Ludovic Marcotte 7862cda661 Merge to 2.2.9 2014-09-26 14:32:47 -04:00
Ludovic Marcotte 329552030b Merge to 2.2.8 2014-09-10 14:17:14 -04:00
Ludovic Marcotte 04904d8c61 Merge to 2.2.6 2014-07-02 11:41:46 -04:00
Francis Lachapelle f0b4a05c70 Merge to 2.2.5 2014-06-05 13:35:45 -04:00
Francis Lachapelle 95d6911f1a Merge to 2.2.4 2014-05-29 11:17:46 -04:00
Francis Lachapelle 48f98ef34e Merge to 2.2.3 2014-04-03 10:06:08 -04:00
Francis Lachapelle ae0c5eae77 Merge to 2.2.2 2014-03-21 15:39:00 -04:00
Francis Lachapelle 0c2d727057 Merge to 2.2.2 2014-03-21 15:33:55 -04:00
Francis Lachapelle 072f5f5a15 Merge to 2.2.1 2014-03-07 14:03:41 -05:00
Francis Lachapelle 1db85743a0 Merge to 2.2.0 2014-02-24 16:54:11 -05:00
Jean Raby 2cf66e037d Merge to 2.1.1 2013-11-19 14:00:22 -05:00
Francis Lachapelle 449d838dc2 Merge to 2.1.0 2013-11-07 14:43:19 -05:00
Francis Lachapelle c4bc215a47 Merge to 2.0.7 2013-07-23 10:02:39 -04:00
Francis Lachapelle c9936d7ecf Merge to 2.0.7 2013-07-23 08:38:44 -04:00
Francis Lachapelle 885e59a2af Merge to 2.0.7 2013-07-19 13:46:37 -04:00
Jean Raby bf398889bf Merge to 2.0.6b 2013-06-27 11:36:30 -04:00
Ludovic Marcotte e26e3d7307 Revert "Properly escape the foldername to avoid XSS issues"
This reverts commit 045b275b27.
2013-06-27 11:15:41 -04:00
Ludovic Marcotte 045b275b27 Properly escape the foldername to avoid XSS issues 2013-06-27 11:06:07 -04:00
Jean Raby 7ec1973e0f Merge to 2.0.6a 2013-06-25 09:22:35 -04:00
Ludovic Marcotte a79a9c4eff Merge to 2.0.6
Conflicts:
	Documentation/SOGo Installation Guide.odt
2013-06-21 12:44:35 -04:00
Jean Raby f049e2430a Added ldap attribute mapping table 2013-04-22 12:25:22 -04:00
Jean Raby 59b3219f2d Merge to 2.05a 2013-04-16 15:20:19 -04:00
Francis Lachapelle e9eb8bdc86 Merge to 2.0.5 2013-04-11 12:56:34 -04:00
Francis Lachapelle 5e0c7ae4f2 Merge to 2.0.4b 2013-02-04 14:24:46 -05:00
Francis Lachapelle c1c0c1ab44 Merge to 2.0.4a 2013-01-30 08:54:00 -05:00
Francis Lachapelle a59fff785b Merge to 2.0.4 2013-01-25 14:01:10 -05:00
Francis Lachapelle 6a70db80e6 Merge to 2.0.3a 2012-12-07 09:35:03 -05:00
Francis Lachapelle d610630c8d Merge to 2.0.3 (again) 2012-12-06 13:08:47 -05:00
Francis Lachapelle 4dc7790015 Merge to 2.0.3 2012-12-06 10:40:33 -05:00
Francis Lachapelle 9dd000a2ca Merge to 2.0.2
Merge commit '1080bee3ba9749aad0dc28625081fc6a496f7280' into maint

Conflicts:
	OpenChange/MAPIStoreContext.h
	OpenChange/MAPIStoreContext.m
2012-11-15 10:10:48 -05:00
Wolfgang Sourdeau ce4084e528 getNewChangeNumbers: new wrapper for openchangedb_get_new_changeNumbers 2012-10-12 16:55:27 -04:00
1361 changed files with 71171 additions and 50929 deletions

No files matched your search

+13 -28
View File
@@ -1,33 +1,18 @@
config.make
tags
*._*
*.css
*.pyc
*.sax
*.swp
*.wox/
*/*/*.SOGo/
*/*/*/obj/
*/*/obj/
*/obj/
.scss-lint-config.yml_
Documentation/*.docbook
Documentation/*.pdf
*._*
*/*/obj/
*/*/*/obj/
*/*/*.SOGo/
*.sax
*.wox/
*.swp
SoObjects/SOGo/SOGo.framework/
SoObjects/SOGo/derived_src/
Tests/*/config.py
UI/WebServerResources/.bowerrc
UI/WebServerResources/.sass-cache/
UI/WebServerResources/bower_components/
UI/WebServerResources/css/
UI/WebServerResources/css/styles.css
UI/WebServerResources/css/styles.css.map
UI/WebServerResources/js/Common.js*
UI/WebServerResources/js/Contacts.js*
UI/WebServerResources/js/Mailer.js*
UI/WebServerResources/js/Preferences.js*
UI/WebServerResources/js/Scheduler.js*
UI/WebServerResources/js/vendor/
UI/WebServerResources/node_modules/
UI/WebServerResources/scss/.sass-cache/
config.make
doc
tags
*.pyc
._*
Documentation/*.docbook
Documentation/*.pdf
-3
View File
@@ -1,3 +0,0 @@
[submodule "UI/WebServerResources/angular-material"]
path = UI/WebServerResources/angular-material
url = https://github.com/angular/material
-33
View File
@@ -12,7 +12,6 @@ trans.da_DK = UI/MailerUI/Danish.lproj/Localizable.strings
trans.de = UI/MailerUI/German.lproj/Localizable.strings
trans.es_AR = UI/MailerUI/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/MailerUI/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/MailerUI/Basque.lproj/Localizable.strings
trans.fi = UI/MailerUI/Finnish.lproj/Localizable.strings
trans.fr = UI/MailerUI/French.lproj/Localizable.strings
trans.hu = UI/MailerUI/Hungarian.lproj/Localizable.strings
@@ -25,10 +24,8 @@ 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
@@ -41,7 +38,6 @@ trans.da_DK = UI/PreferencesUI/Danish.lproj/Localizable.strings
trans.de = UI/PreferencesUI/German.lproj/Localizable.strings
trans.es_AR = UI/PreferencesUI/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/PreferencesUI/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/PreferencesUI/Basque.lproj/Localizable.strings
trans.fi = UI/PreferencesUI/Finnish.lproj/Localizable.strings
trans.fr = UI/PreferencesUI/French.lproj/Localizable.strings
trans.hu = UI/PreferencesUI/Hungarian.lproj/Localizable.strings
@@ -54,10 +50,8 @@ 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
@@ -70,7 +64,6 @@ trans.da_DK = UI/Scheduler/Danish.lproj/Localizable.strings
trans.de = UI/Scheduler/German.lproj/Localizable.strings
trans.es_AR = UI/Scheduler/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/Scheduler/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/Scheduler/Basque.lproj/Localizable.strings
trans.fi = UI/Scheduler/Finnish.lproj/Localizable.strings
trans.fr = UI/Scheduler/French.lproj/Localizable.strings
trans.hu = UI/Scheduler/Hungarian.lproj/Localizable.strings
@@ -83,10 +76,8 @@ 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
@@ -99,7 +90,6 @@ trans.da_DK = UI/Contacts/Danish.lproj/Localizable.strings
trans.de = UI/Contacts/German.lproj/Localizable.strings
trans.es_AR = UI/Contacts/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/Contacts/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/Contacts/Basque.lproj/Localizable.strings
trans.fi = UI/Contacts/Finnish.lproj/Localizable.strings
trans.fr = UI/Contacts/French.lproj/Localizable.strings
trans.hu = UI/Contacts/Hungarian.lproj/Localizable.strings
@@ -112,10 +102,8 @@ 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
@@ -128,7 +116,6 @@ trans.da_DK = UI/MainUI/Danish.lproj/Localizable.strings
trans.de = UI/MainUI/German.lproj/Localizable.strings
trans.es_AR = UI/MainUI/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/MainUI/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/MainUI/Basque.lproj/Localizable.strings
trans.fi = UI/MainUI/Finnish.lproj/Localizable.strings
trans.fr = UI/MainUI/French.lproj/Localizable.strings
trans.hu = UI/MainUI/Hungarian.lproj/Localizable.strings
@@ -141,10 +128,8 @@ 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
@@ -157,7 +142,6 @@ trans.da_DK = UI/Common/Danish.lproj/Localizable.strings
trans.de = UI/Common/German.lproj/Localizable.strings
trans.es_AR = UI/Common/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/Common/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/Common/Basque.lproj/Localizable.strings
trans.fi = UI/Common/Finnish.lproj/Localizable.strings
trans.fr = UI/Common/French.lproj/Localizable.strings
trans.hu = UI/Common/Hungarian.lproj/Localizable.strings
@@ -170,10 +154,8 @@ 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
@@ -186,7 +168,6 @@ trans.da_DK = UI/AdministrationUI/Danish.lproj/Localizable.strings
trans.de = UI/AdministrationUI/German.lproj/Localizable.strings
trans.es_AR = UI/AdministrationUI/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/AdministrationUI/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/AdministrationUI/Basque.lproj/Localizable.strings
trans.fi = UI/AdministrationUI/Finnish.lproj/Localizable.strings
trans.fr = UI/AdministrationUI/French.lproj/Localizable.strings
trans.hu = UI/AdministrationUI/Hungarian.lproj/Localizable.strings
@@ -199,10 +180,8 @@ 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
@@ -215,7 +194,6 @@ trans.da_DK = SoObjects/Appointments/Danish.lproj/Localizable.strings
trans.de = SoObjects/Appointments/German.lproj/Localizable.strings
trans.es_AR = SoObjects/Appointments/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = SoObjects/Appointments/SpanishSpain.lproj/Localizable.strings
trans.eu = SoObjects/Appointments/Basque.lproj/Localizable.strings
trans.fi = SoObjects/Appointments/Finnish.lproj/Localizable.strings
trans.fr = SoObjects/Appointments/French.lproj/Localizable.strings
trans.hu = SoObjects/Appointments/Hungarian.lproj/Localizable.strings
@@ -228,10 +206,8 @@ 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
@@ -244,7 +220,6 @@ trans.da_DK = SoObjects/Contacts/Danish.lproj/Localizable.strings
trans.de = SoObjects/Contacts/German.lproj/Localizable.strings
trans.es_AR = SoObjects/Contacts/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = SoObjects/Contacts/SpanishSpain.lproj/Localizable.strings
trans.eu = SoObjects/Contacts/Basque.lproj/Localizable.strings
trans.fi = SoObjects/Contacts/Finnish.lproj/Localizable.strings
trans.fr = SoObjects/Contacts/French.lproj/Localizable.strings
trans.hu = SoObjects/Contacts/Hungarian.lproj/Localizable.strings
@@ -257,10 +232,8 @@ 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
@@ -273,7 +246,6 @@ trans.da_DK = SoObjects/Mailer/Danish.lproj/Localizable.strings
trans.de = SoObjects/Mailer/German.lproj/Localizable.strings
trans.es_AR = SoObjects/Mailer/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = SoObjects/Mailer/SpanishSpain.lproj/Localizable.strings
trans.eu = SoObjects/Mailer/Basque.lproj/Localizable.strings
trans.fi = SoObjects/Mailer/Finnish.lproj/Localizable.strings
trans.fr = SoObjects/Mailer/French.lproj/Localizable.strings
trans.hu = SoObjects/Mailer/Hungarian.lproj/Localizable.strings
@@ -286,10 +258,8 @@ 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
@@ -302,7 +272,6 @@ trans.da_DK = UI/MailPartViewers/Danish.lproj/Localizable.strings
trans.de = UI/MailPartViewers/German.lproj/Localizable.strings
trans.es_AR = UI/MailPartViewers/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/MailPartViewers/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/MailPartViewers/Basque.lproj/Localizable.strings
trans.fi = UI/MailPartViewers/Finnish.lproj/Localizable.strings
trans.fr = UI/MailPartViewers/French.lproj/Localizable.strings
trans.hu = UI/MailPartViewers/Hungarian.lproj/Localizable.strings
@@ -315,7 +284,5 @@ 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
+16 -19
View File
@@ -1,6 +1,6 @@
/*
Copyright (c) 2015, Inverse inc.
Copyright (c) 2014, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -40,14 +40,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@implementation NGMimeMessage (ActiveSync)
- (void) _addRecipients: (NSEnumerator *) enumerator
toArray: (NSMutableArray *) recipients
- (NSArray *) allRecipients
{
NSEnumerator *enumerator, *addressList;
NSMutableArray *recipients;
NGMailAddressParser *parser;
NSEnumerator *addressList;
NGMailAddress *address;
NSString *s;
recipients = [NSMutableArray array];
enumerator = [[self headersForKey: @"to"] objectEnumerator];
while ((s = [enumerator nextObject]))
{
parser = [NGMailAddressParser mailAddressParserWithString: s];
@@ -56,22 +59,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
while ((address = [addressList nextObject]))
[recipients addObject: [address address]];
}
}
- (NSArray *) allRecipients
{
NSMutableArray *recipients;
recipients = [NSMutableArray array];
[self _addRecipients: [[self headersForKey: @"to"] objectEnumerator]
toArray: recipients];
[self _addRecipients: [[self headersForKey: @"cc"] objectEnumerator]
toArray: recipients];
[self _addRecipients: [[self headersForKey: @"bcc"] objectEnumerator]
toArray: recipients];
enumerator = [[self headersForKey: @"cc"] objectEnumerator];
while ((s = [enumerator nextObject]))
{
parser = [NGMailAddressParser mailAddressParserWithString: s];
addressList = [[parser parseAddressList] objectEnumerator];
while ((address = [addressList nextObject]))
[recipients addObject: [address address]];
}
return recipients;
}
+8 -44
View File
@@ -32,10 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSProcessInfo.h>
#import <Foundation/NSString.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NSObject+Logs.h>
#include <wbxml/wbxml.h>
#include <wbxml/wbxml_conv.h>
@@ -47,18 +44,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (void) _dumpToFile
{
BOOL debugOn;
NSString *path;
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] easDebugEnabled];
if (debugOn)
{
NSString *path;
path = [NSString stringWithFormat: @"/tmp/%@.data", [[NSProcessInfo processInfo] globallyUniqueString]];
[self writeToFile: path atomically: YES];
[self errorWithFormat: @"Original data written to: %@", path];
}
path = [NSString stringWithFormat: @"/tmp/%@.data", [[NSProcessInfo processInfo] globallyUniqueString]];
[self writeToFile: path atomically: YES];
NSLog(@"Original data written to: %@", path);
}
//
@@ -66,33 +56,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSString *tmp, *s;
unichar *buf, *start, c;
int len, i, j;
tmp = [self stringByEncodingBase64] ;
len = [tmp length];
start = buf = (unichar *)malloc(len*sizeof(unichar));
[tmp getCharacters: buf range: NSMakeRange(0, len)];
for (i = 0, j = 0; i < len; i++)
{
c = *buf;
if (!(c == 0xA))
{
*(start+j) = c;
j++;
}
buf++;
}
s = [[NSString alloc] initWithCharactersNoCopy: start length: j freeWhenDone: YES];
return AUTORELEASE(s);
return [[self stringByEncodingBase64] stringByReplacingString: @"\n" withString: @""];
}
- (NSData *) wbxml2xml
@@ -117,7 +81,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
[self errorWithFormat: @"wbxml2xmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
NSLog(@"wbxml2xmlFromContent: failed: %s\n", wbxml_errors_string(ret));
[self _dumpToFile];
return nil;
}
@@ -150,7 +114,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
[self logWithFormat: @"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
NSLog(@"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret));
[self _dumpToFile];
return nil;
}
@@ -165,7 +129,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
[self errorWithFormat: @"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
NSLog(@"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret));
[self _dumpToFile];
free(wbxml);
wbxml_conv_xml2wbxml_destroy(conv);
+1 -4
View File
@@ -1,6 +1,6 @@
/*
Copyright (c) 2014-2015, Inverse inc.
Copyright (c) 2014, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -49,9 +49,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSString *) deviceType;
- (NSString *) attachmentName;
- (NSString *) command;
- (NSString *) collectionid;
- (NSString *) itemid;
- (BOOL) acceptsMultiPart;
- (NSData *) convertHexStringToBytes;
@end
+5 -131
View File
@@ -46,99 +46,6 @@ static NSArray *easCommandParameters = nil;
@implementation NSString (ActiveSync)
//
// This is a copy from NSString+XMLEscaping.m from SOPE.
// The difference here is that we use wchar_t instead of unichar.
// This is needed to get the rigth numeric character reference.
// e.g. SMILING FACE WITH OPEN MOUTH
// ok: wchar_t -> &#128515; wrong: unichar -> &#55357; &#56835;
//
// We avoir naming it like the one in SOPE since if the ActiveSync
// bundle is loaded, it'll overwrite the one provided by SOPE.
//
- (NSString *) _stringByEscapingXMLStringUsingCharacters {
register unsigned i, len, j;
register wchar_t *buf;
const wchar_t *chars;
unsigned escapeCount;
if ([self length] == 0) return @"";
NSData *data = [self dataUsingEncoding:NSUTF32StringEncoding];
chars = [data bytes];
len = [data length]/4;
/* check for characters to escape ... */
for (i = 0, escapeCount = 0; i < len; i++) {
switch (chars[i]) {
case '&': case '"': case '<': case '>': case '\r':
escapeCount++;
break;
default:
if (chars[i] > 127)
escapeCount++;
break;
}
}
if (escapeCount == 0 ) {
/* nothing to escape ... */
return [[self copy] autorelease];
}
buf = calloc((len + 5) + (escapeCount * 16), sizeof(wchar_t));
for (i = 0, j = 0; i < len; i++) {
switch (chars[i]) {
/* escape special chars */
case '\r':
buf[j] = '&'; j++; buf[j] = '#'; j++; buf[j] = '1'; j++;
buf[j] = '3'; j++; buf[j] = ';'; j++;
break;
case '&':
buf[j] = '&'; j++; buf[j] = 'a'; j++; buf[j] = 'm'; j++;
buf[j] = 'p'; j++; buf[j] = ';'; j++;
break;
case '"':
buf[j] = '&'; j++; buf[j] = 'q'; j++; buf[j] = 'u'; j++;
buf[j] = 'o'; j++; buf[j] = 't'; j++; buf[j] = ';'; j++;
break;
case '<':
buf[j] = '&'; j++; buf[j] = 'l'; j++; buf[j] = 't'; j++;
buf[j] = ';'; j++;
break;
case '>':
buf[j] = '&'; j++; buf[j] = 'g'; j++; buf[j] = 't'; j++;
buf[j] = ';'; j++;
break;
default:
/* escape big chars */
if (chars[i] > 127) {
unsigned char nbuf[32];
unsigned int k;
sprintf((char *)nbuf, "&#%i;", (int)chars[i]);
for (k = 0; nbuf[k] != '\0'; k++) {
buf[j] = nbuf[k];
j++;
}
}
else if (chars[i] == 0x9 || chars[i] == 0xA || chars[i] == 0xD || chars[i] >= 0x20) { // ignore any unsupported control character
/* nothing to escape */
buf[j] = chars[i];
j++;
}
break;
}
}
self = [[NSString alloc] initWithBytesNoCopy: buf
length: (j*sizeof(wchar_t))
encoding: NSUTF32StringEncoding
freeWhenDone: YES];
return [self autorelease];
}
- (NSString *) sanitizedServerIdWithType: (SOGoMicrosoftActiveSyncFolderType) folderType
{
if (folderType == ActiveSyncEventFolder)
@@ -158,7 +65,11 @@ static NSArray *easCommandParameters = nil;
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
return [self _stringByEscapingXMLStringUsingCharacters];
NSString *s;
s = [self safeString];
return [s stringByEscapingHTMLString];
}
- (int) activeSyncFolderType
@@ -387,43 +298,6 @@ static NSArray *easCommandParameters = nil;
return s;
}
- (NSString *) itemid
{
NSString *s;
s = [self _valueForParameter: @"ITEMID="];
if (!s)
s = @"Unknown";
return s;
}
- (NSString *) collectionid
{
NSString *s;
s = [self _valueForParameter: @"COLLECTIONID="];
if (!s)
s = @"Unknown";
return s;
}
- (BOOL) acceptsMultiPart
{
NSString *s;
s = [self _valueForParameter: @"OPTIONS="];
if (s && [s rangeOfString: @"AcceptMultiPart" options: NSCaseInsensitiveSearch].location != NSNotFound)
return YES;
return NO;
}
//
// FIXME: combine with our OpenChange code.
//
+53 -157
View File
@@ -57,7 +57,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGCards/NGVCard.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <NGImap4/NSString+Imap4.h>
@@ -131,7 +130,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[[o properties] removeObjectForKey: @"SyncCache"];
[[o properties] removeObjectForKey: @"DateCache"];
[[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
[[o properties] addEntriesFromDictionary: values];
@@ -283,14 +281,15 @@ 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:
default:
{
// FIXME - what to do?
[self errorWithFormat: @"Fatal error occured - tried to call -processSyncAddCommand: ... on a mail folder. We abort."];
// FIXME
//continue;
NSLog(@"BLARG!");
abort();
}
}
@@ -311,10 +310,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syncCache = [folderMetadata objectForKey: @"SyncCache"];
dateCache = [folderMetadata objectForKey: @"DateCache"];
[syncCache setObject: [NSString stringWithFormat:@"%f", [[sogoObject lastModified] timeIntervalSince1970]] forKey: serverId];
[syncCache setObject: [folderMetadata objectForKey: @"SyncKey"] forKey: serverId];
[dateCache setObject: [NSCalendarDate date] forKey: serverId];
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
}
}
@@ -365,7 +364,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NSString *serverId;
NSArray *changes;
id aChange, o, sogoObject;
NSMutableDictionary *folderMetadata, *syncCache;
int i;
@@ -373,9 +371,6 @@ 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];
@@ -402,9 +397,6 @@ 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:
@@ -413,30 +405,15 @@ 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];
@@ -475,27 +452,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
withType: (SOGoMicrosoftActiveSyncFolderType) theFolderType
inBuffer: (NSMutableString *) theBuffer
{
id aDelete, sogoObject, value;
NSArray *deletions;
NSString *serverId;
BOOL deletesAsMoves, useTrash;
id aDelete, sogoObject;
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];
@@ -507,13 +473,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
acquire: NO];
if (![sogoObject isKindOfClass: [NSException class]])
{
// FIXME: handle errors here
if (deletesAsMoves && theFolderType == ActiveSyncMailFolder)
[(SOGoMailFolder *)[sogoObject container] deleteUIDs: [NSArray arrayWithObjects: serverId, nil] useTrashFolder: &useTrash inContext: context];
else
[sogoObject delete];
}
[sogoObject delete];
[theBuffer appendString: @"<Delete>"];
[theBuffer appendFormat: @"<ServerId>%@</ServerId>", serverId];
@@ -580,7 +540,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
NSMutableDictionary *folderMetadata, *dateCache, *syncCache;
NSString *davCollectionTagToStore;
NSAutoreleasePool *pool;
NSMutableString *s;
@@ -659,8 +618,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
more_available = NO;
davCollectionTagToStore = [theCollection davCollectionTag];
switch (theFolderType)
{
// Handle all the GCS components
@@ -831,7 +788,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
{
[folderMetadata removeObjectForKey: @"MoreAvailable"];
[folderMetadata setObject: davCollectionTagToStore forKey: @"SyncKey"];
[folderMetadata setObject: [theCollection davCollectionTag] forKey: @"SyncKey"];
}
[self _setFolderMetadata: folderMetadata
@@ -932,8 +889,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[syncCache removeObjectForKey: [aCacheObject uid]];
[dateCache removeObjectForKey: [aCacheObject uid]];
return_count++;
}
else
{
@@ -943,20 +898,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inContext: context
acquire: 0];
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++;
}
[s appendString: @"<Change xmlns=\"AirSync:\">"];
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", [aCacheObject uid]];
[s appendString: @"<ApplicationData xmlns=\"AirSync:\">"];
[s appendString: [mailObject activeSyncRepresentationInContext: context]];
[s appendString: @"</ApplicationData>"];
[s appendString: @"</Change>"];
[syncCache setObject: [aCacheObject sequence] forKey: [aCacheObject uid]];
}
return_count++;
}
else
{
@@ -1011,7 +963,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
{
[folderMetadata removeObjectForKey: @"MoreAvailable"];
[folderMetadata setObject: davCollectionTagToStore forKey: @"SyncKey"];
[folderMetadata setObject: [theCollection davCollectionTag] forKey: @"SyncKey"];
}
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
@@ -1113,14 +1065,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
changeDetected: (BOOL *) changeDetected
maxSyncResponseSize: (int) theMaxSyncResponseSize
{
NSString *collectionId, *realCollectionId, *syncKey, *davCollectionTag, *bodyPreferenceType, *mimeSupport, *lastServerKey, *syncKeyInCache;
NSString *collectionId, *realCollectionId, *syncKey, *davCollectionTag, *bodyPreferenceType, *lastServerKey;
SOGoMicrosoftActiveSyncFolderType folderType;
id collection, value;
NSMutableString *changeBuffer, *commandsBuffer;
BOOL getChanges, first_sync;
unsigned int windowSize, v, status;
NSMutableDictionary *folderMetadata, *folderOptions;
changeBuffer = [NSMutableString string];
commandsBuffer = [NSMutableString string];
@@ -1169,22 +1120,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
first_sync = NO;
folderMetadata = [self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]];
if ([syncKey isEqualToString: @"0"])
{
davCollectionTag = @"-1";
first_sync = YES;
*changeDetected = YES;
}
else if ((![syncKey isEqualToString: @"-1"]) && !([folderMetadata objectForKey: @"SyncCache"]))
else if ((![syncKey isEqualToString: @"-1"]) && !([[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"SyncCache"]))
{
//NSLog(@"Reset folder: %@", [collection nameInContainer]);
davCollectionTag = @"0";
first_sync = YES;
*changeDetected = YES;
if (!([folderMetadata objectForKey: @"displayName"]))
if (!([[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"displayName"]))
status = 12; // need folderSync
else
status = 3; // do a complete resync
@@ -1194,43 +1143,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
bodyPreferenceType = [[(id)[[(id)[theDocumentElement getElementsByTagName: @"BodyPreference"] lastObject] getElementsByTagName: @"Type"] lastObject] textValue];
if (!bodyPreferenceType)
{
bodyPreferenceType = [[folderMetadata objectForKey: @"FolderOptions"] objectForKey: @"BodyPreferenceType"];
// By default, send MIME mails. See #3146 for details.
if (!bodyPreferenceType)
bodyPreferenceType = @"4";
}
else
{
mimeSupport = [[(id)[theDocumentElement getElementsByTagName: @"MIMESupport"] lastObject] textValue];
if (!mimeSupport)
mimeSupport = [[folderMetadata objectForKey: @"FolderOptions"] objectForKey: @"MIMESupport"];
if (!mimeSupport)
mimeSupport = @"0";
if ([mimeSupport isEqualToString: @"1"] && [bodyPreferenceType isEqualToString: @"4"])
bodyPreferenceType = @"2";
else if ([mimeSupport isEqualToString: @"2"] && [bodyPreferenceType isEqualToString: @"4"])
bodyPreferenceType = @"4";
else if ([mimeSupport isEqualToString: @"0"] && [bodyPreferenceType isEqualToString: @"4"])
bodyPreferenceType = @"2";
// Avoid writing to cache if there is nothing to change.
if (![[[folderMetadata objectForKey: @"FolderOptions"] objectForKey: @"BodyPreferenceType"] isEqualToString: bodyPreferenceType] ||
![[[folderMetadata objectForKey: @"FolderOptions"] objectForKey: @"MIMESupport"] isEqualToString: mimeSupport])
{
folderOptions = [[NSDictionary alloc] initWithObjectsAndKeys: mimeSupport, @"MIMESupport", bodyPreferenceType, @"BodyPreferenceType", nil];
[folderMetadata setObject: folderOptions forKey: @"FolderOptions"];
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: collection withType: folderType]];
}
}
bodyPreferenceType = @"1";
[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
//
@@ -1248,31 +1180,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inBuffer: s
processed: &processed];
// Windows phones don't like empty Responses tags - such as: <Responses></Responses>.
// We only generate this tag when there is a response
// Windows phons don't empty Responses tags - such as: <Responses></Responses>.
// We onnly generate this tag when the command has generated 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
// let's regenerate our SyncKey based on the collection tag.
if ([changeBuffer length] || [commandsBuffer length])
@@ -1283,7 +1196,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
// Use the SyncKey saved by processSyncGetChanges - if processSyncGetChanges is not called (because of getChanges=false)
// SyncKey has the value of the previous sync operation.
davCollectionTag = [folderMetadata objectForKey: @"SyncKey"];
davCollectionTag = [[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"SyncKey"];
if (!davCollectionTag)
davCollectionTag = [collection davCollectionTag];
@@ -1293,13 +1206,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
else
{
// 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]) && !first_sync)
{
davCollectionTag = syncKeyInCache;
*changeDetected = YES;
}
if (folderType == ActiveSyncMailFolder && [syncKey isEqualToString: @"-1"])
davCollectionTag = [collection davCollectionTag];
}
// Generate the response buffer
@@ -1320,7 +1228,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// MoreAvailable breaks Windows Mobile devices if not between <Status> and <Commands>
// https://social.msdn.microsoft.com/Forums/en-US/040b254e-f47e-4cc1-a397-6d8393cdb819/airsyncmoreavailable-breaks-windows-mobile-devices-what-am-i-doing-wrong?forum=os_exchangeprotocols
if ([folderMetadata objectForKey: @"MoreAvailable"])
if ([[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"MoreAvailable"])
[theBuffer appendString: @"<MoreAvailable/>"];
[theBuffer appendString: commandsBuffer];
@@ -1465,10 +1373,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
defaultInterval = [defaults maximumSyncInterval];
internalInterval = [defaults internalSyncInterval];
// If the request doesn't contain "HeartbeatInterval" there is no reason to delay the response.
if (heartbeatInterval == 0)
heartbeatInterval = internalInterval = 1;
// We check to see if our heartbeat interval falls into the supported ranges.
if (heartbeatInterval > defaultInterval || heartbeatInterval < 1)
{
@@ -1485,7 +1389,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
allCollections = (id)[theDocumentElement getElementsByTagName: @"Collection"];
// We enter our loop detection change
for (i = 0; i < (heartbeatInterval/internalInterval); i++)
for (i = 0; i < (defaultInterval/internalInterval); i++)
{
s = [NSMutableString string];
@@ -1497,30 +1401,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inBuffer: s
changeDetected: &changeDetected
maxSyncResponseSize: maxSyncResponseSize];
if (maxSyncResponseSize > 0 && [s length] >= maxSyncResponseSize)
break;
}
if (changeDetected)
{
[self logWithFormat: @"Change detected, we push the content."];
NSLog(@"Change detected, we push the content.");
break;
}
else if (heartbeatInterval > 1)
{
[self logWithFormat: @"Sleeping %d seconds while detecting changes...", internalInterval];
sleep(internalInterval);
}
else
{
break;
NSLog(@"Sleeping %d seconds while detecting changes...", internalInterval);
sleep(internalInterval);
}
}
// Only send a response if there are changes or MS-ASProtocolVersion is either 2.5 or 12.0 oterwise send an empty response.
if (changeDetected || [[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"] || [[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"12.0"])
// Only send a response if there are changes otherwise send an empty response.
if (changeDetected)
{
// We always return the last generated response.
// If we only return <Sync><Collections/></Sync>,
File diff suppressed because it is too large. Load diff
+64 -431
View File
@@ -47,9 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGExtensions/NSString+Encoding.h>
#import <NGImap4/NGImap4Envelope.h>
#import <NGImap4/NGImap4EnvelopeAddress.h>
#import <NGImap4/NSString+Imap4.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOApplication.h>
#import <NGMime/NGMimeBodyPart.h>
#import <NGMime/NGMimeFileData.h>
@@ -59,10 +57,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGMail/NGMimeMessage.h>
#import <NGMail/NGMimeMessageGenerator.h>
#import <Mailer/SOGoMailLabel.h>
#import <SOGo/SOGoUserDefaults.h>
#include "iCalTimeZone+ActiveSync.h"
#include "NSData+ActiveSync.h"
#include "NSDate+ActiveSync.h"
@@ -75,43 +69,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <SOGo/SOGoUser.h>
#include <SOGo/NSString+Utilities.h>
#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;
@@ -126,7 +83,7 @@ struct GlobalObjectId {
FILETIME CreationTime;
uint8_t X[8];
uint32_t Size;
uint8_t Data[0];
uint8_t* Data;
};
@implementation SOGoMailObject (ActiveSync)
@@ -153,40 +110,39 @@ 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];
memcpy(newGlobalId->Data, dataPrefix, 0x0c);
memcpy(newGlobalId->Data + 0x0c, bytes, newGlobalId->Size - 0x0c);
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);
globalObjectId = [[NSData alloc] initWithBytes: newGlobalId length: 40 + newGlobalId->Size*sizeof(uint8_t)];
free(newGlobalId);
globalObjectId = [[NSData alloc] initWithBytes: &newGlobalId length: 40 + newGlobalId.Size*sizeof(uint8_t)];
free(newGlobalId.Data);
return [globalObjectId autorelease];
}
//
// For debugging purposes...
//
@@ -248,15 +204,12 @@ struct GlobalObjectId {
//
//
- (NSData *) _preferredBodyDataInMultipartUsingType: (int) theType
nativeTypeFound: (int *) theNativeTypeFound
{
NSString *encoding, *key, *plainKey, *htmlKey, *type, *subtype;
NSDictionary *textParts, *part;
NSEnumerator *e;
NSData *d;
BOOL ignore;
textParts = [self fetchPlainTextParts];
e = [textParts keyEnumerator];
plainKey = nil;
@@ -265,35 +218,10 @@ struct GlobalObjectId {
while ((key = [e nextObject]))
{
// Walk the hierarchy up and check whether parents are of type mulipart - i.e. ignore message/rfc822
if ([key countOccurrencesOfString: @"."] > 0)
{
NSMutableArray *a;
a = [[[key componentsSeparatedByString: @"."] mutableCopy] autorelease];
ignore = NO;
while ([a count] > 0)
{
[a removeLastObject];
part = [self lookupInfoForBodyPart: [a componentsJoinedByString: @"."]];
if (![[part valueForKey: @"type"] isEqualToString: @"multipart"])
ignore = YES;
}
if (ignore)
continue;
}
part = [self lookupInfoForBodyPart: key];
type = [part valueForKey: @"type"];
subtype = [part valueForKey: @"subtype"];
// Don't select an attachment as body
if ([[[part valueForKey: @"disposition"] valueForKey: @"type"] isEqualToString: @"attachment"])
continue;
if ([type isEqualToString: @"text"] && [subtype isEqualToString: @"html"])
htmlKey = key;
else if ([type isEqualToString: @"text"] && [subtype isEqualToString: @"plain"])
@@ -301,22 +229,11 @@ struct GlobalObjectId {
}
key = nil;
*theNativeTypeFound = 1;
if (theType == 2 && htmlKey)
{
key = htmlKey;
*theNativeTypeFound = 2;
}
else if (theType == 1 && plainKey)
if (theType == 2)
key = htmlKey;
else if (theType == 1)
key = plainKey;
else if (theType == 2 && plainKey)
key = plainKey;
else if (theType == 1 && htmlKey)
{
key = htmlKey;
*theNativeTypeFound = 2;
}
if (key)
{
@@ -334,17 +251,9 @@ struct GlobalObjectId {
charset = [[[self lookupInfoForBodyPart: key] objectForKey: @"parameterList"] objectForKey: @"charset"];
if (![charset length])
charset = @"utf-8";
charset = @"us-ascii";
s = [NSString stringWithData: d usingEncodingNamed: charset];
// We fallback to ISO-8859-1 string encoding
if (!s)
s = [[[NSString alloc] initWithData: d encoding: NSISOLatin1StringEncoding] autorelease];
if (theType == 1 && *theNativeTypeFound == 2)
s = [s htmlToText];
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
@@ -389,7 +298,7 @@ struct GlobalObjectId {
[[[thePart contentType] type] isEqualToString: @"text"] &&
([[[thePart contentType] subType] isEqualToString: @"plain"] || [[[thePart contentType] subType] isEqualToString: @"html"]))
{
// We make sure everything is encoded in UTF-8.
// We make sure everything is encoded in UTF-8
NGMimeType *mimeType;
NSString *s;
@@ -400,13 +309,9 @@ struct GlobalObjectId {
charset = [[thePart contentType] valueOfParameter: @"charset"];
if (![charset length])
charset = @"utf-8";
charset = @"us-ascii";
s = [NSString stringWithData: body usingEncodingNamed: charset];
// We fallback to ISO-8859-1 string encoding. We avoid #3103.
if (!s)
s = [[[NSString alloc] initWithData: body encoding: NSISOLatin1StringEncoding] autorelease];
s = [NSString stringWithData: body usingEncodingNamed: charset];
}
else
{
@@ -417,6 +322,11 @@ struct GlobalObjectId {
if (s)
{
// We sanitize the content immediately, in case we have non-UNICODE safe
// characters that would be re-encoded later in HTML entities and thus,
// ignore afterwards.
s = [s safeString];
body = [s dataUsingEncoding: NSUTF8StringEncoding];
}
@@ -497,14 +407,14 @@ struct GlobalObjectId {
// We get the right part based on the preference
if (theType == 1 || theType == 2)
{
if ([type isEqualToString: @"text"] && ![subtype isEqualToString: @"calendar"])
if ([type isEqualToString: @"text"])
{
NSString *s, *charset;
charset = [[[self lookupInfoForBodyPart: @""] objectForKey: @"parameterList"] objectForKey: @"charset"];
if (![charset length])
charset = @"utf-8";
charset = @"us-ascii";
d = [[self fetchPlainTextParts] objectForKey: @""];
@@ -518,30 +428,25 @@ struct GlobalObjectId {
d = [d dataByDecodingQuotedPrintableTransferEncoding];
s = [NSString stringWithData: d usingEncodingNamed: charset];
// We fallback to ISO-8859-1 string encoding. We avoid #3103.
if (!s)
s = [[[NSString alloc] initWithData: d encoding: NSISOLatin1StringEncoding] autorelease];
// Check if we must convert html->plain
if (theType == 1 && [subtype isEqualToString: @"html"])
{
s = [s htmlToText];
}
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
else if ([type isEqualToString: @"multipart"])
{
d = [self _preferredBodyDataInMultipartUsingType: theType nativeTypeFound: theNativeType];
d = [self _preferredBodyDataInMultipartUsingType: theType];
}
}
else if (theType == 4)
{
// We sanitize the content *ONLY* for Outlook clients and if the content-transfer-encoding is 8bit. Outlook has strange issues
// We sanitize the content *ONLY* for Outlook clients. Outlook has strange issues
// with quoted-printable/base64 encoded text parts. It just doesn't decode them.
encoding = [[self lookupInfoForBodyPart: @""] objectForKey: @"encoding"];
if ([[context objectForKey: @"DeviceType"] isEqualToString: @"WindowsOutlook15"] || ([encoding caseInsensitiveCompare: @"8bit"] == NSOrderedSame))
if ([[context objectForKey: @"DeviceType"] isEqualToString: @"WindowsOutlook15"])
d = [self _sanitizedMIMEMessage];
else
d = [self content];
@@ -550,65 +455,15 @@ 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;
}
//
//
//
- (iCalCalendar *) calendarFromIMIPMessage
{
NSDictionary *part;
NSString *type, *subtype;
NSArray *parts;
int i;
type = [[[self bodyStructure] valueForKey: @"type"] lowercaseString];
subtype = [[[self bodyStructure] valueForKey: @"subtype"] lowercaseString];
// process mail of type text/calendar
if ([type isEqualToString: @"text"] && [subtype isEqualToString: @"calendar"])
{
iCalCalendar *calendar;
NSString *encoding;
NSData *calendarData;
encoding = [[[self bodyStructure] valueForKey: @"encoding"] lowercaseString];
calendarData = [[self fetchPlainTextParts] objectForKey: @""];
if ([encoding caseInsensitiveCompare: @"base64"] == NSOrderedSame)
calendarData = [calendarData dataByDecodingBase64];
else if ([encoding caseInsensitiveCompare: @"quoted-printable"] == NSOrderedSame)
calendarData = [calendarData dataByDecodingQuotedPrintableTransferEncoding];
NS_DURING
calendar = [iCalCalendar parseSingleFromSource: calendarData];
NS_HANDLER
calendar = nil;
NS_ENDHANDLER
return calendar;
}
// We check if we have at least 2 parts and if one of them is a text/calendar
parts = [[self bodyStructure] objectForKey: @"parts"];
@@ -657,10 +512,6 @@ struct GlobalObjectId {
NSData *d, *globalObjId;
NSArray *attachmentKeys;
NSMutableString *s;
uint32_t v;
NSString *p;
id value;
iCalCalendar *calendar;
@@ -685,7 +536,7 @@ struct GlobalObjectId {
if (value)
{
[s appendFormat: @"<Subject xmlns=\"Email:\">%@</Subject>", [value activeSyncRepresentationInContext: context]];
[s appendFormat: @"<ThreadTopic xmlns=\"Email:\">%@</ThreadTopic>", [[self _getNormalizedSubject] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<ThreadTopic xmlns=\"Email:\">%@</ThreadTopic>", [value activeSyncRepresentationInContext: context]];
}
// DateReceived
@@ -701,34 +552,8 @@ struct GlobalObjectId {
if (value)
[s appendFormat: @"<Cc xmlns=\"Email:\">%@</Cc>", [value activeSyncRepresentationInContext: context]];
// Importance
v = 0x1;
value = [[self mailHeaders] objectForKey: @"x-priority"];
if ([value isKindOfClass: [NSArray class]])
p = [value lastObject];
else
p = value;
if (p)
{
if ([p hasPrefix: @"1"]) v = 0x2;
else if ([p hasPrefix: @"2"]) v = 0x2;
else if ([p hasPrefix: @"4"]) v = 0x0;
else if ([p hasPrefix: @"5"]) v = 0x0;
}
else
{
value = [[self mailHeaders] objectForKey: @"importance"];
if ([value isKindOfClass: [NSArray class]])
p = [value lastObject];
else
p = value;
if ([p hasPrefix: @"High"]) v = 0x2;
else if ([p hasPrefix: @"Low"]) v = 0x0;
}
[s appendFormat: @"<Importance xmlns=\"Email:\">%d</Importance>", v];
// Importance - FIXME
[s appendFormat: @"<Importance xmlns=\"Email:\">%@</Importance>", @"1"];
// Read
[s appendFormat: @"<Read xmlns=\"Email:\">%d</Read>", ([self read] ? 1 : 0)];
@@ -792,18 +617,18 @@ struct GlobalObjectId {
[s appendFormat: @"<AllDayEvent xmlns=\"Email:\">%d</AllDayEvent>", ([event isAllDay] ? 1 : 0)];
// StartTime -- https://msdn.microsoft.com/en-us/library/ee203365%28v=exchg.80%29.aspx
// StartTime -- http://msdn.microsoft.com/en-us/library/ee157132(v=exchg.80).aspx
if ([event startDate])
[s appendFormat: @"<StartTime xmlns=\"Email:\">%@</StartTime>", [[event startDate] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<StartTime xmlns=\"Email:\">%@</StartTime>", [[event startDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
if ([event timeStampAsDate])
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event timeStampAsDate] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event timeStampAsDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
else if ([event created])
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event created] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event created] activeSyncRepresentationWithoutSeparatorsInContext: context]];
// EndTime -- https://msdn.microsoft.com/en-us/library/ee158628(v=exchg.80).aspx
// EndTime -- http://msdn.microsoft.com/en-us/library/ee157945(v=exchg.80).aspx
if ([event endDate])
[s appendFormat: @"<EndTime xmlns=\"Email:\">%@</EndTime>", [[event endDate] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<EndTime xmlns=\"Email:\">%@</EndTime>", [[event endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
// FIXME: Single appointment - others are not supported right now
[s appendFormat: @"<InstanceType xmlns=\"Email:\">%d</InstanceType>", 0];
@@ -851,9 +676,7 @@ struct GlobalObjectId {
[s appendFormat: @"<GlobalObjId xmlns=\"Email:\">%@</GlobalObjId>", [globalObjId activeSyncRepresentationInContext: context]];
// We set the right message type - we must set AS version to 14.1 for this
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"14.1"])
[s appendFormat: @"<MeetingMessageType xmlns=\"Email2:\">%d</MeetingMessageType>", 1];
[s appendFormat: @"<MeetingMessageType xmlns=\"Email2:\">%d</MeetingMessageType>", 1];
[s appendString: @"</MeetingRequest>"];
// ContentClass
@@ -880,80 +703,13 @@ struct GlobalObjectId {
nativeBodyType = 1;
d = [self _preferredBodyDataUsingType: preferredBodyType nativeType: &nativeBodyType];
if (calendar && !d)
{
WOApplication *app;
SOGoAptMailNotification *p;
NSString *pageName;
nativeBodyType = 2;
/* get WOApplication instance */
app = [WOApplication application];
/* create page name */
pageName = [NSString stringWithFormat: @"SOGoAptMail%@", @"Invitation"];
/* construct message content */
p = [app pageWithName: pageName inContext: context];
[p setApt: (iCalEvent *) [[calendar events] lastObject]];
if ([[ [[calendar events] lastObject] organizer] cn] && [[[ [[calendar events] lastObject] organizer] cn] length])
{
[p setOrganizerName: [[ [[calendar events] lastObject] organizer] cn]];
}
else
{
[p setOrganizerName: [[SOGoUser userWithLogin: owner] cn]];
}
if (preferredBodyType == 1 && nativeBodyType == 2)
d = [[[p getBody] htmlToText] dataUsingEncoding: NSUTF8StringEncoding];
else
{
preferredBodyType = 2;
d = [[p getBody] dataUsingEncoding: NSUTF8StringEncoding];
}
}
if (d)
{
NSMutableData *sanitizedData;
NSString *content;
int len, truncated;
// Outlook fails to decode quoted-printable (see #3082) if lines are not termined by CRLF.
const char *bytes;
char *mbytes;
int mlen;
len = [d length];
mlen = 0;
sanitizedData = [NSMutableData dataWithLength: len*2];
bytes = [d bytes];
mbytes = [sanitizedData mutableBytes];
while (len > 0)
{
if (*bytes == '\n' && *(bytes-1) != '\r' && mlen > 0)
{
*mbytes = '\r';
mbytes++;
mlen++;
}
*mbytes = *bytes;
mbytes++; bytes++;
len--;
mlen++;
}
[sanitizedData setLength: mlen];
content = [[NSString alloc] initWithData: sanitizedData encoding: NSUTF8StringEncoding];
content = [[NSString alloc] initWithData: d encoding: NSUTF8StringEncoding];
// FIXME: This is a hack. We should normally avoid doing this as we might get
// broken encodings. We should rather tell that the data was truncated and expect
@@ -963,40 +719,26 @@ struct GlobalObjectId {
// for an "interesting" discussion around this.
//
if (!content)
content = [[NSString alloc] initWithData: sanitizedData encoding: NSISOLatin1StringEncoding];
content = [[NSString alloc] initWithData: d encoding: NSISOLatin1StringEncoding];
AUTORELEASE(content);
content = [content activeSyncRepresentationInContext: context];
truncated = 0;
len = [content length];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", preferredBodyType];
[s appendFormat: @"<Truncated>%d</Truncated>", truncated];
[s appendFormat: @"<Preview></Preview>"];
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
if (!truncated)
{
[s appendFormat: @"<Body xmlns=\"Email:\">%@</Body>", content];
[s appendFormat: @"<BodyTruncated xmlns=\"Email:\">%d</BodyTruncated>", truncated];
[s appendFormat: @"<Data>%@</Data>", content];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", len];
}
else
{
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
// Set the correct type if client requested text/html but we got text/plain
if (preferredBodyType == 2 && nativeBodyType == 1)
[s appendString: @"<Type>1</Type>"];
else
[s appendFormat: @"<Type>%d</Type>", preferredBodyType];
[s appendFormat: @"<Truncated>%d</Truncated>", truncated];
[s appendFormat: @"<Preview></Preview>"];
if (!truncated)
{
[s appendFormat: @"<Data>%@</Data>", content];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", len];
}
[s appendString: @"</Body>"];
}
[s appendString: @"</Body>"];
}
// Attachments -namespace 16
@@ -1004,12 +746,9 @@ struct GlobalObjectId {
if ([attachmentKeys count])
{
int i;
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
[s appendString: @"<Attachments xmlns=\"Email:\">"];
else
[s appendString: @"<Attachments xmlns=\"AirSyncBase:\">"];
[s appendString: @"<Attachments xmlns=\"AirSyncBase:\">"];
for (i = 0; i < [attachmentKeys count]; i++)
{
value = [attachmentKeys objectAtIndex: i];
@@ -1020,22 +759,11 @@ struct GlobalObjectId {
// FileReference must be a unique identifier across the whole store. We use the following structure:
// mail/<foldername>/<message UID/<pathofpart>
// mail/INBOX/2
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
[s appendFormat: @"<AttName>mail/%@/%@/%@</AttName>", [[[self container] relativeImap4Name] stringByEscapingURL], [self nameInContainer], [value objectForKey: @"path"]];
else
[s appendFormat: @"<FileReference>mail/%@/%@/%@</FileReference>", [[[self container] relativeImap4Name] stringByEscapingURL], [self nameInContainer], [value objectForKey: @"path"]];
[s appendFormat: @"<FileReference>mail/%@/%@/%@</FileReference>", [[[self container] relativeImap4Name] stringByEscapingURL], [self nameInContainer], [value objectForKey: @"path"]];
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
{
[s appendFormat: @"<AttMethod>%d</AttMethod>", 1];
[s appendFormat: @"<AttSize>%d</AttSize>", [[value objectForKey: @"size"] intValue]];
}
else
{
[s appendFormat: @"<Method>%d</Method>", 1]; // See: http://msdn.microsoft.com/en-us/library/ee160322(v=exchg.80).aspx
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [[value objectForKey: @"size"] intValue]];
//[s appendFormat: @"<IsInline>%d</IsInline>", 1];
}
[s appendFormat: @"<Method>%d</Method>", 1]; // See: http://msdn.microsoft.com/en-us/library/ee160322(v=exchg.80).aspx
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [[value objectForKey: @"size"] intValue]];
//[s appendFormat: @"<IsInline>%d</IsInline>", 1];
[s appendString: @"</Attachment>"];
}
@@ -1046,46 +774,10 @@ struct GlobalObjectId {
[s appendString: @"<Flag xmlns=\"Email:\">"];
[s appendFormat: @"<FlagStatus>%d</FlagStatus>", ([self flagged] ? 2 : 0)];
[s appendString: @"</Flag>"];
// Categroies/Labels
NSEnumerator *categories;
categories = [[[self fetchCoreInfos] objectForKey: @"flags"] objectEnumerator];
if (categories)
{
NSString *currentFlag;
NSDictionary *v;
v = [[[context activeUser] userDefaults] mailLabelsColors];
[s appendFormat: @"<Categories xmlns=\"Email:\">"];
while ((currentFlag = [categories nextObject]))
{
if ([[v objectForKey: currentFlag] objectAtIndex:0])
[s appendFormat: @"<Category>%@</Category>", [[[v objectForKey: currentFlag] objectAtIndex:0] activeSyncRepresentationInContext: context]];
}
[s appendFormat: @"</Categories>"];
}
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"14.0"] ||
[[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"14.1"])
{
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]];
}
// FIXME - support these in the future
//[s appendString: @"<ConversationId xmlns=\"Email2:\">foobar</ConversationId>"];
//[s appendString: @"<ConversationIndex xmlns=\"Email2:\">zot=</ConversationIndex>"];
// NativeBodyType -- http://msdn.microsoft.com/en-us/library/ee218276(v=exchg.80).aspx
// This is a required child element.
@@ -1144,65 +836,6 @@ struct GlobalObjectId {
else
[self removeFlags: @"seen"];;
}
if ((o = [theValues objectForKey: @"Categories"]))
{
NSEnumerator *categories;
NSString *currentFlag;
NSDictionary *v;
v = [[[context activeUser] userDefaults] mailLabelsColors];
// add categories/labels sent from client
if ([o isKindOfClass: [NSArray class]])
{
NSEnumerator *enumerator;
NSMutableArray *labels;
NSEnumerator *flags;
id key;
labels = [NSMutableArray array];
enumerator = [v keyEnumerator];
flags = [o objectEnumerator];
while ((currentFlag = [flags nextObject]))
{
while ((key = [enumerator nextObject]))
{
if (([currentFlag isEqualToString:[[v objectForKey:key] objectAtIndex:0]]))
{
[labels addObject: key];
break;
}
}
}
[self addFlags: [labels componentsJoinedByString: @" "]];
}
categories = [[[self fetchCoreInfos] objectForKey: @"flags"] objectEnumerator];
// remove all categories/labels from server which were not it the list sent from client
if (categories)
{
while ((currentFlag = [categories nextObject]))
{
// only deal with lables and don't touch flags like seen and flagged
if (([v objectForKey: currentFlag]))
{
if (![o isKindOfClass: [NSArray class]])
{
[self removeFlags: currentFlag];
}
else if (([o indexOfObject: [[v objectForKey:currentFlag] objectAtIndex:0]] == NSNotFound))
{
[self removeFlags: currentFlag];
}
}
}
}
}
}
@end
@@ -61,7 +61,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[response setHeader: @"private" forKey: @"Cache-Control"];
[response setHeader: @"OPTIONS, POST" forKey: @"Allow"];
[response setHeader: @"14.1" forKey: @"MS-Server-ActiveSync"];
[response setHeader: @"2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
[response setHeader: @"2.0,2.1,2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
[response setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
[response setHeader: @"OPTIONS, POST" forKey: @"Public"];
}
+14 -46
View File
@@ -40,7 +40,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGExtensions/NSString+misc.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WORequest.h>
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalDateTime.h>
@@ -275,20 +274,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
o = [o activeSyncRepresentationInContext: context];
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
{
[s appendFormat: @"<Body xmlns=\"Calendar:\">%@</Body>", o];
[s appendString: @"<BodyTruncated xmlns=\"Calendar:\">0</BodyTruncated>"];
}
else
{
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
@@ -404,17 +394,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
// FIXME: merge with iCalToDo
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
{
if ((o = [theValues objectForKey: @"Body"]))
[self setComment: o];
}
else
{
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setComment: o];
}
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setComment: o];
if ((o = [theValues objectForKey: @"Location"]))
[self setLocation: o];
@@ -506,14 +488,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[self setOrganizer: person];
}
//
// iOS is plain stupid here. It seends event invitations with no Organizer.
// We check this corner-case and if MeetingStatus == 1 (see http://msdn.microsoft.com/en-us/library/ee219342(v=exchg.80).aspx or details)
// and there's no organizer, we fake one.
//
if ((o = [theValues objectForKey: @"MeetingStatus"]))
{
//
// iOS is plain stupid here. It seends event invitations with no Organizer.
// We check this corner-case and if MeetingStatus == 1 (see http://msdn.microsoft.com/en-us/library/ee219342(v=exchg.80).aspx or details)
// and there's no organizer, we fake one.
//
if ([o intValue] == 1 && ![theValues objectForKey: @"Organizer_Email"] && ![[[self organizer] rfc822Email] length])
if ([o intValue] == 1 && ![theValues objectForKey: @"Organizer_Email"])
{
iCalPerson *person;
@@ -523,20 +505,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[person setPartStat: @"ACCEPTED"];
[self setOrganizer: person];
}
//
// When MeetingResponse fails Outlook still sends a new calendar entry with MeetingStatus=3.
// Use the organizer from the request if the event has no organizer.
//
if ([o intValue] == 3 && [theValues objectForKey: @"Organizer_Email"] && ![[[self organizer] rfc822Email] length])
{
iCalPerson *person;
person = [iCalPerson elementWithTag: @"organizer"];
[person setEmail: [theValues objectForKey: @"Organizer_Email"]];
[person setCn: [theValues objectForKey: @"Organizer_Name"]];
[person setPartStat: @"ACCEPTED"];
[self setOrganizer: person];
}
}
+11 -46
View File
@@ -38,7 +38,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGExtensions/NSString+misc.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WORequest.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
@@ -50,7 +49,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "NSDate+ActiveSync.h"
#include "NSString+ActiveSync.h"
@implementation iCalToDo (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
@@ -64,10 +62,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
s = [NSMutableString string];
// Complete
[s appendFormat: @"<Complete xmlns=\"Tasks:\">%d</Complete>", [[self status] isEqualToString: @"COMPLETED"] ? 1 : 0];
o = [self completed];
[s appendFormat: @"<Complete xmlns=\"Tasks:\">%d</Complete>", (o ? 1 : 0)];
// DateCompleted
if ((o = [self completed]))
if (o)
[s appendFormat: @"<DateCompleted xmlns=\"Tasks:\">%@</DateCompleted>", [o activeSyncRepresentationInContext: context]];
// Start date
@@ -98,7 +97,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Reminder - FIXME
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
// Sensitivity
if ([[self accessClass] isEqualToString: @"PRIVATE"])
v = 2;
else if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
@@ -106,8 +104,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
v = 0;
[s appendFormat: @"<Sensitivity xmlns=\"Tasks:\">%d</Sensitivity>", v];
categories = [self categories];
if ([categories count])
@@ -130,20 +126,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
o = [o activeSyncRepresentationInContext: context];
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
{
[s appendFormat: @"<Body xmlns=\"Tasks:\">%@</Body>", o];
[s appendString: @"<BodyTruncated xmlns=\"Tasks:\">0</BodyTruncated>"];
}
else
{
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
return s;
@@ -165,16 +152,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[self setSummary: o];
// FIXME: merge with iCalEvent
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
{
if ((o = [theValues objectForKey: @"Body"]))
[self setComment: o];
}
else
{
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setComment: o];
}
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setComment: o];
if ([[theValues objectForKey: @"Complete"] intValue] &&
((o = [theValues objectForKey: @"DateCompleted"])) )
@@ -186,11 +166,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[completed setDate: o];
[self setStatus: @"COMPLETED"];
}
else
{
[self setStatus: @"IN-PROCESS"];
[self setCompleted: nil];
}
if ((o = [theValues objectForKey: @"DueDate"]))
{
@@ -202,16 +177,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[due setDateTime: o];
}
if ((o = [theValues objectForKey: @"StartDate"]))
{
iCalDateTime *due;
o = [o calendarDate];
due = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
[due setTimeZone: tz];
[due setDateTime: o];
}
// 2 == high, 1 == normal, 0 == low
if ((o = [theValues objectForKey: @"Importance"]))
{
-4552
View File
File diff suppressed because it is too large. Load diff
+5655
View File
File diff suppressed because it is too large. Load diff
-157
View File
@@ -1,157 +0,0 @@
https://wiki.inverse.ca/focus/SOGo/CodingStyle
https://wiki.inverse.ca/focus/SOGo/D%C3%A9veloppement
https://wiki.inverse.ca/focus/PacketFence/Devel/BestPractices
UI and UX
---------
* http://www.google.com/design/spec/material-design/
* http://goodui.org/
* Try Repeating Your Primary Action instead of showing it just once.
* Try Distinct Clickable/Selected Styles instead of blurring them.
* Try Undos instead of prompting for confirmation.
* Try More Contrast instead of similarity.
* Try Exposing Options instead of hiding them.
* Try Showing State instead of being state agnostic.
* Try Direct Manipulation instead of contextless menus.
* Try Exposing Fields instead of creating extra pages.
* Try Transitions instead of showing changes instantly.
* Try Fewer Borders instead of wasting attention.
* Try Designing For Zero Data instead of just data heavy cases.
* Try Consistency instead of making people relearn.
* Try Conventions instead of reinventing the wheel.
* Try Visual Hierarchy instead of dullness.
* Try Grouping Related Items instead of disordering.
* Try Inline Validation instead of delaying errors.
* Try Forgiving Inputs instead of being strict with data.
* Try Bigger Click Areas instead of tiny ones.
* Try Faster Load Times instead of making people wait.
* Try Keyboard Shortcuts instead of buttons only.
* Try Upfront Progress instead of starting with a blank.
* Try Softer Prompts instead of modal windows.
* Try Multifunctional Controls instead of more parts.
* Try Icon Labels instead of opening for interpretation.
* http://designmodo.com/create-style-guides/
* http://uxmyths.com/
Frameworks & Tools
------------------
GNUstep
~~~~~~~
SOPE
~~~~
AngularJS
~~~~~~~~~
* https://angularjs.org/
* http://angular-ui.github.io/ui-router/
* https://www.airpair.com/angularjs/posts/angularjs-tutorial
Angular Material
~~~~~~~~~~~~~~~~
* https://material.angularjs.org/
Lo-Dash
~~~~~~~
* http://lodash.com/
* http://underscorejs.org/
Code Style
----------
Objective-C
~~~~~~~~~~~
* To document the Web APIs, we follow the http://apidocjs.com/[APIDOC] standards.
apidoc -f ".*\\.m" -i UI -o Documentation/JSON-API
HTML
~~~~
* Localize your strings:
<var:string label:value="I'm localized!"/>
* Localize your attributes:
<input type="text" label:placeholder="I'm localized!"/>
* Reuse existing localized strings as much as possible. Otherwise don't forget to update the English Localizable.strings file of the appropriate module.
JavaScript
~~~~~~~~~~
* http://eslint.org/
* https://github.com/toddmotto/angularjs-styleguide
* https://github.com/angular/material/blob/master/docs/guides/CODING.md
* We conform to https://github.com/airbnb/javascript[Airbnb coding standards]. Use https://github.com/jscs-dev/node-jscs[jscs] with the 'airbnb' preset to validate your code style:
jscs -p airbnb *.js
* For documentation, we follow the http://usejsdoc.org/[JSDoc3] standards:
jsdoc UI/WebServerResources/js/{Appointments,Common,Contacts,Mailer}/*.js -d Documentation/JavaScript-API
Models (facades)
^^^^^^^^^^^^^^^^
////
http://trochette.github.io/Angular-Design-Patterns-Best-Practices/
////
* Move business logic into models and share them.
* Keep it simple, separate server interaction and error handling from the model. That way model only handle data processing and code is easier to maintain.
SASS/CSS
~~~~~~~~
* http://componentcss.com/
* https://github.com/styleguide/css
* https://smacss.com/
* For documentation, we follow http://sassdoc.com/[SassDoc] annotations.
* We need the SASS files of Angular Material to build our CSS. The git repository of Angular Material is included as a submodule of SOGo:
git submodule init
git submodule update
* FlexBox compatibility http://caniuse.com/#feat=flexbox
Fonts
^^^^^
* We build a custom icons font using the online app https://icomoon.io/app/#/select[icomoon].
* http://www.carrois.com/fira-4-0/
* Material Design Iconic Font http://zavoloklom.github.io/material-design-iconic-font/icons.html
Version Control
---------------
* https://devcharm.com/articles/46/improve-your-git-workflow/
* Each commit should cover only one thing;
* Begin the commit message with a single short (less than 50 characters) line summarizing the change, followed by a blank line and then a more thorough description;
* When fixing a bug, commit to the devel branch as well as the maintenance branch of the latest release version (named maintenance/x.y). When a ticket is associated to the bug, add to the description a line saying *Fixes #1234*.
* `git pull` may introduce http://stackoverflow.com/questions/15316601/in-what-cases-could-git-pull-be-harmful[inconsistencies and problems]. Replace it with the following alias:
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
Testing
-------
* https://github.com/angular/protractor
* http://karma-runner.github.io/
JSON API
~~~~~~~~
One practical way to test the JSON API is to use `curl`. To do so, you need to enable `SOGoTrustProxyAuthentication` and configure HTTP authentifcation in Apache. You can pipe the result to [jq](http://stedolan.github.io/jq/) to nicely format and filter the output:
curl -u username:password http://localhost/SOGo/so/username/Calendar/calendarslist | jq '.'
curl -u username:password -H 'Content-Type: application/json' -d '{}' http://localhost/SOGo/so/francis/Calendar/personal/71B6-54904400-1-7C308500.ics/save
+25 -164
View File
@@ -167,9 +167,9 @@ Operating System Requirements
The following 32-bit and 64-bit operating systems are currently
supported by SOGo:
* Red Hat Enterprise Linux (RHEL) Server 5, 6 and 7
* Community ENTerprise Operating System (CentOS) 5, 6 and 7
* Debian GNU/Linux 6.0 (Squeeze) to 8.0 (Jessie)
* Red Hat Enterprise Linux (RHEL) Server 5 and 6
* Community ENTerprise Operating System (CentOS) 5 and 6
* Debian GNU/Linux 5.0 (Lenny) to 7.0 (Wheezy)
* Ubuntu 10.04 (Lucid) to 14.04 (Trusty)
Make sure the required components are started automatically at boot time
@@ -194,8 +194,7 @@ Installation
This section will guide you through the installation of SOGo together
with its dependencies. The steps described here apply to an RPM-based
installation for a Red Hat or CentOS 6 distribution. Most of these steps
should apply to all supported operating systems.
installation for a Red Hat or CentOS distribution.
Software Downloads
~~~~~~~~~~~~~~~~~~
@@ -567,29 +566,17 @@ usernames like this: `SOGoSuperUsernames = (<username1>[, <username2>, ...]);`
for SOGo. Possible values are:
[options="compact"]
* `Arabic`
* `Basque`
* `BrazilianPortuguese`
* `Catalan`
* `Czech`
* `Danish`
* `Dutch`
* `English`
* `Finnish`
* `French`
* `German`
* `Hungarian`
* `Icelandic`
* `Italian`
* `NorwegianBokmal`
* `NorwegianNynorsk`
* `Polish`
* `Russian`
* `Slovak`
* `SpanishSpain`
* `SpanishArgentina`
* `Spanish`
* `Swedish`
* `Ukrainian`
* `Welsh`
|D |SOGoNotifyOnPersonalModifications
@@ -662,7 +649,7 @@ of 1 day by default.
|Parameter used to configure which languages are available from SOGo's
Web interface. Available languages are specified as an array of string.
The default value is: `( "Arabic", "Basque", "Catalan", "Czech", "Dutch", "Danish", "Welsh", "English", "SpanishSpain", "SpanishArgentina", "Finnish", "French", "German", "Icelandic", "Italian", "Hungarian", "BrazilianPortuguese", "NorwegianBokmal", "NorwegianNynorsk", "Polish", "Russian", "Slovak", "Ukrainian", "Swedish" )`
The default value is: `( "Czech", "Welsh", "English", "Spanish", "French", "German", "Italian", "Hungarian", "Dutch", "BrazilianPortuguese", "Polish", "Russian", Ukrainian", "Swedish" )`
|D |SOGoHideSystemEMail
|Parameter used to control if SOGo should hide or not the system email
@@ -856,7 +843,7 @@ source:
[cols="^3,>47,50a"]
|=======================================================================
.34+|D <|SOGoUserSources
.33+|D <|SOGoUserSources
|Parameter used to set the LDAP and/or SQL sources used for
authentication and global address books. Multiple sources can be
specified as an array of dictionaries. A dictionary that defines an LDAP
@@ -1016,14 +1003,6 @@ this feature, every LDAP requests will fail. Note that some LDAP servers
require LDAP/SSL for password policies to work. This is the case for
example with 389 Directory Server.
|updateSambaNTLMPasswords
|If set to `YES`, SOGo will automatically update the sambaNTPassword
and sambaLMPassword attributes when changing passwords. The attributes
must be called sambaNTPassword and sambaLMPassword. You must also make
sure the correct ACL is set in your LDAP server to allow users to change
their own sambaNTPassword and sambaLMPassword password attributes.
Defaults to `NO` when unset.
|isAddressBook
|If set to `YES`, this LDAP source is used as a shared address book
(with read-only access). Note that if set to `NO`, autocompletion will
@@ -1035,8 +1014,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`,
and/or `ActiveSync` for example:
attribute; must be a dictionary with keys `Mail`, and/or `Calendar`, for
example:
----
ModulesConstraints = {
@@ -1061,11 +1040,6 @@ of supported attributes.
user addressbooks (see _abOU_ below), this list of object classes will
be applied to new records as they are created.
|GroupObjectClasses
|A list (array) of names identifying groups within the LDAP source. If not
set, SOGo will use `group`, `groupofnames`, `groupofuniquenames`
and `posixgroup`.
|modifiers
|A list (array) of usernames that are authorized to perform
modifications to the address book defined by this LDAP source.
@@ -1355,27 +1329,27 @@ The following table describes the parameters that were set:
[cols="3,47,50a"]
|=======================================================================
|S |SOGoProfileURL
|D |SOGoProfileURL
|Parameter used to set the database URL so that SOGo can retrieve user
profiles.
For MySQL, set the database URL to something like:
`mysql://sogo:sogo@localhost:3306/sogo/sogo_user_profile`.
|S |OCSFolderInfoURL
|D |OCSFolderInfoURL
|Parameter used to set the database URL so that SOGo can retrieve the
location of user folders (address books and calendars).
For Oracle, set the database URL to something like:
`oracle://sogo:sogo@localhost:1526/sogo/sogo_folder_info`.
|S |OCSSessionsFolderURL
|D |OCSSessionsFolderURL
|Parameter used to set the database URL so that SOGo can store and
retrieve secured user sessions information. For PostgreSQL, the database
URL could be set to something like:
`postgresql://sogo:sogo@localhost:5432/sogo/sogo_sessions_folder`.
|S |OCSEMailAlarmsFolderURL
|D |OCSEMailAlarmsFolderURL
|Parameter used to set the database URL for email-based alarms (that can
be set on events and tasks). This parameter is relevant only if
_SOGoEnableEMailAlarms_ is set to `YES`. For PostgreSQL, the database
@@ -1707,13 +1681,6 @@ cronjob `sogo-tmpwatch`.
Defaults to `/var/spool/sogo`.
|S |NGMimeBuildMimeTempDirectory
|Parameter used to set the path where temporary files will be stored
by SOPE when dealing with MIME messages.
Defaults to `/tmp`.
|S |NGImap4DisableIMAP4Pooling
|Disables IMAP pooling when set to `YES`. Enable pooling by setting to
`NO` or using a caching proxy like imapproxy.
@@ -1817,12 +1784,6 @@ host.
Defaults to `NO` when unset.
|D |SOGoForwardConstraints
|Parameter used to set constraints on possible addresses used when
automatically forwarding mails. When set to `0` (default), no constraint
is enforced. When set to `1`, only internal domains can be used. When
set to `2`, only external domains can be used.
|D |SOGoSieveScriptsEnabled
|Parameter used to activate the edition from the preferences windows of
server-side mail filters. Requires Sieve script support on the IMAP
@@ -1920,11 +1881,10 @@ events. This parameter is an array of arbitrary strings.
Defaults to a list that depends on the language.
|U |SOGoCalendarCategoriesColors
|Parameter used to define the colour of categories. This parameter
is a dictionary of category name/color.
|U |SOGoCalendarDefaultCategoryColor
|Parameter used to define the default colour of categories.
Defaults to `#F0F0F0` for all categories when unset.
Defaults to `#F0F0F0` when unset.
|U |SOGoCalendarEventsDefaultClassification
|Parameter used to defined the default classification for new events.
@@ -2137,8 +2097,7 @@ Multi-domains Configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want your installation to isolate two groups of users, you must
define a distinct authentication source for each _domain_. Your domain keys
must have the same value as your email domain you want to add. Following is
define a distinct authentication source for each _domain_. Following is
the same configuration that now includes two domains (acme.com and
coyote.com):
@@ -2146,7 +2105,7 @@ coyote.com):
{
...
domains = {
acme.com = {
acme = {
SOGoMailDomain = acme.com;
SOGoDraftsFolderName = Drafts;
SOGoUserSources = (
@@ -2167,7 +2126,7 @@ coyote.com):
}
);
};
coyote.com = {
coyote = {
SOGoMailDomain = coyote.com;
SOGoIMAPServer = imap.coyote.com;
SOGoUserSources = (
@@ -2198,7 +2157,7 @@ domains.
[cols="3,47,50a"]
|=======================================================================
|S |SOGoEnableDomainBasedUID
|Parameter used to enable user identification by domain. Users will be
|Parameter used to activate user identification by domain. Users will be
able (without being required) to login using the form `username@domain`,
meaning that values of _UIDFieldName_ no longer have to be unique among
all domains but only within the same domain. Internally, users will
@@ -2387,8 +2346,8 @@ easier. These GUI utilities can make use of templates to create and
pre-configure typical user accounts or any standardized LDAP record,
along with the correct object classes, fields and default values.
Microsoft Enterprise ActiveSync
-------------------------------
Microsoft ActiveSync
--------------------
SOGo supports the Microsoft ActiveSync protocol.
@@ -2454,23 +2413,17 @@ Defaults to `0`, which means no overwrite is performed.
Setting this parameter to a value greater than `512` will
have unexpected behaviour with various ActiveSync clients.
|S |SOGoEASDebugEnabled
|Parameter used to log the complete request and response of every single
EAS command.
Defaults to `NO`, which means no logging is performed.
|=======================================================================
Please be aware of the following limitations:
* When creating an Outlook 2013 profile, you must actually kill Outlook
before the end of the creation process. See http://www.vionblog.com/connect-zimbra-community-with-outlook-2013
for a procedure example.
* Outlook 2013 does not search the GAL. One possible alternative
solution is to configure Outlook to use a LDAP server (over SSL) with
authentication. Outlook 2013 also does not seem to support multiple
address books over ActiveSync.
* To successfully synchronize Outlook email categories, a corresponding
mail label (Preferences->Mail Options) has to be created manually in SOGo
for each label defined in Outlook. The name in SOGo and in Outlook must be
identical.
* Make sure you do not use a self-signed certificate. While this will
work, Outlook will work intermittently as it will raise popups for
certificate validation, sometimes in background, preventing the user to
@@ -2507,83 +2460,6 @@ and send an email to iplicreq@microsoft.com
Inverse inc. provides this software for free, but is not responsible for
anything related to its usage.
Microsoft Enterprise ActiveSync Tuning
--------------------------------------
First of all, it is important to know that most EAS devices will keep
HTTP connections open to SOGo (and thus, Apache) for a long time. This
is required for "push" to work properly. Connections can stay open for
up to one hour, or 3600 seconds.
The first parameter to check is related to Apache's proxying to
SOGo:
----
ProxyPass /Microsoft-Server-ActiveSync \
http://127.0.0.1:20000/SOGo/Microsoft-Server-ActiveSync \
retry=60 connectiontimeout=5 timeout=360
----
The above line sets a timeout for up to 360 seconds, or 6 minutes. If
you want to let EAS clients keep their HTTP connections open for up
to an hour, you must change the timeout parameter and set it to 3600.
If you change this value, the WOWatchDogRequestTimeout parameter must be changed
accordingly in SOGo's configuration file (/etc/sogo/sogo.conf). By default,
a SOGo child process is allowed to handle a request that can take up
to 10 minutes before it gets killed by its parent process. When using
EAS "push", the client expects to keep its connection open for up to one
hour - so the WOWatchDogRequestTimeout, which is set in minutes,
must be adjusted accordingly.
EAS clients will keep HTTP connections open for a long time
during these two EAS commands: Ping and Sync. By default, SOGo will prevent
EAS clients from keeping connections for a long time. This is to avoid the
situation where all SOGo child processes would be monopolized by EAS clients -
rendering the SOGo web interface or DAV interface unavailable. The
default SOGo behavior is thus similar to disable EAS push entirely.
Two SOGo configuration parameters are available to modify this behavior:
SOGoMaximumPingInterval (set by default to 10 seconds) and
SOGoMaximumSyncInterval (set by default to 30 seconds). If you want
connection to stay open for up to one hour, you should set these
slightly under 3600 seconds (say 3540 - or 59 minutes). During a
long-lived HTTP connection, the SOGo child process will perform
internal polling to detect changes and return them to the EAS client
if any changes are found. The parameter used to control this
is SOGoInternalSyncInterval. By default, polling is done every 10
seconds. This might generate too much load on large-scale system.
The last configuration parameter to adjust is WOWorkersCount - which sets the
number of SOGo child process that will be used to handle requests.
You should have at least one child per EAS device configured to use
"push". You must also have more children than you have EAS devices
configured to use "push" - in order to handle normal SOGo requests to
its Web or DAV interfaces.
Here are some usage examples for EAS devices using "push". In all
cases, the Apache timeout is set to 3600 and the
WOWatchDogRequestTimeout parameter is set to 60.
Example 1 - 100 users, 10 EAS devices:
----
WOWorkersCount = 15;
SOGoMaximumPingInterval = 3540;
SOGoMaximumSyncInterval = 3540;
SOGoInternalSyncInterval = 30;
----
Example 2 - 1000 users, 100 EAS devices:
----
WOWorkersCount = 120;
SOGoMaximumPingInterval = 3540;
SOGoMaximumSyncInterval = 3540;
SOGoInternalSyncInterval = 60;
----
Using SOGo
----------
@@ -2713,21 +2589,6 @@ current version of SOGo from the previous release.
[cols="100a"]
|=======================================================================
h|2.3.1
|The SOGoCalendarDefaultCategoryColor default has been removed. If you
want to customize the color of calendar categories, use the
SOGoCalendarCategories and SOGoCalendarCategoriesColors defaults.
h|2.3.0
|Run the shell script `sql-update-2.2.17_to_2.3.0.sh` or
`sql-update-2.2.17_to_2.3.0-mysql.sh` (if you use MySQL).
This will grow the "participant states" field of calendar quick tables to a larger
size and add the the "c_description" column to calendar quick tables.
Moreover, if you are using a multi-domain configuration, make sure the keys for
your domains match the email domains you have defined.
h|2.2.8
|The configuration configuration parameters were renamed:
@@ -239,7 +239,7 @@ Red Hat Enterprise Linux v6 x86_64
If you are using Red Hat Enterprise Linux version 6 x86_64, packages
for Samba 4, OpenChange and SOGo and the SOGo OpenChange backend are
available from SOGo's web site. Please follow the instructions from
http://www.sogo.nu/english/downloads/backend.html.
http://www.sogo.nu/english/downloads/backend_nightly.html.
In order to satisfy certain dependencies, you should also add the EPEL
source corresponding to your distribution and architecture. More
@@ -266,30 +266,32 @@ from this guide.
[NOTE]
Samba4/OpenChange are not available for now on CentOS 5 i386/x86_64,
and CentOS 7. On Debian-based systems, packages are available only on
the x86_64 platform.
CentOS 6 i386 and CentOS 7.
Debian 7 (Wheezy) and Ubuntu 12.04 (Precise Pangolin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Debian 7.0 (Wheezy) and Ubuntu 12.04 (Precise Pangolin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SOGo, OpenChange and the SOGo OpenChange backend are now
available from SOGo's web site. Please follow the instructions from
http://www.sogo.nu/english/downloads/backend.html to setup your
apt sources.
On Debian7, for some Samba 4 dependencies, you need to use the
_wheezy-backports_ repository. To do so, create
`/etc/apt/sources.list.d/backports.list` with the following
content:
For Samba 4, you need to use the _wheezy-backports_ repository. To do so, create
`/etc/apt/sources.list.d/backports.list`:
deb http://http.debian.net/debian wheezy-backports main
On Ubuntu 12.04, you will also have to add the Wheezy sources:
deb http://ftp.us.debian.org/debian wheezy main
deb http://security.debian.org/ wheezy/updates main
Then install Samba 4 on top of an existing SOGo
installation:
----
apt-get update
apt-get install samba samba-dev
apt-get -t wheezy-backports install samba samba-dev
----
Once completed, install the packages related to OpenChange and the SOGo
@@ -301,12 +303,7 @@ apt-get install openchangeserver \
openchangeproxy \
python-ocsmanager \
mysql-server \
python-mysqldb \
openchange-ocsmanager \
openchange-rpcproxy \
python-sievelib \
python-spyne \
python-rpclib
python-mysqldb
----
Once the packages are installed, refer to the _Configuration_ chapter
@@ -318,8 +315,10 @@ 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)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ubuntu 14.04 (Trusty Tahr)
~~~~~~~~~~~~~~~~~~~~~~~~~~
For Ubuntu 14.04, you must not use the Debian Wheezy backports.
Please follow the instructions from
http://www.sogo.nu/english/downloads/backend.html to setup your
@@ -342,26 +341,12 @@ apt-get install openchangeserver \
openchangeproxy \
python-ocsmanager \
mysql-server \
python-mysqldb \
openchange-ocsmanager \
openchange-rpcproxy \
python-sievelib \
python-spyne \
python-rpclib
python-mysqldb
----
Once the packages are installed, refer to the _Configuration_ chapter
from this guide.
[NOTE]
The `ocsmanager.conf` and `rpcproxy.conf` are currently located in
`/etc/apache2/conf.d`. These should be moved to `/etc/apache2/conf-available`.
This is a packaging error that will soon be fixed.
[NOTE]
You might have to adjust the `rpcproxy.conf` configuration file to add the
`Require all granted` permission if you get Apache errors such as
`client denied by server configuration`.
Configuration
-------------
@@ -405,7 +390,6 @@ Add the following parameters to the `[global]` section of the
----
### Configuration required by OpenChange server ###
dsdb:schema update allowed = true
dcerpc endpoint servers = epmapper, mapiproxy, dnsserver
dcerpc_mapiproxy:server = true
dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
@@ -423,7 +407,6 @@ Your Samba 4 configuration file should look like this:
netbios name = sogo
passdb backend = samba4
### Configuration required by OpenChange server ###
dsdb:schema update allowed = true
dcerpc endpoint servers = +epmapper, +mapiproxy
dcerpc_mapiproxy:server = true
dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
@@ -550,7 +533,7 @@ 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`.
in `/etc/apache2/conf.d/`.
The configuration requires three Apache modules:  _mod_proxy_,
_mod_proxy_http_ and _mod_wsgi_. These are usually already installed but
@@ -558,17 +541,13 @@ might need to be activated on Debian-based installations:
a2enmod proxy proxy_http wsgi
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`.
uncommented in `/etc/httpd/conf.d/wsgi.conf` (or
`python26-mod_wsgi.conf` on RHELv5).
The _reqtimeout_ apache module is known to cause problems when using the
default configuration shipped with Debian-based systems. On such
distributions, Apache will close (HTTP/1.1 500) any HTTP request for
distributions, apache will close (HTTP/1.1 500) any HTTP request for
which the HTTP body hasn't arrived in 10 seconds.
While this is arguably good practice with regular HTTP, it will disrupt
@@ -588,102 +567,9 @@ On Debian-based distributions, do:
update-rc.d apache2 defaults && /etc/init.d/apache2 restart
Finally, you must adjust the OCS Manager configuration file, which is
located in `/etc/ocsmanager/ocsmanager.ini`. You should enable LDAP-based
authentication in the `main` section and configure it accordingly. You should
also enable rpcproxy. You file should be similar to this one:
----
[DEFAULT]
debug = true
email_to = you@yourdomain.com
smtp_server = localhost
error_email_from = paste@localhost
[main]
auth = ldap
mapistore_root = /var/lib/samba/private
mapistore_data = /var/lib/samba/private/mapistore
debug = yes
[auth:file]
[auth:ldap]
host = ldap://127.0.0.1
port = 389
bind_dn = cn=administrator,cn=Users,dc=example,dc=com
bind_pw = %1OpenChange
basedn = cn=Users,dc=example,dc=com
[auth:single]
username = openchange
password = {SSHA}I6Hy5Wv0wuxyXvMBFWFQDVVN12_CLaX9
[server:main]
use = egg:Paste#http
host = 127.0.0.1
port = 5000
protocol_version = HTTP/1.1
[app:main]
use = egg:ocsmanager
full_stack = true
static_files = true
cache_dir = %(here)s/data
beaker.session.key = ocsmanager
beaker.session.secret = SDyKK3dKyDgW0mlpqttTMGU1f
app_instance_uuid = {ee533ebc-f266-49d1-ae10-d017ee6aa98c}
NTLMAUTHHANDLER_WORKDIR = /var/cache/ntlmauthhandler
SAMBA_HOST = 127.0.0.1
[rpcproxy:ldap]
host = localhost
port = 389
basedn = CN=Users,DC=example,DC=com
set debug = true
----
----
[autodiscover]
[autodiscover:rpcproxy]
enabled = true
[outofoffice]
[outofoffice:file]
sieve_script_path = /var/vmail/$domain/$user/sieve-script
sieve_script_path_mkdir = false
[outofoffice:managesieve]
secret = secret
[loggers]
keys = root
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = INFO
handlers = console
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s
----
Once completed, start the OCS Manager service:
/etc/init.d/openchange-ocsmanager start
[NOTE]
Debian-based distributions are not supported anymore for
OCSManager/rpcproxy. Support will soon resume.
Name Service Configuration for Web Services
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+3 -3
View File
@@ -1,7 +1,7 @@
<!-- TODO have the build system take care of this -->
<releaseinfo>Version 2.3.1 - July 2015</releaseinfo>
<subtitle>for version 2.3.1</subtitle>
<date>2015-07-23</date>
<releaseinfo>Version 2.2.14 - January 2015</releaseinfo>
<subtitle>for version 2.2.14</subtitle>
<date>2015-01-20</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>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

@@ -13,6 +13,6 @@
// TODO have the build system take care of this
:release_version: 2.3.1
:release_version: 2.2.14
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:
+2 -2
View File
@@ -245,7 +245,7 @@ static BOOL debugLeaks;
}
else
{
[self errorWithFormat: @"No value specified for '%@'", *urlString];
NSLog (@"No value specified for '%@'", *urlString);
ok = NO;
}
}
@@ -441,7 +441,7 @@ static BOOL debugLeaks;
if (debugLeaks)
{
if (debugOn)
[self logWithFormat: @"allocated classes:\n%s", GSDebugAllocationList (YES)];
NSLog (@"allocated classes:\n%s", GSDebugAllocationList (YES));
else
{
debugOn = YES;
+4 -4
View File
@@ -1,15 +1,15 @@
/*
Copyright (C) 2004-2005 SKYRIX Software AG
Copyright (C) 2006-2015 Inverse inc.
Copyright (C) 2006-2009 Inverse inc.
This file is part of SOGo.
This file is part of OpenGroupware.org.
SOGo is free software; you can redistribute it and/or modify it under
OGo is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
OGo is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
-173
View File
@@ -1,176 +1,3 @@
2.3.x (2015-MM-DD)
------------------
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)
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
- added Slovenian translation - thanks to Jens Riecken
- added Chinese (Taiwan) translation
Bug fixes
- EAS's GetItemEstimate/ItemOperations now support fetching mails and empty folders
- fixed some rare cornercases in multidomain configurations
- properly escape folder after creation using EAS (#3237)
- fixed potential organizer highjacking when using EAS (#3131)
- 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)
-------------------
New features
- Internet headers are now shown in Outlook (Zentyal)
Enhancements
- improved multipart handling using EAS
- added systemd startup script (PR#76)
- added Basque translation - thanks to Gorka Gonzalez
- updated Brazilian (Portuguese), Dutch, Norwegian (Bokmal), Polish, Russian, and Spanish (Spain) translations
- calendar sharing request support among different Outlook versions (Zentyal)
- improved sync speed from Outlook by non-reprocessing already downloaded unread mails (Zentyal)
- added support for sharing calendar invitations
- missing contact fields are now saved and available when sharing it (Office, Profession, Manager's name, Assistant's name, Spouse/Partner, Anniversary) (Zentyal)
- appointment color and importance work now between Outlooks (Zentyal)
- synchronize events, contacts and tasks in reverse chronological order (Zentyal)
- during login, we now extract the domain from the user to accelerate authentication requests on sources
- make sure sure email invitations can always be read by EAS clients
- now able to print event/task's description (new components only) in the list view (#2881)
- now possible to log EAS commands using the SOGoEASDebugEnabled system defaults
- many improvements to EAS SmartReply/SmartForward commands
- event invitation response mails from Outlook are now sent
- mail subfolders created in WebMail are created when Outlook synchronises
- mail root folder created in WebMail (same level INBOX) are created on Outlook logon
Bug fixes
- now keep the BodyPreference for future EAS use and default to MIME if none set (#3146)
- EAS reply fix when message/rfc822 parts are included in the original mail (#3153)
- fixed yet an other potential crash during freebusy lookups during timezone changes
- fixed display of freebusy information in event attendees editor during timezone changes
- fixed timezone of MSExchange freebusy information
- fixed a potential EAS error with multiple email priority flags
- fixed paragraphs margins in HTML messages (#3163)
- fixed regression when loading the inbox for the first time
- fixed serialization of the PreventInvitationsWhitelist settings
- fixed md4 support (for NTLM password changes) with GNU TLS
- fixed edition of attachment URL in event/task editor
- sent mails are not longer in Drafts folder using Outlook (Zentyal)
- deleted mails are properly synced between Outlook profiles from the same account (Zentyal)
- does not create a mail folder in other user's mailbox (Zentyal)
- fix server-side crash with invalid events (Zentyal)
- fix setting permissions for a folder with several users (Zentyal)
- fix reception of calendar event invitations on optional attendees (Zentyal)
- fix server side crash parsing rtf without color table (Zentyal)
- weekly recurring events created in SOGo web interface are now shown in Outlook (Zentyal)
- fix exception modifications import in recurrence series (Zentyal)
- fix server side crash parsing rtf emails with images (with word97 format) (Zentyal)
- fix sender on importing email messages like event invitations (Zentyal)
- fix Outlook crashes when modifying the view of a folder (Zentyal)
- fix server side crash when reading some recurrence appointments (Zentyal)
- Outlook clients can use reply all functionality on multidomain environment (Zentyal)
- optional attendes on events are now shown properly (Zentyal)
- fixed the EAS maximum response size being per-folder, and not global
- now set MeetingMessageType only for EAS 14.1
- now correctly handle external invitations using EAS
- now correctly handle multiple email addresses in the GAL over EAS (#3102)
- now handle very large amount of participants correctly (#3175)
- fix message bodies not shown on some EAS devices (#3173)
- avoid appending the domain unconditionally when SOGoEnableDomainBasedUID is set to YES
- recurrent all day events are now shown properly in Outlook
2.2.17a (2015-03-15)
--------------------
Bug fixes
- avoid calling -stringByReplacingOccurrencesOfString:... for old GNUstep runtime
2.2.17 (2015-03-24)
-------------------
Enhancements
- support for mail prority using EAS
- immediately delete mails from EAS clients when they are marked as deleted on the IMAP server
- now favor login@domain as the default email address if multiple mail: fields are specified
- enable by default HTML mails support using EAS on Windows and BB phones
- now possible to configure objectClass names for LDAP groups using GroupObjectClasses (#1499)
Bug fixes
- fixed login issue after password change (#2601)
- fixed potential encoding issue using EAS and 8-bit mails (#3116)
- multiple collections support for GetItemEstimate using EAS
- fixed empty sync responses for EAS 2.5 and 12.0 clients
- use the correct mail body element for EAS 2.5 clients
- fixed tasks disappearing issue with RoadSync
- use the correct body element for events for EAS 2.5 clients
- SmartReply improvements for missing body attributes
- do not use syncKey from cache when davCollectionTag = -1
- use correct mail attachment elements for EAS 2.5 clients
- fixed contacts lookup by UID in freebusy
- reduced telephone number to a single value in JSON response of contacts list
- fixed freebusy data when 'busy off hours' is enabled and period starts during the weekend
- fixed fetching of freebusy data from the Web interface
- fixed EAS handling of Bcc in emails (#3138)
- fixed Language-Region tags in Web interface (#3121)
- properly fallback over EAS to UTF-8 and then Latin1 for messages w/o charset (#3103)
- prevent potential freebusy lookup crashes during timezone changes with repetitive events
- improved GetItemEstimate to count all vasnished/deleted mails too
- improvements to EAS SyncKey handling to avoid missing mails (#3048, #3058)
- fixed EAS replies decoding from Outlook (#3123)
2.2.16 (2015-02-12)
-------------------
New features
- now possible for SOGo to change the sambaNTPassword/sambaLMPassword
- now possible to limit automatic forwards to internal/external domains
Enhancements
- added support for email categories using EAS (#2995)
- now possible to always send vacation messages (#2332)
- added EAS best practices to the documentation
- improved fetching of text parts over EAS
- updated Czech, Finnish, French, German and Hungarian translations
Bug fixes
- (regression) fixed sending a message when mail module is not active (#3088)
- mail labels with blanks are not handled correctly (#3078)
- fixed BlackBerry issues sending multiple mails over EAS (#3095)
- fixed plain/text mails showing on one line on Android/EAS (#3055)
- fixed exception in sogo-tool when parsing arguments of a set operation
2.2.15 (2015-01-30)
-------------------
Enhancements
- improved handling of EAS Push when no heartbeat is provided
- no longer need to kill Outlook 2013 when creating EAS profiles (#3076)
- improved server-side CSS cleaner (#3040)
- unified the logging messages in sogo.log file (#2534/#3063)
- updated Brazilian (Portuguese) and Hungarian translations
2.2.14 (2015-01-20)
-------------------
-34
View File
@@ -1,34 +0,0 @@
/* Codepages.h - this file is part of SOGo
*
* Copyright (C) 2014 Jesús García Sáez
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSDictionary.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSString.h>
@interface Codepages
+ (NSDictionary *) getCodepagesTable;
+ (NSDictionary *) getReverseCodepagesTable;
+ (NSNumber *) getCodepageFromName: (NSString *) name;
+ (NSString *) getNameFromCodepage: (NSNumber *) codepage;
@end
-214
View File
@@ -1,214 +0,0 @@
/* Codepages.m - this file is part of SOGo
*
* Copyright (C) 2014 Jesús García Sáez
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import "Codepages.h"
#import <Foundation/NSArray.h>
@implementation Codepages
+ (NSDictionary *) getCodepagesTable
{
static NSDictionary *table = nil;
if (table == nil)
{
/* http://msdn.microsoft.com/en-us/library/dd317756%28v=vs.85%29.aspx */
table = [[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt: 37], @"ibm037",
[NSNumber numberWithInt: 437], @"ibm437",
[NSNumber numberWithInt: 500], @"ibm500",
[NSNumber numberWithInt: 708], @"asmo-708",
[NSNumber numberWithInt: 720], @"dos-720",
[NSNumber numberWithInt: 737], @"ibm737",
[NSNumber numberWithInt: 775], @"ibm775",
[NSNumber numberWithInt: 850], @"ibm850",
[NSNumber numberWithInt: 852], @"ibm852",
[NSNumber numberWithInt: 855], @"ibm855",
[NSNumber numberWithInt: 857], @"ibm857",
[NSNumber numberWithInt: 858], @"ibm00858",
[NSNumber numberWithInt: 860], @"ibm860",
[NSNumber numberWithInt: 861], @"ibm861",
[NSNumber numberWithInt: 862], @"dos-862",
[NSNumber numberWithInt: 863], @"ibm863",
[NSNumber numberWithInt: 864], @"ibm864",
[NSNumber numberWithInt: 865], @"ibm865",
[NSNumber numberWithInt: 866], @"cp866",
[NSNumber numberWithInt: 869], @"ibm869",
[NSNumber numberWithInt: 870], @"ibm870",
[NSNumber numberWithInt: 874], @"windows-874",
[NSNumber numberWithInt: 875], @"cp875",
[NSNumber numberWithInt: 932], @"shift_jis",
[NSNumber numberWithInt: 936], @"gb2312",
[NSNumber numberWithInt: 949], @"ks_c_5601-1987",
[NSNumber numberWithInt: 950], @"big5",
[NSNumber numberWithInt: 1026], @"ibm1026",
[NSNumber numberWithInt: 1047], @"ibm01047",
[NSNumber numberWithInt: 1140], @"ibm01140",
[NSNumber numberWithInt: 1141], @"ibm01141",
[NSNumber numberWithInt: 1142], @"ibm01142",
[NSNumber numberWithInt: 1143], @"ibm01143",
[NSNumber numberWithInt: 1144], @"ibm01144",
[NSNumber numberWithInt: 1145], @"ibm01145",
[NSNumber numberWithInt: 1146], @"ibm01146",
[NSNumber numberWithInt: 1147], @"ibm01147",
[NSNumber numberWithInt: 1148], @"ibm01148",
[NSNumber numberWithInt: 1149], @"ibm01149",
[NSNumber numberWithInt: 1200], @"utf-16",
[NSNumber numberWithInt: 1201], @"unicodefffe",
[NSNumber numberWithInt: 1250], @"windows-1250",
[NSNumber numberWithInt: 1251], @"windows-1251",
[NSNumber numberWithInt: 1252], @"windows-1252",
[NSNumber numberWithInt: 1253], @"windows-1253",
[NSNumber numberWithInt: 1254], @"windows-1254",
[NSNumber numberWithInt: 1255], @"windows-1255",
[NSNumber numberWithInt: 1256], @"windows-1256",
[NSNumber numberWithInt: 1257], @"windows-1257",
[NSNumber numberWithInt: 1258], @"windows-1258",
[NSNumber numberWithInt: 1361], @"johab",
[NSNumber numberWithInt: 10000], @"macintosh",
[NSNumber numberWithInt: 10001], @"x-mac-japanese",
[NSNumber numberWithInt: 10002], @"x-mac-chinesetrad",
[NSNumber numberWithInt: 10003], @"x-mac-korean",
[NSNumber numberWithInt: 10004], @"x-mac-arabic",
[NSNumber numberWithInt: 10005], @"x-mac-hebrew",
[NSNumber numberWithInt: 10006], @"x-mac-greek",
[NSNumber numberWithInt: 10007], @"x-mac-cyrillic",
[NSNumber numberWithInt: 10008], @"x-mac-chinesesimp",
[NSNumber numberWithInt: 10010], @"x-mac-romanian",
[NSNumber numberWithInt: 10017], @"x-mac-ukrainian",
[NSNumber numberWithInt: 10021], @"x-mac-thai",
[NSNumber numberWithInt: 10029], @"x-mac-ce",
[NSNumber numberWithInt: 10079], @"x-mac-icelandic",
[NSNumber numberWithInt: 10081], @"x-mac-turkish",
[NSNumber numberWithInt: 10082], @"x-mac-croatian",
[NSNumber numberWithInt: 12000], @"utf-32",
[NSNumber numberWithInt: 12001], @"utf-32be",
[NSNumber numberWithInt: 20000], @"x-chinese-cns",
[NSNumber numberWithInt: 20001], @"x-cp20001",
[NSNumber numberWithInt: 20002], @"x-chinese-eten",
[NSNumber numberWithInt: 20003], @"x-cp20003",
[NSNumber numberWithInt: 20004], @"x-cp20004",
[NSNumber numberWithInt: 20005], @"x-cp20005",
[NSNumber numberWithInt: 20105], @"x-ia5",
[NSNumber numberWithInt: 20106], @"x-ia5-german",
[NSNumber numberWithInt: 20107], @"x-ia5-swedish",
[NSNumber numberWithInt: 20108], @"x-ia5-norwegian",
[NSNumber numberWithInt: 20127], @"us-ascii",
[NSNumber numberWithInt: 20261], @"x-cp20261",
[NSNumber numberWithInt: 20269], @"x-cp20269",
[NSNumber numberWithInt: 20273], @"ibm273",
[NSNumber numberWithInt: 20277], @"ibm277",
[NSNumber numberWithInt: 20278], @"ibm278",
[NSNumber numberWithInt: 20280], @"ibm280",
[NSNumber numberWithInt: 20284], @"ibm284",
[NSNumber numberWithInt: 20285], @"ibm285",
[NSNumber numberWithInt: 20290], @"ibm290",
[NSNumber numberWithInt: 20297], @"ibm297",
[NSNumber numberWithInt: 20420], @"ibm420",
[NSNumber numberWithInt: 20423], @"ibm423",
[NSNumber numberWithInt: 20424], @"ibm424",
[NSNumber numberWithInt: 20833], @"x-ebcdic-koreanextended",
[NSNumber numberWithInt: 20838], @"ibm-thai",
[NSNumber numberWithInt: 20866], @"koi8-r",
[NSNumber numberWithInt: 20871], @"ibm871",
[NSNumber numberWithInt: 20880], @"ibm880",
[NSNumber numberWithInt: 20905], @"ibm905",
[NSNumber numberWithInt: 20924], @"ibm00924",
[NSNumber numberWithInt: 20932], @"euc-jp",
[NSNumber numberWithInt: 20936], @"x-cp20936",
[NSNumber numberWithInt: 20949], @"x-cp20949",
[NSNumber numberWithInt: 21025], @"cp1025",
[NSNumber numberWithInt: 21866], @"koi8-u",
[NSNumber numberWithInt: 28591], @"iso-8859-1",
[NSNumber numberWithInt: 28592], @"iso-8859-2",
[NSNumber numberWithInt: 28593], @"iso-8859-3",
[NSNumber numberWithInt: 28594], @"iso-8859-4",
[NSNumber numberWithInt: 28595], @"iso-8859-5",
[NSNumber numberWithInt: 28596], @"iso-8859-6",
[NSNumber numberWithInt: 28597], @"iso-8859-7",
[NSNumber numberWithInt: 28598], @"iso-8859-8",
[NSNumber numberWithInt: 28599], @"iso-8859-9",
[NSNumber numberWithInt: 28603], @"iso-8859-13",
[NSNumber numberWithInt: 28605], @"iso-8859-15",
[NSNumber numberWithInt: 29001], @"x-europa",
[NSNumber numberWithInt: 38598], @"iso-8859-8-i",
[NSNumber numberWithInt: 50220], @"iso-2022-jp",
[NSNumber numberWithInt: 50221], @"csiso2022jp",
[NSNumber numberWithInt: 50222], @"iso-2022-jp",
[NSNumber numberWithInt: 50225], @"iso-2022-kr",
[NSNumber numberWithInt: 50227], @"x-cp50227",
[NSNumber numberWithInt: 51932], @"euc-jp",
[NSNumber numberWithInt: 51936], @"euc-cn",
[NSNumber numberWithInt: 51949], @"euc-kr",
[NSNumber numberWithInt: 52936], @"hz-gb-2312",
[NSNumber numberWithInt: 54936], @"gb18030",
[NSNumber numberWithInt: 57002], @"x-iscii-de",
[NSNumber numberWithInt: 57003], @"x-iscii-be",
[NSNumber numberWithInt: 57004], @"x-iscii-ta",
[NSNumber numberWithInt: 57005], @"x-iscii-te",
[NSNumber numberWithInt: 57006], @"x-iscii-as",
[NSNumber numberWithInt: 57007], @"x-iscii-or",
[NSNumber numberWithInt: 57008], @"x-iscii-ka",
[NSNumber numberWithInt: 57009], @"x-iscii-ma",
[NSNumber numberWithInt: 57010], @"x-iscii-gu",
[NSNumber numberWithInt: 57011], @"x-iscii-pa",
[NSNumber numberWithInt: 65000], @"utf-7",
[NSNumber numberWithInt: 65001], @"utf-8",
nil] retain];
}
return table;
}
+ (NSDictionary *) getReverseCodepagesTable
{
static NSDictionary *table = nil;
if (table == nil)
{
NSDictionary *codepages_table;
NSEnumerator *enumerator;
NSMutableArray *codepages, *names;
id key;
// Build reverse table: (NSNumber) codepage -> (NSString) encoding name
codepages_table = [self getCodepagesTable];
codepages = [NSMutableArray arrayWithCapacity: [codepages_table count]];
names = [NSMutableArray arrayWithCapacity: [codepages_table count]];
enumerator = [codepages_table keyEnumerator];
while ((key = [enumerator nextObject]))
{
[names addObject: key];
[codepages addObject: [codepages_table objectForKey: key]];
}
table = [[NSDictionary dictionaryWithObjects: names forKeys: codepages] retain];
}
return table;
}
+ (NSNumber *) getCodepageFromName: (NSString *) name
{
return [[self getCodepagesTable] objectForKey: [name lowercaseString]];
}
+ (NSString *) getNameFromCodepage: (NSNumber *) codepage
{
return [[self getReverseCodepagesTable] objectForKey: codepage];
}
@end
+3 -8
View File
@@ -31,7 +31,7 @@ endif
all::
@echo " Python executable: ${PYTHON}"
SAMBA_PRIVATE_DIR = $(shell $(PYTHON) ./samba-get-config.py 'private dir' || echo /var/lib/samba/private)
SAMBA_PRIVATE_DIR = $(shell $(PYTHON) ./samba-get-config.py "private dir")
$(SOGOBACKEND)_PRINCIPAL_CLASS = MAPIApplication
@@ -100,7 +100,6 @@ $(SOGOBACKEND)_OBJC_FILES += \
MAPIStoreMailAttachment.m \
MAPIStoreMailContext.m \
MAPIStoreMailFolder.m \
MAPIStoreMailFolderTable.m \
MAPIStoreMailMessage.m \
MAPIStoreMailVolatileMessage.m \
MAPIStoreMailMessageTable.m \
@@ -111,8 +110,6 @@ $(SOGOBACKEND)_OBJC_FILES += \
\
MAPIStoreFallbackContext.m \
\
MAPIStoreSharingMessage.m \
\
NSArray+MAPIStore.m \
NSData+MAPIStore.m \
NSDate+MAPIStore.m \
@@ -123,9 +120,7 @@ $(SOGOBACKEND)_OBJC_FILES += \
iCalEvent+MAPIStore.m \
iCalTimeZone+MAPIStore.m \
\
RTFHandler.m \
\
Codepages.m
RTFHandler.m
$(SOGOBACKEND)_RESOURCE_FILES += \
@@ -176,7 +171,7 @@ $(SOGOBACKEND)_LIB_DIRS += \
$(LIBMAPISTORE_LIBS)
ADDITIONAL_INCLUDE_DIRS += \
-Wall \
-Werror -Wall \
-DSAMBA_PRIVATE_DIR=@"\"$(SAMBA_PRIVATE_DIR)\"" \
$(LIBMAPI_CFLAGS) \
$(LIBMAPISTORE_CFLAGS) \
+1 -2
View File
@@ -33,9 +33,8 @@
}
- (id) authenticatorInContext: (id) context;
- (MAPIStoreUserContext *) userContext;
- (void) setUserContext: (MAPIStoreUserContext *) newContext;
- (void) cleanup;
@end
-10
View File
@@ -76,11 +76,6 @@ MAPIApplication *MAPIApp = nil;
return NO;
}
- (MAPIStoreUserContext *) userContext
{
return userContext;
}
- (void) setUserContext: (MAPIStoreUserContext *) newContext
{
/* user contexts must not be retained here ad their holder (mapistore)
@@ -93,9 +88,4 @@ MAPIApplication *MAPIApp = nil;
return [userContext authenticator];
}
- (void) cleanup
{
[userContext deactivate];
}
@end
+29 -94
View File
@@ -45,7 +45,6 @@
#import "MAPIStoreRecurrenceUtils.h"
#import "MAPIStoreSamDBUtils.h"
#import "MAPIStoreTypes.h"
#import "NSArray+MAPIStore.h"
#import "NSData+MAPIStore.h"
#import "NSDate+MAPIStore.h"
#import "NSObject+MAPIStore.h"
@@ -264,7 +263,7 @@ static NSCharacterSet *hexCharacterSet = nil;
if (contactInfos)
{
username = [contactInfos objectForKey: @"sAMAccountName"];
username = [contactInfos objectForKey: @"c_uid"];
recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username);
}
@@ -273,7 +272,7 @@ static NSCharacterSet *hexCharacterSet = nil;
recipient->username = NULL;
entryId = MAPIStoreExternalEntryId (cn, email);
}
recipient->type = [[person role] isEqualToString: @"OPT-PARTICIPANT"] ? MAPI_CC : MAPI_TO;
recipient->type = MAPI_TO;
/* properties */
p = 0;
@@ -283,7 +282,7 @@ static NSCharacterSet *hexCharacterSet = nil;
// PR_OBJECT_TYPE = MAPI_MAILUSER (see MAPI_OBJTYPE)
recipient->data[p] = MAPILongValue (msgData, MAPI_MAILUSER);
p++;
// PR_DISPLAY_TYPE = DT_MAILUSER (see MS-NSPI)
recipient->data[p] = MAPILongValue (msgData, 0);
p++;
@@ -365,7 +364,7 @@ static NSCharacterSet *hexCharacterSet = nil;
if (contactInfos)
{
username = [contactInfos objectForKey: @"sAMAccountName"];
username = [contactInfos objectForKey: @"c_uid"];
recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username);
}
@@ -383,7 +382,7 @@ static NSCharacterSet *hexCharacterSet = nil;
// PR_OBJECT_TYPE = MAPI_MAILUSER (see MAPI_OBJTYPE)
recipient->data[p] = MAPILongValue (msgData, MAPI_MAILUSER);
p++;
// PR_DISPLAY_TYPE = DT_MAILUSER (see MS-NSPI)
recipient->data[p] = MAPILongValue (msgData, 0);
p++;
@@ -792,20 +791,11 @@ static NSCharacterSet *hexCharacterSet = nil;
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc;
NSCalendarDate *dateValue, *start;
NSCalendarDate *dateValue;
if ([event isRecurrent])
{
/* [MS-OXOCAL] For a recurring series, this property specifies
midnight in the user's machine time zone, on the date of the
first instance, then is persisted in UTC. */
start = [event startDate];
dateValue = [NSCalendarDate dateWithYear: [start yearOfCommonEra]
month: [start monthOfYear]
day: [start dayOfMonth]
hour: 0 minute: 0 second: 0
timeZone: timeZone];
[dateValue setTimeZone: utcTZ];
dateValue = [[event startDate] hour: 0 minute: 0 second: 0];
*data = [dateValue asFileTimeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
@@ -904,7 +894,7 @@ static NSCharacterSet *hexCharacterSet = nil;
}
else
dateValue = [NSCalendarDate dateWithYear: 4500 month: 8 day: 31
hour: 23 minute: 59 second: 00
hour: 23 minute: 59 second: 59
timeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
@@ -931,7 +921,7 @@ static NSCharacterSet *hexCharacterSet = nil;
contactInfos = [mgr contactInfosForUserWithUIDorEmail: email];
if (contactInfos)
{
username = [contactInfos objectForKey: @"sAMAccountName"];
username = [contactInfos objectForKey: @"c_uid"];
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username);
}
else
@@ -1201,31 +1191,11 @@ static NSCharacterSet *hexCharacterSet = nil;
return [self getYes: data inMemCtx: memCtx];
}
- (int) getPidTagSensitivity: (void **) data
- (int) getPidTagSensitivity: (void **) data // not implemented, depends on CLASS
inMemCtx: (TALLOC_CTX *) memCtx
{
/* See [MS-OXCICAL] Section 2.1.3.11.20.4 */
uint32_t v;
NSString *accessClass;
accessClass = [event accessClass];
if (accessClass)
{
if ([accessClass isEqualToString: @"X-PERSONAL"])
v = 0x1;
else if ([accessClass isEqualToString: @"PRIVATE"])
v = 0x2;
else if ([accessClass isEqualToString: @"CONFIDENTIAL"])
v = 0x3;
else
v = 0x0; /* PUBLIC */
}
else
v = 0x0; /* PUBLIC */
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
// normal = 0, personal?? = 1, private = 2, confidential = 3
return [self getLongZero: data inMemCtx: memCtx];
}
- (int) getPidTagImportance: (void **) data
@@ -1244,22 +1214,6 @@ static NSCharacterSet *hexCharacterSet = nil;
return MAPISTORE_SUCCESS;
}
- (int) getPidNameKeywords: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
/* See [MS-OXCICAL] Section 2.1.3.1.1.20.3 */
NSArray *categories;
categories = [event categories];
if (categories)
{
*data = [categories asMVUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
else
return MAPISTORE_ERR_NOT_FOUND;
}
- (int) getPidTagBody: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -1277,7 +1231,7 @@ static NSCharacterSet *hexCharacterSet = nil;
/* Avoiding those trail weird characters at event description */
range = [stringValue rangeOfString: trimingString
options: NSBackwardsSearch];
if (range.location != NSNotFound)
if (range.location > 0)
{
stringValue = [stringValue substringToIndex: (NSMaxRange(range) -1)];
}
@@ -1461,6 +1415,8 @@ static NSCharacterSet *hexCharacterSet = nil;
firstStartDate = [event firstRecurrenceStartDate];
if (firstStartDate)
{
[firstStartDate setTimeZone: timeZone];
arp = talloc_zero (NULL, struct AppointmentRecurrencePattern);
[rule fillRecurrencePattern: &arp->RecurrencePattern
withEvent: event
@@ -1470,12 +1426,6 @@ static NSCharacterSet *hexCharacterSet = nil;
arp->WriterVersion2 = 0x00003008; /* 0x3008 for compatibility with
ol2003 */
/* All day events' dates are specified in floating time
([MS-OXCICAL] 2.1.3.1.1.20.10). The StartTimeOffset and EndTimeOffset
fields are relative to midnight of those days ([MS-OXOCAL] 2.2.1.44.5),
so no time zone adjustment is needed */
if (![event isAllDay])
[firstStartDate setTimeZone: timeZone];
startMinutes = ([firstStartDate hourOfDay] * 60
+ [firstStartDate minuteOfHour]);
arp->StartTimeOffset = startMinutes;
@@ -1876,25 +1826,16 @@ ReservedBlockEE2Size: 00 00 00 00
NSArray *alarms;
NSUInteger count, max;
iCalAlarm *currentAlarm;
NSString *action, *webstatus;
NSString *action;
alarms = [event alarms];
max = [alarms count];
for (count = 0; !alarm && count < max; count++)
{
currentAlarm = [alarms objectAtIndex: count];
// Only handle 'display' alarms
action = [currentAlarm action];
if ([action caseInsensitiveCompare: @"display"] != NSOrderedSame)
continue;
// Ignore alarms already triggered
webstatus = [[currentAlarm trigger] value: 0 ofAttribute: @"x-webstatus"];
if ([webstatus caseInsensitiveCompare: @"triggered"] == NSOrderedSame)
continue;
ASSIGN (alarm, currentAlarm);
action = [[currentAlarm action] lowercaseString];
if (!action || [action isEqualToString: @"display"])
ASSIGN (alarm, currentAlarm);
}
alarmSet = YES;
@@ -2073,23 +2014,17 @@ ReservedBlockEE2Size: 00 00 00 00
enum mapistore_error rc;
iCalTimeZone *icalTZ;
/* [MS-OXOCAL] 3.1.5.5.1: This property is used in floating (all-day) events,
specified in floating time, to convert the start date from UTC to the user's
time zone */
if ([event isAllDay])
icalTZ = [iCalTimeZone timeZoneForName: [timeZone timeZoneName]];
else if ([event isRecurrent])
icalTZ = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] timeZone];
else
icalTZ = nil;
if (icalTZ)
if ([event isRecurrent])
{
/* [MS-OXOCAL] 2.2.1.42: This property can only have the E flag set in the
TimeZoneDefinition struct */
*data = [icalTZ asZoneTimeDefinitionWithFlags: TZRULE_FLAG_EFFECTIVE_TZREG
inMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
icalTZ = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] timeZone];
if (icalTZ)
{
*data = [icalTZ asZoneTimeDefinitionWithFlags: TZRULE_FLAG_EFFECTIVE_TZREG | TZRULE_FLAG_RECUR_CURRENT_TZREG
inMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
else
rc = MAPISTORE_ERR_NOT_FOUND;
}
else
rc = MAPISTORE_ERR_NOT_FOUND;
+7 -28
View File
@@ -63,15 +63,19 @@
SOGoAppointmentObject *newEntry;
NSString *name;
[[self userContext] activate];
//[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
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;
}
@@ -96,14 +100,6 @@
[roles addObject: SOGoCalendarRole_PrivateViewer];
[roles addObject: SOGoCalendarRole_ConfidentialViewer];
}
if (rights & RightsFreeBusySimple)
{
[roles addObject: SOGoCalendarRole_PublicDAndTViewer];
}
if (rights & RightsFreeBusyDetailed)
{
[roles addObject: SOGoCalendarRole_ConfidentialDAndTViewer];
}
// [self logWithFormat: @"roles for rights %.8x = (%@)", rights, roles];
@@ -125,21 +121,12 @@
else if ([roles containsObject: SOGoCalendarRole_PublicViewer]
&& [roles containsObject: SOGoCalendarRole_PrivateViewer]
&& [roles containsObject: SOGoCalendarRole_ConfidentialViewer])
// We have to set by hand other rights as only the highest role is returned
// See SOGoAppointmentFolder.m:aclsForUser for details
rights |= RightsReadItems | RightsFreeBusySimple | RightsFreeBusyDetailed;
if ([roles containsObject: SOGoCalendarRole_PublicDAndTViewer])
rights |= RightsFreeBusySimple;
if ([roles containsObject: SOGoCalendarRole_ConfidentialDAndTViewer])
rights |= RightsFreeBusyDetailed;
rights |= RightsReadItems | 0x1800;
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
// [self logWithFormat: @"rights for roles (%@) = %.8x", roles, rights];
return rights;
}
@@ -182,14 +169,6 @@
[(SOGoAppointmentFolder *) sogoObject aclSQLListingFilter]];
}
- (int) getPidTagContainerClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"IPF.Appointment" asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidTagDefaultPostMessageClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
+90 -71
View File
@@ -81,7 +81,7 @@
// extern void ndr_print_AppointmentRecurrencePattern(struct ndr_print *ndr, const char *name, const struct AppointmentRecurrencePattern *r);
static Class NSArrayK, MAPIStoreAppointmentWrapperK;
static Class NSArrayK;
@implementation SOGoAppointmentObject (MAPIStoreExtension)
@@ -97,7 +97,6 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
+ (void) initialize
{
NSArrayK = [NSArray class];
MAPIStoreAppointmentWrapperK = [MAPIStoreAppointmentWrapper class];
}
+ (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP
@@ -181,12 +180,6 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
else
{
origCalendar = [sogoObject calendar: YES secure: YES];
if (!origCalendar)
{
[self errorWithFormat: @"Incorrect calendar event %@. Empty message is created",
[self url]];
return self;
}
calendar = [origCalendar mutableCopy];
masterEvent = [[calendar events] objectAtIndex: 0];
[self _setupAttachmentParts];
@@ -212,23 +205,13 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
[super dealloc];
}
- (MAPIStoreAppointmentWrapper *) _appointmentWrapper
/* getters */
- (int) getPidLidFInvited: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSUInteger i, max;
id proxy;
max = [proxies count];
for (i = 0; i < max; i++) {
proxy = [proxies objectAtIndex: i];
if ([proxy isKindOfClass: MAPIStoreAppointmentWrapperK])
{
return proxy;
}
}
return nil;
return [self getYes: data inMemCtx: memCtx];
}
/* getters */
- (int) getPidTagMessageClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -341,63 +324,100 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
}
else
{
[[self _appointmentWrapper] fillMessageData: msgData
inMemCtx: memCtx];
/* HACK: we know the first (and only) proxy is our appointment wrapper
instance, but this might not always be true */
[[proxies objectAtIndex: 0] fillMessageData: msgData
inMemCtx: memCtx];
}
*dataPtr = msgData;
}
/* sender representing */
// - (int) getPidTagSentRepresentingEmailAddress: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagSenderEmailAddress: data inMemCtx: memCtx];
// }
// - (int) getPidTagSentRepresentingAddressType: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getSMTPAddrType: data inMemCtx: memCtx];
// }
// - (int) getPidTagSentRepresentingName: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagSenderName: data inMemCtx: memCtx];
// }
// - (int) getPidTagSentRepresentingEntryId: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagSenderEntryId: data inMemCtx: memCtx];
// }
/* attendee */
// - (int) getPidTagReceivedByAddressType: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [appointmentWrapper getPidTagReceivedByAddressType: data
// inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedByEmailAddress: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [appointmentWrapper getPidTagReceivedByEmailAddress: data
// inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedByName: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [appointmentWrapper getPidTagReceivedByName: data
// inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedByEntryId: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [appointmentWrapper getPidTagReceivedByEntryId: data
// inMemCtx: memCtx];
// }
// /* attendee representing */
// - (int) getPidTagReceivedRepresentingEmailAddress: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagReceivedByEmailAddress: data inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedRepresentingAddressType: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getSMTPAddrType: data inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedRepresentingName: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagReceivedByName: data inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedRepresentingEntryId: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagReceivedByEntryId: data inMemCtx: memCtx];
// }
- (int) getPidTagResponseRequested: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getYes: data inMemCtx: memCtx];
}
/* This three methods: getPidTagNormalizedSubject,
getPidTagSensitivity and getPidTagImportance are implemented in
MAPIStoreMessage base class, then the proxy method is not reached
(see MAPIStoreObject).
*/
- (int) getPidTagNormalizedSubject: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
MAPIStoreAppointmentWrapper *appointmentWrapper;
appointmentWrapper = [self _appointmentWrapper];
if (appointmentWrapper)
return [appointmentWrapper getPidTagNormalizedSubject: data inMemCtx: memCtx];
return MAPISTORE_ERR_NOT_FOUND;
}
- (int) getPidTagSensitivity: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
MAPIStoreAppointmentWrapper *appointmentWrapper;
appointmentWrapper = [self _appointmentWrapper];
if (appointmentWrapper)
return [appointmentWrapper getPidTagSensitivity: data inMemCtx: memCtx];
return [self getLongZero: data inMemCtx: memCtx];
}
- (int) getPidTagImportance: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
MAPIStoreAppointmentWrapper *appointmentWrapper;
appointmentWrapper = [self _appointmentWrapper];
if (appointmentWrapper)
return [appointmentWrapper getPidTagImportance: data inMemCtx: memCtx];
*data = MAPILongValue (memCtx, 1);
return MAPISTORE_SUCCESS;
}
- (NSString *) _uidFromGlobalObjectId: (TALLOC_CTX *) memCtx
{
NSData *objectId;
@@ -494,7 +514,6 @@ 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)
{
@@ -578,7 +597,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
}
}
- (void) save: (TALLOC_CTX *) memCtx
- (void) save: (TALLOC_CTX *) memCtx
{
// iCalCalendar *vCalendar;
// NSCalendarDate *now;
@@ -635,7 +654,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
withActiveUser: activeUser
inMemCtx: memCtx];
[self _updateAttachedEvents];
[[self userContext] activate];
[[self userContext] activateWithUser: activeUser];
[sogoObject updateContentWithCalendar: calendar
fromRequest: nil];
[self updateVersions];
@@ -182,9 +182,6 @@ static Class MAPIStoreCalendarMessageK = Nil;
forKey: MAPIPropertyKey (PR_CREATION_TIME)];
[knownProperties setObject: @"c_uid"
forKey: MAPIPropertyKey (PR_OWNER_APPT_ID)];
/* Use by oxcfxics to sort the latest first */
[knownProperties setObject: @"c_lastmodified"
forKey: MAPIPropertyKey (PidTagMessageDeliveryTime)];
}
return [knownProperties objectForKey: MAPIPropertyKey (property)];
+2 -5
View File
@@ -28,7 +28,6 @@
#import <Contacts/SOGoContactFolders.h>
#import "MAPIApplication.h"
#import "MAPIStoreUserContext.h"
#import "MAPIStoreContactsContext.h"
#import "MAPIStoreContactsMessage.h"
#import "MAPIStoreContactsMessageTable.h"
@@ -59,12 +58,10 @@
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];
@@ -103,7 +100,7 @@
rights |= RightsReadItems;
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
return rights;
}
+1 -169
View File
@@ -170,21 +170,6 @@
return MAPISTORE_SUCCESS;
}
- (int) getPidTagProfession: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[sogoObject vCard] role];
if (stringValue)
*data = [stringValue asUnicodeInMemCtx: memCtx];
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (int) getPidTagCompanyName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -738,107 +723,6 @@
return rc;
}
- (int) getPidTagWeddingAnniversary: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSCalendarDate *dateValue;
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-anniversary"]
flattenedValuesForKey: @""];
if (stringValue && ! [stringValue isEqualToString: @""])
{
dateValue = [NSCalendarDate dateWithString: stringValue
calendarFormat: @"%Y-%m-%d"];
*data = [dateValue asFileTimeInMemCtx: memCtx];
}
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (int) getPidTagSpouseName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-spouse"]
flattenedValuesForKey: @""];
if (stringValue)
*data = [stringValue asUnicodeInMemCtx: memCtx];
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (int) getPidTagManagerName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-manager"]
flattenedValuesForKey: @""];
if (stringValue)
*data = [stringValue asUnicodeInMemCtx: memCtx];
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (int) getPidTagAssistant: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-assistant"]
flattenedValuesForKey: @""];
if (stringValue)
*data = [stringValue asUnicodeInMemCtx: memCtx];
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (int) getPidTagOfficeLocation: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-office"]
flattenedValuesForKey: @""];
if (stringValue)
*data = [stringValue asUnicodeInMemCtx: memCtx];
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (int) getPidLidFreeBusyLocation: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"fburl"]
flattenedValuesForKey: @""];
if (stringValue)
*data = [stringValue asUnicodeInMemCtx: memCtx];
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
//
// Decomposed fullname getters
//
@@ -1249,18 +1133,12 @@ fromProperties: (NSDictionary *) attachmentProps
//
// job title, profession, nickname, company name, deparment, work url, im address/screen name and birthday
// job title, nickname, company name, deparment, work url, im address/screen name and birthday
//
value = [properties objectForKey: MAPIPropertyKey(PR_TITLE_UNICODE)];
if (value)
[newCard setTitle: value];
value = [properties objectForKey: MAPIPropertyKey(PR_PROFESSION_UNICODE)];
if (value)
{
[newCard setRole: value];
}
value = [properties objectForKey: MAPIPropertyKey(PR_NICKNAME_UNICODE)];
if (value)
[newCard setNickname: value];
@@ -1295,52 +1173,6 @@ fromProperties: (NSDictionary *) attachmentProps
[newCard setBday: [value descriptionWithCalendarFormat: @"%Y-%m-%d"]];
}
//
// wedding anniversary, spouse's name, manager's name, assistant's name, office location, freebusy location
//
value = [properties objectForKey: MAPIPropertyKey(PidTagWeddingAnniversary)];
if (value)
{
[[newCard uniqueChildWithTag: @"x-ms-anniversary"]
setSingleValue: [value descriptionWithCalendarFormat: @"%Y-%m-%d"]
forKey: @""];
}
value = [properties objectForKey: MAPIPropertyKey(PR_SPOUSE_NAME_UNICODE)];
if (value)
{
[[newCard uniqueChildWithTag: @"x-ms-spouse"]
setSingleValue: value forKey: @""];
}
value = [properties objectForKey: MAPIPropertyKey(PR_MANAGER_NAME_UNICODE)];
if (value)
{
[[newCard uniqueChildWithTag: @"x-ms-manager"]
setSingleValue: value forKey: @""];
}
value = [properties objectForKey: MAPIPropertyKey(PR_ASSISTANT_UNICODE)];
if (value)
{
[[newCard uniqueChildWithTag: @"x-ms-assistant"]
setSingleValue: value forKey: @""];
}
value = [properties objectForKey: MAPIPropertyKey(PR_OFFICE_LOCATION_UNICODE)];
if (value)
{
[[newCard uniqueChildWithTag: @"x-ms-office"]
setSingleValue: value forKey: @""];
}
value = [properties objectForKey: MAPIPropertyKey(PidLidFreeBusyLocation)];
if (value)
{
[[newCard uniqueChildWithTag: @"fburl"]
setSingleValue: value forKey: @""];
}
/* photo */
if ([attachmentParts count] > 0)
{
@@ -220,9 +220,6 @@ static Class MAPIStoreContactsMessageK, NGMailAddressK, NSDataK, NSStringK;
forKey: MAPIPropertyKey (PidTagSubject)];
[knownProperties setObject: @"c_cn"
forKey: MAPIPropertyKey (PidTagNormalizedSubject)];
/* Use by oxcfxics to sort the latest first */
[knownProperties setObject: @"c_lastmodified"
forKey: MAPIPropertyKey (PidTagMessageDeliveryTime)];
}
return [knownProperties objectForKey: MAPIPropertyKey (property)];
+79 -39
View File
@@ -33,6 +33,7 @@
#import <SOGo/SOGoUser.h>
#import "MAPIStoreAttachment.h"
// #import "MAPIStoreAttachmentTable.h"
#import "MAPIStoreFallbackContext.h"
#import "MAPIStoreFolder.h"
#import "MAPIStoreFolderTable.h"
@@ -50,7 +51,6 @@
#import "MAPIStoreContext.h"
#undef DEBUG
#include <dlinklist.h>
#include <stdbool.h>
#include <gen_ndr/exchange.h>
#include <util/attr.h>
@@ -88,31 +88,32 @@ 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;
// User context is activated on initialization
[MAPIStoreUserContext userContextWithUsername: userName
andTDBIndexing: indexing];
userContext = [MAPIStoreUserContext userContextWithUsername: userName
andTDBIndexing: indexing];
[userContext activateWithUser: [userContext sogoUser]];
classes = GSObjCAllSubclassesOfClass (self);
max = [classes count];
@@ -120,7 +121,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);
@@ -130,7 +131,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;
@@ -223,6 +224,8 @@ 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);
@@ -273,11 +276,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
{
NSString *username;
if (newConnInfo == NULL)
{
return nil;
}
if ((self = [self init]))
{
ASSIGN (contextUrl, newUrl);
@@ -294,6 +292,13 @@ 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]);
@@ -311,6 +316,12 @@ 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];
@@ -338,16 +349,26 @@ 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
//[xxxx stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
url = [[contextUrl absoluteString]
stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
objectURL = [[userContext mapping] urlFromID: fmid];
if (objectURL)
{
@@ -368,6 +389,14 @@ 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;
}
@@ -383,6 +412,7 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
withFID: (uint64_t) newFid
{
enum mapistore_error rc;
MAPIStoreMapping *mapping;
MAPIStoreFolder *baseFolder;
SOGoFolder *currentFolder;
WOContext *woContext;
@@ -390,7 +420,11 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
NSArray *pathComponents;
NSUInteger count, max;
[userContext activate];
mapping = [userContext mapping];
if (![mapping urlFromID: newFid])
[mapping registerURL: [contextUrl absoluteString]
withID: newFid];
[userContext activateWithUser: activeUser];
woContext = [userContext woContext];
[self ensureContextFolder];
@@ -452,7 +486,7 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
/* utils */
- (NSString *) extractChildNameFromURL: (NSString *) objectURL
andFolderURLAt: (NSString **) folderURL;
andFolderURLAt: (NSString **) folderURL;
{
NSString *childKey;
NSRange lastSlash;
@@ -461,15 +495,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;
@@ -480,10 +514,11 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
- (uint64_t) idForObjectWithKey: (NSString *) key
inFolderURL: (NSString *) folderURL
{
NSString *childURL;
NSString *childURL, *owner;
MAPIStoreMapping *mapping;
uint64_t mappingId;
enum mapistore_error ret;
uint32_t contextId;
void *rootObject;
if (key)
childURL = [NSString stringWithFormat: @"%@%@", folderURL,
@@ -494,13 +529,17 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
mappingId = [mapping idFromURL: childURL];
if (mappingId == NSNotFound)
{
[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)];
//[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);
}
return mappingId;
@@ -510,7 +549,7 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
{
uint64_t newVersionNumber;
if (openchangedb_get_new_changeNumber (connInfo->oc_ctx, connInfo->username, &newVersionNumber)
if (openchangedb_get_new_changeNumber (connInfo->oc_ctx, &newVersionNumber)
!= MAPI_E_SUCCESS)
abort ();
@@ -527,9 +566,9 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
memCtx = talloc_zero(NULL, TALLOC_CTX);
newChangeNumbers = [NSMutableArray arrayWithCapacity: max];
if (openchangedb_get_new_changeNumbers (connInfo->oc_ctx,
memCtx, connInfo->username, max, &numbers)
memCtx, max, &numbers)
!= MAPI_E_SUCCESS || numbers->cValues != max)
abort ();
for (count = 0; count < max; count++)
@@ -554,14 +593,15 @@ 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];
}
+15 -37
View File
@@ -138,9 +138,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
MAPIStoreMapping *mapping;
NSRange slashRange;
pathComponent = nil;
if (isMove && ([targetFolder isKindOfClass: MAPIStoreDBFolderK] || !targetFolder))
if (isMove && [targetFolder isKindOfClass: MAPIStoreDBFolderK])
{
path = [sogoObject path];
slashRange = [path rangeOfString: @"/" options: NSBackwardsSearch];
@@ -149,28 +147,14 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
format: @"db folder path must start with a '/'"];
else
pathComponent = [path substringFromIndex: slashRange.location + 1];
if (targetFolder)
{
targetPath = [[targetFolder sogoObject] path];
newPath = [NSString stringWithFormat: @"%@/%@",
targetPath, pathComponent];
[dbFolder changePathTo: newPath
intoNewContainer: [targetFolder dbFolder]];
}
else
[dbFolder changePathTo: [NSString stringWithFormat: @"/fallback/%@", pathComponent]
intoNewContainer: nil];
targetPath = [[targetFolder sogoObject] path];
newPath = [NSString stringWithFormat: @"%@/%@",
targetPath, pathComponent];
[dbFolder changePathTo: newPath];
mapping = [self mapping];
if (targetFolder)
newURL = [NSString stringWithFormat: @"%@%@/",
[targetFolder url], pathComponent];
else
newURL = [NSString stringWithFormat: @"sogo://%@@fallback/%@/",
[[self userContext] username], pathComponent];
newURL = [NSString stringWithFormat: @"%@%@/",
[targetFolder url], pathComponent];
[mapping updateID: [self objectId]
withURL: newURL];
@@ -193,8 +177,6 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
SOGoMAPIDBMessage *fsObject;
NSString *newKey;
[[self userContext] activate];
newKey = [NSString stringWithFormat: @"%@.plist",
[SOGoObject globallyUniqueObjectId]];
fsObject = [SOGoMAPIDBMessage objectWithName: newKey
@@ -216,13 +198,10 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
ownerUser = [[self userContext] sogoUser];
if ([[context activeUser] isEqual: ownerUser]
|| [self subscriberCanReadMessages])
{
[[self userContext] activate];
keys = [(SOGoCacheGCSFolder *) sogoObject childKeysOfType: MAPIMessageCacheObject
includeDeleted: NO
matchingQualifier: qualifier
andSortOrderings: sortOrderings];
}
keys = [(SOGoCacheGCSFolder *) sogoObject childKeysOfType: MAPIMessageCacheObject
includeDeleted: NO
matchingQualifier: qualifier
andSortOrderings: sortOrderings];
else
keys = [NSArray array];
@@ -232,7 +211,6 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
- (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings
{
[[self userContext] activate];
return [dbFolder childKeysOfType: MAPIFolderCacheObject
includeDeleted: NO
matchingQualifier: qualifier
@@ -268,7 +246,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
if ([date laterDate: fileDate] == fileDate)
{
//[self logWithFormat: @"current date: %@", date];
date = fileDate;
}
}
@@ -332,7 +310,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
rights |= RightsFolderContact;
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
return rights;
}
@@ -367,7 +345,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)];
+4 -7
View File
@@ -50,22 +50,19 @@
NSUInteger count;
enum MAPITAGS faiProperties[] = { 0x68350102, 0x683c0102, 0x683e0102,
0x683f0102, 0x68410003, 0x68420102,
0x68450102, 0x68460003,
// PR_VD_NAME_W, PR_VD_FLAGS, PR_VD_VERSION, PR_VIEW_CLSID
0x7006001F, 0x70030003, 0x70070003, 0x68330048 };
size_t faiSize = sizeof(faiProperties) / sizeof(enum MAPITAGS);
0x68450102, 0x68460003 };
properties = talloc_zero (memCtx, struct SPropTagArray);
properties->cValues = MAPIStoreSupportedPropertiesCount + faiSize;
properties->cValues = MAPIStoreSupportedPropertiesCount + 8;
properties->aulPropTag = talloc_array (properties, enum MAPITAGS,
MAPIStoreSupportedPropertiesCount + faiSize);
MAPIStoreSupportedPropertiesCount + 8);
for (count = 0; count < MAPIStoreSupportedPropertiesCount; count++)
properties->aulPropTag[count] = MAPIStoreSupportedProperties[count];
/* FIXME (hack): append a few undocumented properties that can be added to
FAI messages */
for (count = 0; count < faiSize; count++)
for (count = 0; count < 8; count++)
properties->aulPropTag[MAPIStoreSupportedPropertiesCount+count]
= faiProperties[count];
+2 -9
View File
@@ -30,7 +30,6 @@
#undef DEBUG
#include <inttypes.h>
#include <dlinklist.h>
#include <mapistore/mapistore.h>
@implementation MAPIStoreFallbackContext
@@ -56,10 +55,7 @@
NSString *baseURL, *url, *name;
MAPIStoreUserContext *userContext;
baseURL = [NSString stringWithFormat: @"sogo://%@@fallback/",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"]];
baseURL = [NSString stringWithFormat: @"sogo://%@@fallback/", userName];
context = talloc_zero (memCtx, struct mapistore_contexts_list);
context->url = [baseURL asUnicodeInMemCtx: context];
@@ -103,10 +99,7 @@
forUser: (NSString *) userName
{
return [NSString stringWithFormat: @"sogo://%@@fallback/0x%.16"PRIx64"/",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
(unsigned long long) fid];
userName, (unsigned long long) fid];
}
@end
+6 -1
View File
@@ -150,7 +150,6 @@
/* helpers */
- (uint64_t) idForObjectWithKey: (NSString *) childKey;
- (MAPIStoreFolder *) rootContainer;
/* subclasses */
- (MAPIStoreMessage *) createMessage;
@@ -185,6 +184,12 @@
/* subclass helpers */
- (void) setupVersionsMessage;
- (void) ensureIDsForChildKeys: (NSArray *) keys;
- (void) postNotificationsForMoveCopyMessagesWithMIDs: (uint64_t *) srcMids
andMessageURLs: (NSArray *) oldMessageURLs
andCount: (uint32_t) midCount
fromFolder: (MAPIStoreFolder *) sourceFolder
withMIDs: (uint64_t *) targetMids
wantCopy: (uint8_t) wantCopy;
@end
+207 -102
View File
@@ -29,7 +29,6 @@
#import <Foundation/NSString.h>
#import <Foundation/NSURL.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <SOGo/SOGoContentObject.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoFolder.h>
@@ -53,7 +52,6 @@
#import <SOGo/SOGoCacheGCSFolder.h>
#import "SOGoMAPIDBMessage.h"
#import "SOGoCacheGCSObject+MAPIStore.h"
#import <Mailer/SOGoMailObject.h>
#include <gen_ndr/exchange.h>
@@ -102,8 +100,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSUInteger lastPartIdx;
MAPIStoreUserContext *userContext;
parts = 0;
lastPartIdx = 0;
folderURL = [NSURL URLWithString: [self url]];
/* note: -[NSURL path] returns an unescaped representation */
path = [folderURL path];
@@ -120,7 +116,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
folderName = [folderURL host];
userContext = [self userContext];
[userContext activate];
[userContext ensureFolderTableExists];
ASSIGN (dbFolder,
@@ -232,19 +227,24 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
- (id) lookupFolder: (NSString *) folderKey
{
MAPIStoreFolder *childFolder = nil;
MAPIStoreFolder *childFolder;
SOGoFolder *sogoFolder;
WOContext *woContext;
if ([[self folderKeys] containsObject: folderKey])
{
[[self userContext] activate];
sogoFolder = [sogoObject lookupName: folderKey
inContext: nil
woContext = [[self userContext] woContext];
sogoFolder = [sogoObject lookupName: folderKey inContext: woContext
acquire: NO];
if (sogoFolder && ![sogoFolder isKindOfClass: NSExceptionK])
childFolder = [isa mapiStoreObjectWithSOGoObject: sogoFolder
inContainer: self];
{
[sogoFolder setContext: woContext];
childFolder = [isa mapiStoreObjectWithSOGoObject: sogoFolder
inContainer: self];
}
}
else
childFolder = nil;
return childFolder;
}
@@ -275,16 +275,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (messageKey)
{
[[self userContext] activate];
msgObject = [sogoObject lookupName: messageKey
inContext: nil
acquire: NO];
/* If the lookup in the indexing table works, but the IMAP does
not have the message, then the message does not exist in this
folder */
if (msgObject && [msgObject isKindOfClass: [SOGoMailObject class]]
&& ! [(SOGoMailObject *)msgObject doesMailExist])
return nil;
if (msgObject && ![msgObject isKindOfClass: NSExceptionK])
{
[msgObject setContext: [[self userContext] woContext]];
@@ -305,7 +298,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (messageKey)
{
[[self userContext] activate];
if ([[self faiMessageKeys] containsObject: messageKey])
{
msgObject = [dbFolder lookupName: messageKey
@@ -394,8 +386,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
withRow: (struct SRow *) aRow
andFID: (uint64_t) fid
{
BOOL mapped;
enum mapistore_error rc = MAPISTORE_SUCCESS;
int rc = MAPISTORE_SUCCESS;
MAPIStoreMapping *mapping;
NSString *baseURL, *childURL, *folderKey;
MAPIStoreFolder *childFolder;
@@ -423,12 +414,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
childURL = [NSString stringWithFormat: @"%@%@/",
baseURL,
[folderKey stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
mapped = [mapping registerURL: childURL withID: fid];
if (!mapped)
/* Enforce the creation if the backend does know the fid */
[mapping updateURL: childURL withID: fid];
[mapping registerURL: childURL withID: fid];
childFolder = [self lookupFolder: folderKey];
if (childFolder)
{
@@ -447,11 +433,16 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
return rc;
}
- (int) deleteFolder
- (void) deleteFolderImpl
{
// TODO: raise exception in case underlying delete fails?
// [propsMessage delete];
[dbFolder delete];
}
- (int) deleteFolder
{
[self deleteFolderImpl];
[self cleanupCaches];
@@ -512,12 +503,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
else
rc = MAPISTORE_ERR_DENIED;
}
else
{
/* Unregistering from indexing table as the backend says the
object was not found */
[mapping unregisterURLWithID: mid];
}
}
return rc;
@@ -538,7 +523,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
context = [self context];
ownerUser = [[self userContext] sogoUser];
[[self userContext] activate];
if ([[context activeUser] isEqual: ownerUser]
|| (!isAssociated && [self subscriberCanCreateMessages]))
@@ -580,12 +564,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSUInteger count, max;
id msgObject;
SOGoUser *ownerUser;
struct mapistore_connection_info *connInfo;
struct mapistore_object_notification_parameters *notif_parameters;
int rc;
/* flags that control the behaviour of the operation
(MAPISTORE_SOFT_DELETE or MAPISTORE_PERMANENT_DELETE) */
[self logWithFormat: @"-deleteMessageWithMID: mid: 0x%.16llx flags: %d", mid, flags];
mapping = [self mapping];
childURL = [mapping urlFromID: mid];
if (childURL)
@@ -618,9 +602,51 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
}
else
{
if (![message isNew])
{
/* folder notification */
notif_parameters
= talloc_zero(NULL,
struct mapistore_object_notification_parameters);
notif_parameters->object_id = [self objectId];
notif_parameters->tag_count = 5;
notif_parameters->tags = talloc_array (notif_parameters,
enum MAPITAGS, 5);
notif_parameters->tags[0] = PR_CONTENT_COUNT;
notif_parameters->tags[1] = PR_DELETED_COUNT_TOTAL;
notif_parameters->tags[2] = PR_MESSAGE_SIZE;
notif_parameters->tags[3] = PR_NORMAL_MESSAGE_SIZE;
notif_parameters->tags[4] = PR_DELETED_MSG_COUNT;
notif_parameters->new_message_count = true;
notif_parameters->message_count = [[self messageKeys]
count] - 1;
connInfo = [[self context] connectionInfo];
mapistore_push_notification (connInfo->mstore_ctx,
MAPISTORE_FOLDER,
MAPISTORE_OBJECT_MODIFIED,
notif_parameters);
talloc_free(notif_parameters);
/* message notification */
notif_parameters
= talloc_zero(NULL,
struct mapistore_object_notification_parameters);
notif_parameters->object_id = mid;
notif_parameters->folder_id = [self objectId];
/* Exchange sends a fnevObjectCreated!! */
mapistore_push_notification (connInfo->mstore_ctx,
MAPISTORE_MESSAGE,
MAPISTORE_OBJECT_CREATED,
notif_parameters);
talloc_free(notif_parameters);
/* table notification */
for (count = 0; count < max; count++)
[[activeTables objectAtIndex: count]
notifyChangesForChild: message];
}
[self logWithFormat: @"successfully deleted object at URL: %@", childURL];
/* Ensure we are respecting flags parameter */
[mapping unregisterURLWithID: mid andFlags: flags];
[mapping unregisterURLWithID: mid];
[self cleanupCaches];
rc = MAPISTORE_SUCCESS;
}
@@ -650,7 +676,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
//TALLOC_CTX *memCtx;
struct SRow aRow;
struct SPropValue property;
uint8_t deleteFlags;
[self logWithFormat: @"-moveCopyMessageWithMID: 0x%.16llx .. withMID: 0x%.16llx .. wantCopy: %d", srcMid, targetMid, wantCopy];
@@ -681,9 +706,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
}
[destMsg save: memCtx];
if (!wantCopy)
/* We want to keep mid for restoring/shared data to work if mids are different. */
deleteFlags = (srcMid == targetMid) ? MAPISTORE_PERMANENT_DELETE : MAPISTORE_SOFT_DELETE;
rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: deleteFlags];
rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: 0];
end:
//talloc_free (memCtx);
@@ -744,6 +767,13 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
/* Notifications */
if (rc == MAPISTORE_SUCCESS)
{
[self postNotificationsForMoveCopyMessagesWithMIDs: srcMids
andMessageURLs: oldMessageURLs
andCount: midCount
fromFolder: sourceFolder
withMIDs: targetMids
wantCopy: wantCopy];
// We cleanup cache of our source and destination folders
[self cleanupCaches];
[sourceFolder cleanupCaches];
@@ -751,9 +781,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
}
else
rc = MAPISTORE_ERR_DENIED;
//talloc_free (memCtx);
return rc;
}
@@ -815,7 +845,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (isMove)
{
fmid = [mapping idFromURL: [message url]];
[self deleteMessageWithMID: fmid andFlags: MAPISTORE_PERMANENT_DELETE];
[self deleteMessageWithMID: fmid andFlags: 0];
[mapping registerURL: [targetMessage url]
withID: fmid];
}
@@ -836,7 +866,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (isMove)
{
fmid = [mapping idFromURL: [message url]];
[self deleteMessageWithMID: fmid andFlags: MAPISTORE_PERMANENT_DELETE];
[self deleteMessageWithMID: fmid andFlags: 0];
[mapping registerURL: [targetMessage url]
withID: fmid];
}
@@ -863,23 +893,16 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
}
if (isMove)
[self deleteFolder];
{
fmid = [mapping idFromURL: [self url]];
[mapping unregisterURLWithID: fmid];
[self deleteFolderImpl];
[mapping registerURL: [newFolder url]
withID: fmid];
}
[targetFolder cleanupCaches];
}
[self cleanupCaches];
/* We perform the mapping operations at the
end as objectId is required to be available
until the caches are cleaned up */
if (isMove && rc == MAPISTORE_SUCCESS)
{
fmid = [mapping idFromURL: [self url]];
[mapping unregisterURLWithID: fmid];
[mapping registerURL: [newFolder url]
withID: fmid];
}
}
else
rc = MAPISTORE_ERR_DENIED;
@@ -923,8 +946,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSString *baseURL, *URL, *key;
NSArray *newIDs;
uint64_t idNbr;
bool softDeleted;
baseURL = [self url];
mapping = [self mapping];
@@ -934,8 +956,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
{
key = [keys objectAtIndex: count];
URL = [NSString stringWithFormat: @"%@%@", baseURL, key];
idNbr = [mapping idFromURL: URL isSoftDeleted: &softDeleted];
if (idNbr == NSNotFound && !softDeleted)
idNbr = [mapping idFromURL: URL];
if (idNbr == NSNotFound)
[missingURLs addObject: URL];
}
@@ -945,6 +967,113 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
withIDs: newIDs];
}
- (void) postNotificationsForMoveCopyMessagesWithMIDs: (uint64_t *) srcMids
andMessageURLs: (NSArray *) oldMessageURLs
andCount: (uint32_t) midCount
fromFolder: (MAPIStoreFolder *) sourceFolder
withMIDs: (uint64_t *) targetMids
wantCopy: (uint8_t) wantCopy
{
NSArray *activeTables;
NSUInteger count, tableCount, max;
MAPIStoreMessage *message;
NSString *messageURL;
MAPIStoreMapping *mapping;
struct mapistore_object_notification_parameters *notif_parameters;
struct mapistore_connection_info *connInfo;
connInfo = [[self context] connectionInfo];
// For the "source folder, we ensure the table caches are loaded so
// that old and new state can be compared
activeTables = [sourceFolder activeMessageTables];
max = [activeTables count];
for (count = 0; count < max; count++)
[[activeTables objectAtIndex: count] restrictedChildKeys];
if (!wantCopy)
{
// We notify the client. We start with the source folder.
notif_parameters = talloc_zero(NULL, struct mapistore_object_notification_parameters);
notif_parameters->object_id = [sourceFolder objectId];
notif_parameters->tag_count = 5;
notif_parameters->tags = talloc_array (notif_parameters, enum MAPITAGS, 5);
notif_parameters->tags[0] = PR_CONTENT_COUNT;
notif_parameters->tags[1] = PR_DELETED_COUNT_TOTAL;
notif_parameters->tags[2] = PR_MESSAGE_SIZE;
notif_parameters->tags[3] = PR_NORMAL_MESSAGE_SIZE;
notif_parameters->tags[4] = PR_RECIPIENT_ON_NORMAL_MSG_COUNT;
notif_parameters->new_message_count = true;
notif_parameters->message_count = [[sourceFolder messageKeys] count] - midCount;
mapistore_push_notification (connInfo->mstore_ctx,
MAPISTORE_FOLDER,
MAPISTORE_OBJECT_MODIFIED,
notif_parameters);
talloc_free(notif_parameters);
}
// move/copy notification of the copied/moved message
for (count = 0; count < midCount; count++)
{
notif_parameters = talloc_zero (NULL, struct mapistore_object_notification_parameters);
notif_parameters->tag_count = 0;
notif_parameters->new_message_count = true;
notif_parameters->message_count = 0;
notif_parameters->object_id = targetMids[count];
notif_parameters->folder_id = [self objectId];
notif_parameters->old_object_id = srcMids[count];
notif_parameters->old_folder_id = [sourceFolder objectId];
mapistore_push_notification (connInfo->mstore_ctx,
MAPISTORE_MESSAGE,
(wantCopy ? MAPISTORE_OBJECT_COPIED : MAPISTORE_OBJECT_MOVED),
notif_parameters);
talloc_free (notif_parameters);
message = [sourceFolder lookupMessageByURL: [oldMessageURLs objectAtIndex: count]];
// table notification
for (tableCount = 0; tableCount < max; tableCount++)
[[activeTables objectAtIndex: tableCount]
notifyChangesForChild: message];
}
// For the "destination folder, we ensure the table caches are loaded so
// that old and new state can be compared
activeTables = [self activeMessageTables];
max = [activeTables count];
for (count = 0; count < max; count++)
[[activeTables objectAtIndex: count] restrictedChildKeys];
notif_parameters = talloc_zero(NULL, struct mapistore_object_notification_parameters);
notif_parameters->object_id = [self objectId];
notif_parameters->tag_count = 5;
notif_parameters->tags = talloc_array (notif_parameters, enum MAPITAGS, 5);
notif_parameters->tags[0] = PR_CONTENT_COUNT;
notif_parameters->tags[1] = PR_DELETED_COUNT_TOTAL;
notif_parameters->tags[2] = PR_MESSAGE_SIZE;
notif_parameters->tags[3] = PR_NORMAL_MESSAGE_SIZE;
notif_parameters->tags[4] = PR_RECIPIENT_ON_NORMAL_MSG_COUNT;
notif_parameters->new_message_count = true;
notif_parameters->message_count = [[self messageKeys] count] + midCount;
connInfo = [[self context] connectionInfo];
mapistore_push_notification (connInfo->mstore_ctx,
MAPISTORE_FOLDER,
MAPISTORE_OBJECT_MODIFIED,
notif_parameters);
talloc_free(notif_parameters);
// table notification
mapping = [self mapping];
for (count = 0; count < midCount; count++)
{
messageURL = [mapping urlFromID: targetMids[count]];
message = [self lookupMessageByURL: messageURL];
for (tableCount = 0; tableCount < max; tableCount++)
[[activeTables objectAtIndex: tableCount]
notifyChangesForChild: message];
}
}
- (int) getDeletedFMIDs: (struct UI8Array_r **) fmidsPtr
andCN: (uint64_t *) cnPtr
fromChangeNumber: (uint64_t) changeNum
@@ -959,7 +1088,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
MAPIStoreMapping *mapping;
struct UI8Array_r *fmids;
uint64_t fmid;
bool softDeleted;
keys = [self getDeletedKeysFromChangeNumber: changeNum andCN: &cnNbr
inTableType: tableType];
@@ -986,10 +1114,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
{
url = [NSString stringWithFormat: format,
baseURL, [keys objectAtIndex: count]];
fmid = [mapping idFromURL: url isSoftDeleted: &softDeleted];
fmid = [mapping idFromURL: url];
if (fmid != NSNotFound) /* if no fmid is returned, then the object
"never existed" in the OpenChange
databases. Soft-deleted messages are returned back */
databases */
{
fmids->lpui8[fmids->cValues] = fmid;
fmids->cValues++;
@@ -1053,10 +1181,9 @@ 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, PidTagChangeNumber, 0x00000000 };
PR_CHANGE_KEY, 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 */
@@ -1074,12 +1201,6 @@ 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,7 +1226,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
- (NSArray *) faiMessageKeysMatchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings
{
[[self userContext] activate];
return [dbFolder childKeysOfType: MAPIFAICacheObject
includeDeleted: NO
matchingQualifier: qualifier
@@ -1214,7 +1334,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
/*
Possible values are:
0x00000001 Modify
0x00000002 Read
0x00000004 Delete
@@ -1245,7 +1365,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
access |= 0x10;
if (userIsOwner)
access |= 0x20;
*data = MAPILongValue (memCtx, access);
return MAPISTORE_SUCCESS;
@@ -1274,7 +1394,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
rights |= RightsCreateSubfolders;
if (userIsOwner)
rights |= RightsFolderOwner | RightsFolderContact;
*data = MAPILongValue (memCtx, rights);
return MAPISTORE_SUCCESS;
@@ -1310,7 +1430,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPIBoolValue (memCtx, [self supportsSubFolders] && [[self folderKeys] count] > 0);
return MAPISTORE_SUCCESS;
}
@@ -1318,7 +1438,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPILongValue (memCtx, [[self folderKeys] count]);
return MAPISTORE_SUCCESS;
}
@@ -1420,7 +1540,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
[dbObject setIsNew: YES];
newMessage = [MAPIStoreFAIMessageK mapiStoreObjectWithSOGoObject: dbObject
inContainer: self];
return newMessage;
}
@@ -1429,8 +1549,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
MAPIStoreMessage *newMessage;
WOContext *woContext;
[[self userContext] activate];
if (isAssociated)
newMessage = [self _createAssociatedMessage];
else
@@ -1595,12 +1713,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
aclFolder = [self aclFolder];
users = [[aclFolder aclUsers] copy];
users = [aclFolder aclUsers];
max = [users count];
for (count = 0; count < max; count++)
[aclFolder removeUserFromAcls: [users objectAtIndex: count]];
[users release];
}
- (int) modifyPermissions: (struct PermissionData *) permissions
@@ -1630,7 +1746,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
permissionUser = nil;
permissionRoles = nil;
if (currentPermission->PermissionDataFlags == ROW_ADD)
isAdd = YES;
else if (currentPermission->PermissionDataFlags == ROW_MODIFY)
@@ -1748,17 +1864,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
inFolderURL: [self url]];
}
- (MAPIStoreFolder *) rootContainer
{
/* Return the oldest ancestor, which does not have
container. If there is not container, it returns itself.
*/
if (container)
return [container rootContainer];
else
return self;
}
- (NSDate *) creationTime
{
return [dbFolder creationDate];
@@ -1781,7 +1886,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
{
[self subclassResponsibility: _cmd];
return nil;
return nil;
}
- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum
+4 -6
View File
@@ -82,9 +82,7 @@
andTDBIndexing: indexing];
parentFolder = [[userContext rootFolders] objectForKey: moduleName];
baseUrl = [NSString stringWithFormat: @"sogo://%@@%@/",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
moduleName];
userName, moduleName];
subfolders = [parentFolder subFolders];
max = [subfolders count];
@@ -121,6 +119,7 @@
userContext = [MAPIStoreUserContext userContextWithUsername: userName
andTDBIndexing: NULL];
[MAPIApp setUserContext: userContext];
moduleName = [self MAPIModuleName];
parentFolder = [[userContext rootFolders] objectForKey: moduleName];
nameInContainer = nil;
@@ -128,11 +127,10 @@
if (![parentFolder newFolderWithName: folderName
nameInContainer: &nameInContainer])
mapistoreURI = [NSString stringWithFormat: @"sogo://%@@%@/%@/",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
moduleName, nameInContainer];
userName, moduleName, nameInContainer];
else
mapistoreURI = nil;
[MAPIApp setUserContext: nil];
return mapistoreURI;
}
+6 -19
View File
@@ -163,15 +163,8 @@
- (int) getPidTagDisplayName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *fileName;
fileName = [self _fileName];
if ([fileName isEqualToString: @"sharing_metadata.xml"])
/* Required to disallow user from seeing the attachment by default */
*data = [@"sharing_metadata.xml" asUnicodeInMemCtx: memCtx];
else
*data = [[bodyInfo objectForKey: @"description"]
asUnicodeInMemCtx: memCtx];
*data = [[bodyInfo objectForKey: @"description"]
asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
@@ -188,17 +181,11 @@
- (int) getPidTagAttachMimeTag: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *mimeTag, *fileName;
fileName = [self _fileName];
if ([fileName isEqualToString: @"sharing_metadata.xml"])
/* Required by [MS-OXWSMSHR] Section 3.1.1 */
mimeTag = [NSString stringWithFormat: @"application/x-sharing-metadata-xml"];
else
mimeTag = [NSString stringWithFormat: @"%@/%@",
[bodyInfo objectForKey: @"type"],
[bodyInfo objectForKey: @"subtype"]];
NSString *mimeTag;
mimeTag = [NSString stringWithFormat: @"%@/%@",
[bodyInfo objectForKey: @"type"],
[bodyInfo objectForKey: @"subtype"]];
*data = [[mimeTag lowercaseString] asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
+13 -36
View File
@@ -67,7 +67,7 @@ MakeDisplayFolderName (NSString *folderName)
NSArray *parts;
NSString *lastFolder;
NSUInteger max;
parts = [folderName componentsSeparatedByString: @"/"];
max = [parts count];
if (max > 1)
@@ -87,7 +87,7 @@ MakeDisplayFolderName (NSString *folderName)
inMemCtx: (TALLOC_CTX *) memCtx
{
struct mapistore_contexts_list *firstContext = NULL, *context;
NSString *urlBase, *stringData, *currentName, *realName, *inboxName, *draftsName, *sentName, *trashName;
NSString *urlBase, *stringData, *currentName, *inboxName, *draftsName, *sentName, *trashName;
NSArray *unprefixedFolders;
NSMutableArray *secondaryFolders;
enum mapistore_context_role role[] = {MAPISTORE_MAIL_ROLE,
@@ -126,11 +126,7 @@ MakeDisplayFolderName (NSString *folderName)
trashName = [NSString stringWithFormat: @"folder%@",
[unprefixedFolders componentsJoinedByString: @"/folder"]];
urlBase = [NSString stringWithFormat: @"sogo://%@:%@@mail/",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"]];
urlBase = [NSString stringWithFormat: @"sogo://%@:%@@mail/", userName, userName];
for (count = 0; count < 3; count++)
{
context = talloc_zero (memCtx, struct mapistore_contexts_list);
@@ -146,9 +142,6 @@ MakeDisplayFolderName (NSString *folderName)
DLIST_ADD_END (firstContext, context, void);
}
/* FIXME: Flush any cache before retrieving the hierarchy */
[accountFolder flushMailCaches];
secondaryFolders = [[accountFolder toManyRelationshipKeysWithNamespaces: NO]
mutableCopy];
[secondaryFolders autorelease];
@@ -160,23 +153,12 @@ MakeDisplayFolderName (NSString *folderName)
for (count = 0; count < max; count++)
{
context = talloc_zero (memCtx, struct mapistore_contexts_list);
// secondaryFolders has the names (1) Imap4Encoded and (2) asCSSIdentifier
// e.g.: Probl&AOg-mes_SP_de_SP_synchronisation
currentName = [secondaryFolders objectAtIndex: count];
// To get the real name we have to revert that (applying the decode functions)
// in reverse order
// e.g.: Problèmes de synchronisation
realName = [[currentName fromCSSIdentifier]
stringByDecodingImap4FolderName];
// And finally to represent that as URI we have to (1) asCSSIdentifier,
// (2) Imap4Encode and (3) AddPercentEscapes
// e.g.: Probl&AOg-mes_SP_de_SP_synchronisation
// In the example there are no percent escapes added because is already ok
stringData = [[[realName asCSSIdentifier]
stringByEncodingImap4FolderName]
stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
context->url = [[NSString stringWithFormat: @"%@%@", urlBase, stringData] asUnicodeInMemCtx: context];
context->name = [[realName substringFromIndex: 6] asUnicodeInMemCtx: context];
stringData = [NSString stringWithFormat: @"%@%@",
urlBase, [currentName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
context->url = [stringData asUnicodeInMemCtx: context];
stringData = [[[currentName substringFromIndex: 6] fromCSSIdentifier] stringByDecodingImap4FolderName];
context->name = [stringData asUnicodeInMemCtx: context];
context->main_folder = false;
context->role = MAPISTORE_MAIL_ROLE;
context->tag = "tag";
@@ -198,6 +180,7 @@ MakeDisplayFolderName (NSString *folderName)
userContext = [MAPIStoreUserContext userContextWithUsername: userName
andTDBIndexing: NULL];
[MAPIApp setUserContext: userContext];
accountFolder = [[userContext rootFolders] objectForKey: @"mail"];
folderName = [NSString stringWithFormat: @"folder%@",
[newFolderName asCSSIdentifier]];
@@ -205,13 +188,11 @@ MakeDisplayFolderName (NSString *folderName)
inContainer: accountFolder];
if ([newFolder create])
mapistoreURI = [NSString stringWithFormat: @"sogo://%@:%@@mail/%@/",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
userName, userName,
[[folderName stringByEncodingImap4FolderName] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
else
mapistoreURI = nil;
[MAPIApp setUserContext: nil];
return mapistoreURI;
}
@@ -283,12 +264,8 @@ MakeDisplayFolderName (NSString *folderName)
componentsSeparatedByString: @"/"];
folderName = [NSString stringWithFormat: @"folder%@",
[unprefixedFolders componentsJoinedByString: @"/folder"]];
url = [NSString stringWithFormat: @"sogo://%@:%@@outbox/%@",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
folderName];
url = [NSString stringWithFormat: @"sogo://%@:%@@outbox/%@", userName,
userName, folderName];
context = talloc_zero (memCtx, struct mapistore_contexts_list);
context->url = [url asUnicodeInMemCtx: context];
-8
View File
@@ -44,9 +44,6 @@
/* synchronisation & versioning */
- (BOOL) synchroniseCache;
- (void) synchronizeUpdatedFolder: (NSNumber *) lastModseq
withMapping: (NSMutableDictionary *) mapping;
- (BOOL) synchroniseCacheForUID: (NSString *) messageUID;
- (NSNumber *) modseqFromMessageChangeNumber: (NSString *) changeNum;
- (NSString *) messageUIDFromMessageKey: (NSString *) messageKey;
- (NSString *) changeNumberForMessageUID: (NSString *) messageUid;
@@ -55,11 +52,6 @@
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey;
- (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey;
/* Extra properties from mail messages that already hit the server */
- (void) setExtraProperties: (NSDictionary *) props
forMessage: (NSString *) messageKey;
- (NSDictionary *) extraPropertiesForMessage: (NSString *) messageKey;
@end
/* MAPIStoreOutboxFolder is a special subclass of MAPIStoreMailFolder where
+56 -384
View File
@@ -52,7 +52,6 @@
#import "MAPIStoreFAIMessage.h"
#import "MAPIStoreMailContext.h"
#import "MAPIStoreMailMessage.h"
#import "MAPIStoreMailFolderTable.h"
#import "MAPIStoreMailMessageTable.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreTypes.h"
@@ -71,7 +70,6 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
#undef DEBUG
#include <util/attr.h>
#include <libmapi/libmapi.h>
#include <libmapiproxy.h>
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
@@ -139,7 +137,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];
@@ -155,11 +153,6 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
return [MAPIStoreMailMessageTable tableForContainer: self];
}
- (MAPIStoreFolderTable *) folderTable
{
return [MAPIStoreMailFolderTable tableForContainer: self];
}
- (enum mapistore_error) createFolder: (struct SRow *) aRow
withFID: (uint64_t) newFID
andKey: (NSString **) newKeyP
@@ -170,7 +163,6 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
int i;
nameInContainer = nil;
rc = MAPISTORE_ERROR;
folderName = nil;
for (i = 0; !folderName && i < aRow->cValues; i++)
@@ -185,9 +177,6 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
{
nameInContainer = [NSString stringWithFormat: @"folder%@",
[[folderName stringByEncodingImap4FolderName] asCSSIdentifier]];
[[self userContext] activate];
newFolder = [SOGoMailFolderK objectWithName: nameInContainer
inContainer: sogoObject];
if ([newFolder create])
@@ -242,7 +231,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
sortOrdering: nil]
count];
*data = MAPILongValue (memCtx, longValue);
return MAPISTORE_SUCCESS;
}
@@ -250,7 +239,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"IPF.Note" asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
@@ -262,7 +251,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
if (!nonDeletedQualifier)
{
deletedQualifier
= [[EOKeyValueQualifier alloc]
= [[EOKeyValueQualifier alloc]
initWithKey: @"FLAGS"
operatorSelector: EOQualifierOperatorContains
value: [NSArray arrayWithObject: @"Deleted"]];
@@ -362,54 +351,19 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
- (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings
{
NSArray *filteredSubfolderKeys;
NSMutableArray *subfolderKeys;
NSMutableArray *subfolderKeysQualifying;
NSString *subfolderKey;
NSUInteger count, max;
if ([self ensureFolderExists])
{
/* Only folder name can be used as qualifier key */
if (qualifier)
[self warnWithFormat: @"qualifier is only used for folders with name"];
[self errorWithFormat: @"qualifier is not used for folders"];
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)
[sogoObject flushMailCaches];
subfolderKeys = [[sogoObject toManyRelationshipKeys] mutableCopy];
[subfolderKeys autorelease];
[self _cleanupSubfolderKeys: subfolderKeys];
if (qualifier)
{
subfolderKeysQualifying = [NSMutableArray array];
max = [subfolderKeys count];
for (count = 0; count < max; count++) {
subfolderKey = [subfolderKeys objectAtIndex: count];
/* Remove "folder" prefix */
subfolderKey = [subfolderKey substringFromIndex: 6];
subfolderKey = [[subfolderKey fromCSSIdentifier] stringByDecodingImap4FolderName];
[subfolderKeysQualifying addObject: [NSDictionary dictionaryWithObject: subfolderKey
forKey: @"name"]];
}
filteredSubfolderKeys = [subfolderKeysQualifying filteredArrayUsingQualifier: qualifier];
max = [filteredSubfolderKeys count];
subfolderKeys = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{
subfolderKey = [[filteredSubfolderKeys objectAtIndex: count] valueForKey: @"name"];
subfolderKey = [NSString stringWithFormat: @"folder%@", [[subfolderKey stringByEncodingImap4FolderName] asCSSIdentifier]];
[subfolderKeys addObject: subfolderKey];
}
}
}
else
subfolderKeys = nil;
@@ -469,7 +423,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
}
else
supportsSubFolders = YES;
return supportsSubFolders;
}
@@ -557,7 +511,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
*nextModseq;
NSString *changeNumber, *uid, *messageKey;
uint64_t lastModseqNbr;
EOQualifier *searchQualifier;
EOQualifier *kvQualifier, *searchQualifier;
NSArray *uids, *changeNumbers;
NSUInteger count, max;
NSArray *fetchResults;
@@ -598,11 +552,14 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
{
lastModseqNbr = [lastModseq unsignedLongLongValue];
nextModseq = [NSNumber numberWithUnsignedLongLong: lastModseqNbr + 1];
searchQualifier = [[EOKeyValueQualifier alloc]
kvQualifier = [[EOKeyValueQualifier alloc]
initWithKey: @"modseq"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: nextModseq];
searchQualifier = [[EOAndQualifier alloc]
initWithQualifiers:
kvQualifier, [self nonDeletedQualifier], nil];
[kvQualifier release];
[searchQualifier autorelease];
}
else
@@ -630,7 +587,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
fetchResults
= [(NSDictionary *) [sogoObject fetchUIDs: uids
parts: [NSArray arrayWithObjects: @"modseq", @"flags", nil]]
parts: [NSArray arrayWithObject: @"modseq"]]
objectForKey: @"fetch"];
/* NOTE: we sort items manually because Cyrus does not properly sort
@@ -638,7 +595,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
fetchResults
= [fetchResults sortedArrayUsingFunction: _compareFetchResultsByMODSEQ
context: NULL];
for (count = 0; count < max; count++)
{
result = [fetchResults objectAtIndex: count];
@@ -666,230 +623,58 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
if (!lastModseq
|| ([lastModseq compare: modseq] == NSOrderedAscending))
lastModseq = modseq;
if ([[result objectForKey: @"flags"] containsObject: @"deleted"])
[currentProperties setObject: changeNumber
forKey: @"SyncLastDeleteChangeNumber"];
}
[currentProperties setObject: lastModseq forKey: @"SyncLastModseq"];
foundChange = YES;
}
/* 2. we synchronise expunged UIDs */
/* 2. we synchronise deleted UIDs */
if (initialLastModseq)
{
fetchResults = [(SOGoMailFolder *) sogoObject
fetchUIDsOfVanishedItems: lastModseqNbr];
max = [fetchResults count];
changeNumbers = [[self context] getNewChangeNumbers: max];
changeNumber = nil;
for (count = 0; count < max; count++)
{
uid = [[fetchResults objectAtIndex: count] stringValue];
uid = [fetchResults objectAtIndex: count];
if ([messages objectForKey: uid])
{
if (!changeNumber)
{
newChangeNum = [[self context] getNewChangeNumber];
changeNumber = [NSString stringWithUnsignedLongLong: newChangeNum];
}
newChangeNum = [[changeNumbers objectAtIndex: count]
unsignedLongLongValue];
changeNumber = [NSString stringWithUnsignedLongLong: newChangeNum];
[messages removeObjectForKey: uid];
[self logWithFormat: @"Removed message entry for UID %@", uid];
}
else
{
[self logWithFormat:@"Message entry not found for UID %@", uid];
[self logWithFormat: @"removed message entry for uid %@", uid];
}
}
if (changeNumber)
{
[currentProperties setObject: changeNumber
forKey: @"SyncLastDeleteChangeNumber"];
[mapping setObject: lastModseq forKey: changeNumber];
foundChange = YES;
}
}
if (foundChange)
{
[self synchronizeUpdatedFolder: lastModseq
withMapping: mapping];
ti = [NSNumber numberWithDouble: [now timeIntervalSince1970]];
[currentProperties setObject: ti
forKey: @"SyncLastSynchronisationDate"];
[versionsMessage save];
}
return rc;
}
- (void) synchronizeUpdatedFolder: (NSNumber *) lastModseq
withMapping: (NSMutableDictionary *) mapping
{
/* This method should be called whenever something has changed on the folder.
Then we will perform two actions:
1 - Update the PidTagChangeNumber property of the root container.
2 - Store relationship PidTagChangenumber with lastModseq value on the
mapping given as parameter for this folder */
uint64_t *current_cn;
struct SRow row;
struct SPropValue prop;
uint64_t fid;
const char *username;
struct openchangedb_context *oc_ctx;
enum MAPISTATUS retval;
TALLOC_CTX *local_mem_ctx = NULL;
row.cValues = 1;
prop.ulPropTag = PidTagChangeNumber;
prop.value.d = 0; // It doesn't matter, it will be autogenerated
row.lpProps = &prop;
/* We are doing a "touch" operation to update change number of the root container.
We get the root container as it has the properties in the OpenChange DB */
username = [[self context] connectionInfo]->username;
oc_ctx = [[self context] connectionInfo]->oc_ctx;
fid = [[self rootContainer] objectId];
retval = openchangedb_set_folder_properties(oc_ctx, username, fid, &row);
if (retval != MAPI_E_SUCCESS)
{
[self errorWithFormat:@"%s: Error setting change number on %"PRIu64,
__PRETTY_FUNCTION__, fid];
return;
}
local_mem_ctx = talloc_named(NULL, 0, __PRETTY_FUNCTION__);
if (local_mem_ctx == NULL)
{
[self errorWithFormat:@"%s: Error with talloc_named, out of memory?",
__PRETTY_FUNCTION__];
return;
}
retval = openchangedb_get_folder_property(local_mem_ctx, oc_ctx, username,
PidTagChangeNumber, fid,
(void **) &current_cn);
if (retval != MAPI_E_SUCCESS)
{
[self errorWithFormat:@"%s: Error getting change number on %"PRIu64,
__PRETTY_FUNCTION__, fid];
talloc_free(local_mem_ctx);
return;
}
[mapping setObject: lastModseq
forKey: [NSString stringWithUnsignedLongLong: *current_cn]];
talloc_free(local_mem_ctx);
}
- (BOOL) synchroniseCacheForUID: (NSString *) messageUID
{
/* Try to synchronise old UIDs in versions.plist cache using an
specific UID. It returns a boolean indicating if the
synchronisation were done.
It should be used as last resort, keeping synchroniseCache to main
sync entry point.
*/
NSMutableDictionary *currentProperties, *messages, *messageEntry, *mapping;
NSArray *fetchResults;
uint64_t changeNumber;
NSDictionary *result;
NSNumber *modseq;
NSString *changeNumberStr;
NSData *changeKey;
[versionsMessage reloadIfNeeded];
currentProperties = [versionsMessage properties];
messages = [currentProperties objectForKey: @"Messages"];
messageEntry = [messages objectForKey: messageUID];
if (!messageEntry)
{
fetchResults = [(NSDictionary *) [sogoObject fetchUIDs: [NSArray arrayWithObject: messageUID]
parts: [NSArray arrayWithObjects: @"modseq", @"flags", nil]]
objectForKey: @"fetch"];
if ([fetchResults count] == 1)
{
result = [fetchResults objectAtIndex: 0];
modseq = [result objectForKey: @"modseq"];
changeNumber = [[self context] getNewChangeNumber];
changeNumberStr = [NSString stringWithUnsignedLongLong: changeNumber];
/* Create new message entry in Messages dict */
messageEntry = [NSMutableDictionary new];
[messages setObject: messageEntry forKey: messageUID];
[messageEntry release];
/* Store the modseq and change number */
[messageEntry setObject: modseq forKey: @"modseq"];
[messageEntry setObject: changeNumberStr forKey: @"version"];
/* Store the change key */
changeKey = [self getReplicaKeyFromGlobCnt: changeNumber >> 16];
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
/* Store the changeNumber -> modseq mapping */
mapping = [currentProperties objectForKey: @"VersionMapping"];
[mapping setObject: modseq forKey: changeNumberStr];
/* Store the last deleted change number if it is soft-deleted */
if ([[result objectForKey: @"flags"] containsObject: @"deleted"])
[currentProperties setObject: changeNumberStr
forKey: @"SyncLastDeleteChangeNumber"];
/* Save the message */
[versionsMessage save];
return YES;
}
else
{
return NO;
}
}
/* If message entry exists, then synchroniseCache did its job */
return YES;
}
- (NSNumber *) modseqFromMessageChangeNumber: (NSString *) changeNum
{
NSDictionary *mapping;
NSNumber *modseq;
NSEnumerator *enumerator;
id key;
uint64_t found, target, current, replica_id, current_cn;
NSString *closestChangeNum;
mapping = [[versionsMessage properties] objectForKey: @"VersionMapping"];
modseq = [mapping objectForKey: changeNum];
if (modseq) return modseq;
// Not found from stored change numbers for this folder.
// Get the closest modseq for the change number given.
// O(n) cost but will be unusual behaviour.
target = exchange_globcnt([changeNum unsignedLongLongValue] >> 16);
replica_id = [changeNum unsignedLongLongValue] & 0xFFFF;
found = 0;
enumerator = [mapping keyEnumerator];
while ((key = [enumerator nextObject]))
{
current_cn = [(NSString *)key unsignedLongLongValue];
if ((current_cn & 0xFFFF) != replica_id)
continue;
current = exchange_globcnt(current_cn >> 16);
if (current < target && current > found)
found = current;
}
if (found)
{
closestChangeNum = [NSString stringWithUnsignedLongLong:
(exchange_globcnt(found) << 16 | replica_id)];
modseq = [mapping objectForKey: closestChangeNum];
}
return modseq;
}
@@ -903,11 +688,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
if (dotRange.location != NSNotFound)
messageUid = [messageKey substringToIndex: dotRange.location];
else
{
messageUid = nil;
[self errorWithFormat:@"%s: Unexpected messageKey value [%@]",
__PRETTY_FUNCTION__, messageKey];
}
messageUid = nil;
return messageUid;
}
@@ -929,26 +710,14 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
{
NSMutableDictionary *messages, *messageEntry;
NSString *messageUid;
BOOL synced;
messageUid = [self messageUIDFromMessageKey: messageKey];
messages = [[versionsMessage properties] objectForKey: @"Messages"];
messageEntry = [messages objectForKey: messageUid];
if (!messageEntry)
{
[self warnWithFormat: @"attempting to synchronise to set the change key for "
@"this message %@", messageKey];
synced = [self synchroniseCacheForUID: messageUid];
if (synced)
messageEntry = [[[versionsMessage properties] objectForKey: @"Messages"] objectForKey: messageUid];
if (!messageEntry)
{
[self errorWithFormat: @"still nothing. We crash!"];
abort ();
}
}
abort ();
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
[versionsMessage save];
}
@@ -1015,37 +784,6 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
return list;
}
/* Management for extra properties once they already hit the IMAP server */
- (void) setExtraProperties: (NSDictionary *) props
forMessage: (NSString *) messageKey
{
NSMutableDictionary *extraProps, *currentProperties;
NSString *messageUid;
messageUid = [self messageUIDFromMessageKey: messageKey];
currentProperties = [versionsMessage properties];
extraProps = [currentProperties objectForKey: @"ExtraMessagesProperties"];
if (!extraProps)
{
extraProps = [NSMutableDictionary new];
[currentProperties setObject: extraProps forKey: @"ExtraMessagesProperties"];
[extraProps release];
}
[extraProps setObject: props
forKey: messageUid];
[versionsMessage save];
}
- (NSDictionary *) extraPropertiesForMessage: (NSString *) messageKey
{
NSString *messageUid;
messageUid = [self messageUIDFromMessageKey: messageKey];
return [[[versionsMessage properties] objectForKey: @"ExtraMessagesProperties"]
objectForKey: messageUid];
}
- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum
andCN: (NSNumber **) cnNbr
inTableType: (uint8_t) tableType
@@ -1054,7 +792,6 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
NSString *changeNumber;
uint64_t modseq;
NSDictionary *versionProperties;
EOQualifier *deletedQualifier, *kvQualifier, *searchQualifier;
if (tableType == MAPISTORE_MESSAGE_TABLE)
{
@@ -1063,33 +800,8 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
unsignedLongLongValue];
if (modseq > 0)
{
/* Hard deleted items */
deletedUIDs = [(SOGoMailFolder *) sogoObject
fetchUIDsOfVanishedItems: modseq];
/* Soft deleted items */
kvQualifier = [[EOKeyValueQualifier alloc]
initWithKey: @"modseq"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: [NSNumber numberWithUnsignedLongLong: modseq]];
deletedQualifier
= [[EOKeyValueQualifier alloc]
initWithKey: @"FLAGS"
operatorSelector: EOQualifierOperatorContains
value: [NSArray arrayWithObject: @"Deleted"]];
searchQualifier = [[EOAndQualifier alloc]
initWithQualifiers:
kvQualifier, deletedQualifier, nil];
deletedUIDs = [deletedUIDs arrayByAddingObjectsFromArray:
[sogoObject fetchUIDsMatchingQualifier: searchQualifier
sortOrdering: nil]];
[deletedQualifier release];
[kvQualifier release];
[searchQualifier release];
deletedKeys = [deletedUIDs stringsWithFormat: @"%@.eml"];
if ([deletedUIDs count] > 0)
{
@@ -1145,8 +857,6 @@ _parseIMAPRange (const unichar *uniString, NSArray **UIDsP)
uint32_t currentUid, rangeMin;
BOOL done = NO, inRange = NO;
rangeMin = 0;
currentUid = 0;
UIDs = [NSMutableArray array];
while (!done)
{
@@ -1175,7 +885,7 @@ _parseIMAPRange (const unichar *uniString, NSArray **UIDsP)
count++;
}
*UIDsP = UIDs;
return count;
}
@@ -1271,20 +981,13 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
if (![[result objectForKey: @"result"] boolValue])
return MAPISTORE_ERROR;
/* "Move" treatment: Store \Deleted and unregister urls as soft-deleted */
/* "Move" treatment: Store \Deleted and unregister urls */
if (!wantCopy)
{
[client storeFlags: [NSArray arrayWithObject: @"Deleted"] forUIDs: uids
addOrRemove: YES];
for (count = 0; count < midCount; count++)
{
/* Using soft-deleted to make deleted fmids to return the
srcMids.
See [MAPIStoreFolder getDeletedFMIDs:andCN:fromChangeNumber:inTableType:inMemCtx]
for details */
[mapping unregisterURLWithID: srcMids[count]
andFlags: MAPISTORE_SOFT_DELETE];
}
[mapping unregisterURLWithID: srcMids[count]];
}
/* Registration of target messages */
@@ -1333,6 +1036,13 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
}
}
[self postNotificationsForMoveCopyMessagesWithMIDs: srcMids
andMessageURLs: oldMessageURLs
andCount: midCount
fromFolder: sourceFolder
withMIDs: targetMids
wantCopy: wantCopy];
// We cleanup cache of our source and destination folders
[self cleanupCaches];
[sourceFolder cleanupCaches];
@@ -1351,7 +1061,6 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
struct SRow folderRow;
struct SPropValue nameProperty;
MAPIStoreMailFolder *newFolder;
SOGoMailAccount *accountFolder;
SOGoMailFolder *targetSOGoFolder;
NSMutableArray *uids;
NSArray *childKeys;
@@ -1359,12 +1068,12 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
NGImap4Connection *connection;
NGImap4Client *client;
NSString *newURL, *parentDBFolderPath, *childKey, *folderIMAPName,
*urlNamePart, *newFolderIMAPName, *newFolderDBName;
*urlNamePart, *newFolderIMAPName;
NSException *error;
MAPIStoreMapping *mapping;
NSDictionary *result;
if ([targetFolder isKindOfClass: MAPIStoreMailFolderK] || (!targetFolder && isMove))
if ([targetFolder isKindOfClass: MAPIStoreMailFolderK])
{
folderURL = [sogoObject imap4URL];
if (!newFolderName)
@@ -1372,23 +1081,9 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
targetSOGoFolder = [targetFolder sogoObject];
if (isMove)
{
newFolderDBName = [[newFolderName stringByEncodingImap4FolderName] asCSSIdentifier];
if (targetSOGoFolder)
{
/* Mimetise [SOGoMailFolderK imap4URLString] */
urlNamePart = [[newFolderName stringByEncodingImap4FolderName] stringByEscapingURL];
newFolderURL = [NSURL URLWithString: urlNamePart
relativeToURL: [targetSOGoFolder imap4URL]];
}
else
{
/* Mimetise what createRootSecondaryFolderWithFID does */
accountFolder = [[[self userContext] rootFolders] objectForKey: @"mail"];
targetSOGoFolder = [SOGoMailFolder objectWithName: [NSString stringWithFormat: @"folder%@",
newFolderDBName]
inContainer: accountFolder];
newFolderURL = [targetSOGoFolder imap4URL];
}
urlNamePart = [newFolderName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
newFolderURL = [NSURL URLWithString: urlNamePart
relativeToURL: [targetSOGoFolder imap4URL]];
error = [[sogoObject imap4Connection]
moveMailboxAtURL: folderURL
toURL: newFolderURL];
@@ -1398,29 +1093,16 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
{
rc = MAPISTORE_SUCCESS;
mapping = [self mapping];
if (targetFolder)
newURL = [NSString stringWithFormat: @"%@folder%@/",
[targetFolder url], newFolderDBName];
else
newURL = [NSString stringWithFormat: @"sogo://%@:%@@mail/folder%@/",
[[self userContext] username], [[self userContext] username],
newFolderDBName];
newURL = [NSString stringWithFormat: @"%@folder%@/",
[targetFolder url], urlNamePart];
[mapping updateID: [self objectId] withURL: newURL];
if (targetFolder)
{
parentDBFolderPath = [[targetFolder dbFolder] path];
if (!parentDBFolderPath)
parentDBFolderPath = @"";
[dbFolder changePathTo: [NSString stringWithFormat:
@"%@/folder%@",
parentDBFolderPath,
newFolderDBName]
intoNewContainer: [targetFolder dbFolder]];
}
else
[dbFolder changePathTo: [NSString stringWithFormat:
@"/mail/folder%@", newFolderDBName]
intoNewContainer: nil];
parentDBFolderPath = [[targetFolder dbFolder] path];
if (!parentDBFolderPath)
parentDBFolderPath = @"";
[dbFolder changePathTo: [NSString stringWithFormat:
@"%@/folder%@",
parentDBFolderPath,
newFolderName]];
}
}
else
@@ -1453,7 +1135,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])
{
@@ -1492,10 +1174,9 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
{
SOGoCacheObject *childObject;
[[[self context] userContext] activate];
childObject = [SOGoCacheObject objectWithName: [SOGoCacheObject globallyUniqueObjectId]
inContainer: sogoObject];
childObject = [SOGoCacheObject objectWithName: [SOGoCacheObject
globallyUniqueObjectId]
inContainer: sogoObject];
return [MAPIStoreMailVolatileMessage
mapiStoreObjectWithSOGoObject: childObject
inContainer: self];
@@ -1571,7 +1252,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
rights |= RoleNone; /* actually "folder visible" */
// [self logWithFormat: @"rights for roles (%@) = %.8x", roles, rights];
return rights;
}
@@ -1609,20 +1290,11 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
{
[bodyPartKeys addObject: bodyPartKey];
messageUid = [self messageUIDFromMessageKey: messageKey];
/* If the bodyPartKey include peek, remove it as it is not returned
as key in the IMAP server response.
IMAP conversation example:
a4 UID FETCH 1 (UID BODY.PEEK[text])
* 1 FETCH (UID 1 BODY[TEXT] {1677}
*/
bodyPartKey = [bodyPartKey stringByReplacingOccurrencesOfString: @"body.peek"
withString: @"body"];
[keyAssoc setObject: bodyPartKey forKey: messageUid];
}
}
}
client = [[(SOGoMailFolder *) sogoObject imap4Connection] client];
[client select: [sogoObject absoluteImap4Name]];
response = [client fetchUids: [keyAssoc allKeys]
-31
View File
@@ -1,31 +0,0 @@
/* MAPIStoreMailFolderTable.h - this file is part of SOGo
*
* Copyright (C) 2015 Enrique J. Hernández
*
* Author: Enrique J. Hernández <ejhernandez@zentyal.com>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef MAPISTOREMAILFOLDERTABLE_H
#define MAPISTOREMAILFOLDERTABLE_H
#import "MAPIStoreFolderTable.h"
@interface MAPIStoreMailFolderTable : MAPIStoreFolderTable
@end
#endif /* MAPISTOREMAILFOLDERTABLE_H */
-42
View File
@@ -1,42 +0,0 @@
/* MAPIStoreMailFolderTable.m - this file is part of SOGo
*
* Copyright (C) 2015 Enrique J. Hernández
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSString.h>
#import "MAPIStoreMailFolderTable.h"
#import "MAPIStoreTypes.h"
@implementation MAPIStoreMailFolderTable
- (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property
{
switch(property)
{
case PR_DISPLAY_NAME:
case PR_DISPLAY_NAME_UNICODE:
return @"name";
default:
return nil;
}
}
@end
-2
View File
@@ -35,8 +35,6 @@
{
BOOL headerSetup;
BOOL mailIsEvent;
BOOL mailIsMeetingRequest;
BOOL mailIsSharingObject;
NSString *mimeKey;
NSString *headerCharset;
NSString *headerEncoding;
+37 -152
View File
@@ -32,7 +32,6 @@
#import <NGImap4/NGImap4EnvelopeAddress.h>
#import <NGMail/NGMailAddress.h>
#import <NGMail/NGMailAddressParser.h>
#import <NGMail/NGMimeMessageGenerator.h>
#import <NGCards/iCalCalendar.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSString+Utilities.h>
@@ -41,7 +40,6 @@
#import <Mailer/SOGoMailBodyPart.h>
#import <Mailer/SOGoMailObject.h>
#import "Codepages.h"
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
@@ -52,7 +50,6 @@
#import "MAPIStoreMailFolder.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreSamDBUtils.h"
#import "MAPIStoreSharingMessage.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
@@ -66,7 +63,7 @@
@class iCalCalendar, iCalEvent;
static Class NSExceptionK, MAPIStoreSharingMessageK;
static Class NSExceptionK;
@interface NSString (MAPIStoreMIME)
@@ -109,7 +106,6 @@ static Class NSExceptionK, MAPIStoreSharingMessageK;
+ (void) initialize
{
NSExceptionK = [NSException class];
MAPIStoreSharingMessageK = [MAPIStoreSharingMessage class];
}
- (id) init
@@ -118,8 +114,6 @@ static Class NSExceptionK, MAPIStoreSharingMessageK;
{
mimeKey = nil;
mailIsEvent = NO;
mailIsMeetingRequest = NO;
mailIsSharingObject = NO;
headerCharset = nil;
headerEncoding = nil;
headerMimeType = nil;
@@ -138,7 +132,6 @@ static Class NSExceptionK, MAPIStoreSharingMessageK;
[bodyContent release];
[headerMimeType release];
[headerCharset release];
[headerEncoding release];
[appointmentWrapper release];
[super dealloc];
}
@@ -158,30 +151,6 @@ static Class NSExceptionK, MAPIStoreSharingMessageK;
return [sogoObject date];
}
- (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP
inMemCtx: (TALLOC_CTX *) memCtx
{
BOOL listedProperties[65536];
NSUInteger count;
uint16_t propId;
if (mailIsSharingObject)
{
memset (listedProperties, NO, 65536 * sizeof (BOOL));
[super getAvailableProperties: propertiesP inMemCtx: memCtx];
for (count = 0; count < (*propertiesP)->cValues; count++)
{
propId = ((*propertiesP)->aulPropTag[count] >> 16) & 0xffff;
listedProperties[propId] = YES;
}
[MAPIStoreSharingMessage fillAvailableProperties: *propertiesP
withExclusions: listedProperties];
return MAPISTORE_SUCCESS;
}
else
return [super getAvailableProperties: propertiesP inMemCtx: memCtx];
}
static NSComparisonResult
_compareBodyKeysByPriority (id entry1, id entry2, void *data)
{
@@ -231,11 +200,9 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
- (void) _fetchHeaderData
{
MAPIStoreSharingMessage *sharingMessage;
NSMutableArray *keys;
NSArray *acceptedTypes;
NSDictionary *messageData, *partHeaderData, *parameters;
NSString *sharingHeader;
acceptedTypes = [NSArray arrayWithObjects: @"text/calendar",
@"application/ics",
@@ -259,27 +226,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
ASSIGN (headerCharset, [parameters objectForKey: @"charset"]);
if ([headerMimeType isEqualToString: @"text/calendar"]
|| [headerMimeType isEqualToString: @"application/ics"])
{
mailIsEvent = YES;
if ([[parameters objectForKey: @"method"] isEqualToString: @"REQUEST"])
mailIsMeetingRequest = YES;
}
else
{
sharingHeader = [[sogoObject mailHeaders] objectForKey: @"x-ms-sharing-localtype"];
if (sharingHeader)
{
mailIsSharingObject = YES;
/* It is difficult to subclass this in folder class, that's why
a sharing object is a proxy in a mail message */
sharingMessage = [[MAPIStoreSharingMessage alloc]
initWithMailHeaders: [sogoObject mailHeaders]
andConnectionInfo: [[self context] connectionInfo]
fromMessage: self];
[self addProxy: sharingMessage];
[sharingMessage release];
}
}
}
headerSetup = YES;
@@ -421,7 +368,6 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
{
uint64_t version = ULLONG_MAX;
NSString *uid, *changeNumber;
BOOL synced;
uid = [(MAPIStoreMailFolder *)
container messageUIDFromMessageKey: [self nameInContainer]];
@@ -440,19 +386,8 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
[self logWithFormat: @"got one"];
else
{
[self warnWithFormat: @"attempting to get change number"
@" by synchronising this specific message..."];
synced = [(MAPIStoreMailFolder *) container synchroniseCacheForUID: uid];
if (synced)
{
changeNumber = [(MAPIStoreMailFolder *) container
changeNumberForMessageUID: uid];
}
else
{
[self errorWithFormat: @"still nothing. We crash!"];
abort();
}
[self errorWithFormat: @"still nothing. We crash!"];
abort();
}
}
version = [changeNumber unsignedLongLongValue] >> 16;
@@ -569,31 +504,36 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if (mailIsEvent)
[[self _appointmentWrapper] getPidTagMessageClass: data
inMemCtx: memCtx];
else if (mailIsSharingObject)
*data = talloc_strdup (memCtx, "IPM.Sharing");
else
*data = talloc_strdup (memCtx, "IPM.Note");
return MAPISTORE_SUCCESS;
}
- (int) getPidTagReplyRequested: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
/* Note: this applies to regular mails... */
// - (int) getPidTagReplyRequested: (void **) data // TODO
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// if (!headerSetup)
// [self _fetchHeaderData];
// return (mailIsEvent
// ? [self getYes: data inMemCtx: memCtx]
// : [self getNo: data inMemCtx: memCtx]);
// }
/* ... while this applies to invitations. */
- (int) getPidTagResponseRequested: (void **) data // TODO
inMemCtx: (TALLOC_CTX *) memCtx
{
if (!headerSetup)
[self _fetchHeaderData];
return (mailIsMeetingRequest
? [self getYes: data inMemCtx: memCtx]
return (mailIsEvent
? [self getNo: data inMemCtx: memCtx]
: MAPISTORE_ERR_NOT_FOUND);
}
- (int) getPidTagResponseRequested: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidTagReplyRequested: data inMemCtx: memCtx];
}
- (int) getPidTagLatestDeliveryTime: (void **) data // DOUBT
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -801,7 +741,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
contactInfos = [mgr contactInfosForUserWithUIDorEmail: email];
if (contactInfos)
{
username = [contactInfos objectForKey: @"sAMAccountName"];
username = [contactInfos objectForKey: @"c_uid"];
samCtx = [[self context] connectionInfo]->sam_ctx;
entryId = MAPIStoreInternalEntryId (samCtx, username);
}
@@ -983,17 +923,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
- (int) getPidTagInternetCodepage: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSNumber *codepage;
codepage = [Codepages getCodepageFromName: headerCharset];
if (!codepage)
{
[self warnWithFormat: @"Couldn't find codepage from `%@`. "
@"Using UTF-8 by default", headerCharset];
codepage = [Codepages getCodepageFromName: @"utf-8"];
}
*data = MAPILongValue(memCtx, [codepage intValue]);
/* ref:
http://msdn.microsoft.com/en-us/library/dd317756%28v=vs.85%29.aspx
minimal list that should be handled:
us-ascii: 20127
iso-8859-1: 28591
iso-8859-15: 28605
utf-8: 65001 */
*data = MAPILongValue(memCtx, 65001);
return MAPISTORE_SUCCESS;
}
@@ -1395,41 +1333,6 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
: MAPISTORE_ERR_NOT_FOUND);
}
- (int) getPidTagTransportMessageHeaders: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSDictionary *mailHeaders;
NSEnumerator *keyEnumerator;
NSMutableArray *headers;
NGMimeMessageGenerator *g;
NSString *headerKey, *fullHeader, *headerGenerated;
id headerValue;
NSData *headerData;
/* Let's encode each mail header and put them on 'headers' array */
mailHeaders = [sogoObject mailHeaders];
headers = [NSMutableArray arrayWithCapacity: [mailHeaders count]];
g = [[NGMimeMessageGenerator alloc] init];
keyEnumerator = [mailHeaders keyEnumerator];
while ((headerKey = [keyEnumerator nextObject]))
{
headerValue = [mailHeaders objectForKey: headerKey];
headerData = [g generateDataForHeaderField: headerKey value: headerValue];
headerGenerated = [[NSString alloc] initWithData: headerData encoding:NSUTF8StringEncoding];
fullHeader = [NSString stringWithFormat:@"%@: %@", headerKey, headerGenerated];
[headerGenerated release];
[headers addObject: fullHeader];
}
[g release];
*data = [[headers componentsJoinedByString:@"\n"] asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (void) getMessageData: (struct mapistore_message **) dataPtr
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -1499,10 +1402,10 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if ([cn length] == 0)
cn = email;
contactInfos = [mgr contactInfosForUserWithUIDorEmail: email];
if (contactInfos)
{
username = [contactInfos objectForKey: @"sAMAccountName"];
username = [contactInfos objectForKey: @"c_uid"];
recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (samCtx, username);
}
@@ -1614,8 +1517,6 @@ _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];
@@ -1665,7 +1566,11 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if (!headerSetup)
[self _fetchHeaderData];
bodyPartKey = mimeKey;
if ([mimeKey hasPrefix: @"body.peek"])
bodyPartKey = [NSString stringWithFormat: @"body[%@]",
[mimeKey _strippedBodyKey]];
else
bodyPartKey = mimeKey;
return bodyPartKey;
}
@@ -1679,21 +1584,6 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
bodySetup = YES;
}
- (MAPIStoreSharingMessage *) _sharingObject
{
/* Get the sharing object if available */
NSUInteger i, max;
id proxy;
max = [proxies count];
for (i = 0; i < max; i++) {
proxy = [proxies objectAtIndex: i];
if ([proxy isKindOfClass: MAPIStoreSharingMessageK])
return proxy;
}
return nil;
}
- (void) save: (TALLOC_CTX *) memCtx
{
NSNumber *value;
@@ -1707,11 +1597,6 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
else /* 0: unflagged, 1: follow up complete */
[sogoObject removeFlags: @"\\Flagged"];
}
if (mailIsSharingObject)
[[self _sharingObject] saveWithMessage: self
andSOGoObject: sogoObject];
}
@end
+27 -215
View File
@@ -28,10 +28,9 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSScanner.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <Foundation/NSValue.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NGHashMap.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+Encoding.h>
@@ -44,7 +43,6 @@
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSCalendarDate+SOGo.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoCacheObject.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoMailer.h>
#import <SOGo/SOGoUser.h>
@@ -52,7 +50,6 @@
#import <Mailer/SOGoMailFolder.h>
#import <Mailer/NSString+Mail.h>
#import "Codepages.h"
#import "MAPIStoreAttachment.h"
#import "MAPIStoreAttachmentTable.h"
#import "MAPIStoreContext.h"
@@ -65,13 +62,13 @@
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import <SOGo/SOGoCacheObject.h>
#import "MAPIStoreMailVolatileMessage.h"
#undef DEBUG
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
#include <mapistore/mapistore_nameid.h>
static Class NSNumberK = Nil;
@@ -386,7 +383,7 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
contactInfos = [mgr contactInfosForUserWithUIDorEmail: email];
if (contactInfos)
{
username = [contactInfos objectForKey: @"sAMAccountName"];
username = [contactInfos objectForKey: @"c_uid"];
recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (samCtx, username);
}
@@ -534,112 +531,13 @@ QuoteSpecials (NSString *address)
return result;
}
static inline void
FillMessageHeadersFromSharingProperties (NGMutableHashMap *headers, NSDictionary *mailProperties)
{
/* Store the *important* properties related with a sharing object as
MIME eXtension headers. See [MS-OXSHARE] Section 2.2 for details
about the properties */
id value;
NSNumber *sharingFlavourNum = nil;
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingCapabilities)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-Capabilities"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingFlavor)];
if (value)
sharingFlavourNum = (NSNumber *)value;
else
{
value = [mailProperties objectForKey: MAPIPropertyKey (PidNameXSharingFlavor)];
if (value)
{
/* Transform the hex string to unsigned int */
NSScanner *scanner;
unsigned int sharingFlavour;
scanner = [NSScanner scannerWithString:value];
if ([scanner scanHexInt:&sharingFlavour])
sharingFlavourNum =[NSNumber numberWithUnsignedInt: sharingFlavour];
}
}
if (sharingFlavourNum)
{
if ([sharingFlavourNum unsignedIntegerValue] == 0x5100)
{
/* 0x5100 sharing flavour is not in standard but it seems to
be a denial of request + invitation message so we store
deny sharing flavour */
sharingFlavourNum = [NSNumber numberWithUnsignedInt: SHARING_DENY_REQUEST];
}
[headers setObject: sharingFlavourNum
forKey: @"X-MS-Sharing-Flavor"];
}
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorEntryId)];
if (value)
[headers setObject: [[value stringByEncodingBase64] stringByReplacingOccurrencesOfString: @"\n"
withString: @""]
forKey: @"X-MS-Sharing-InitiatorEntryId"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorName)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-InitiatorName"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorSmtp)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-InitiatorSmtp"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingLocalType)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-LocalType"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingProviderName)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-ProviderName"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingRemoteName)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-RemoteName"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingRemoteStoreUid)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-RemoteStoreUid"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingRemoteUid)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-RemoteUid"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingResponseTime)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-ResponseTime"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingResponseType)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-ResponseType"];
}
static inline void
FillMessageHeadersFromProperties (NGMutableHashMap *headers,
NSDictionary *mailProperties, BOOL withBcc,
struct mapistore_connection_info *connInfo)
{
BOOL fromResolved = NO;
NSData *senderEntryId;
NSMutableString *subject;
NSString *from, *recId, *messageId, *subjectData, *recipientsStr, *msgClass;
NSString *from, *recId, *messageId, *subjectData;
NSArray *list;
NSCalendarDate *date;
NSDictionary *recipients;
@@ -673,96 +571,10 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
list = MakeRecipientsList ([recipients objectForKey: @"orig"]);
if ([list count])
{
[headers setObjects: list forKey: @"from"];
fromResolved = YES;
}
}
if (!fromResolved)
{
NSLog (@"Message without an orig from, try to guess it from PidTagSenderEntryId");
senderEntryId = [mailProperties objectForKey: MAPIPropertyKey (PR_SENDER_ENTRYID)];
if (senderEntryId)
{
struct Binary_r bin32;
struct AddressBookEntryId *addrBookEntryId;
NSString *username;
NSMutableDictionary *fromRecipient;
fromRecipient = [NSMutableDictionary dictionaryWithCapacity: 2];
bin32.cb = [senderEntryId length];
bin32.lpb = (uint8_t *) [senderEntryId bytes];
addrBookEntryId = get_AddressBookEntryId (connInfo->sam_ctx, &bin32);
if (addrBookEntryId && [[NSString stringWithGUID: &addrBookEntryId->ProviderUID]
hasSuffix: @"08002b2fe182"])
{
/* TODO: better way to distinguish local and other ones */
username = MAPIStoreSamDBUserAttribute (connInfo->sam_ctx, @"legacyExchangeDN",
[NSString stringWithUTF8String: addrBookEntryId->X500DN], @"sAMAccountName");
if (username)
{
SOGoUser *fromUser;
fromUser = [SOGoUser userWithLogin: [username lowercaseString]];
[fromRecipient setObject: [fromUser cn] forKey: @"fullName"];
[fromRecipient setObject: [[fromUser allEmails] objectAtIndex: 0]
forKey: @"email"];
}
else
[fromRecipient setObject: [NSString stringWithUTF8String: addrBookEntryId->X500DN]
forKey: @"email"];
}
else
{
/* Try with One-Off EntryId */
struct OneOffEntryId *oneOffEntryId;
oneOffEntryId = get_OneOffEntryId (connInfo->sam_ctx, &bin32);
if (oneOffEntryId && [[NSString stringWithGUID: &oneOffEntryId->ProviderUID]
hasSuffix: @"00dd010f5402"])
{
[fromRecipient setObject: [NSString stringWithUTF8String: oneOffEntryId->DisplayName.lpszW]
forKey: @"fullName"];
[fromRecipient setObject: [NSString stringWithUTF8String: oneOffEntryId->EmailAddress.lpszW]
forKey: @"email"];
}
talloc_free (oneOffEntryId);
}
talloc_free (addrBookEntryId);
if ([[fromRecipient allKeys] count] > 0)
{
list = MakeRecipientsList ([NSArray arrayWithObjects: fromRecipient, nil]);
if ([list count])
[headers setObjects: list forKey: @"from"];
}
}
}
if (!recipients)
{
NSLog (@"Message without recipients."
@"Guessing recipients from PidTagOriginalDisplayTo and PidTagOriginalCc");
recipientsStr = [mailProperties objectForKey: MAPIPropertyKey (PidTagOriginalDisplayTo)];
if (recipientsStr)
{
list = [recipientsStr componentsSeparatedByString:@", "];
if ([list count])
[headers setObjects: list forKey: @"to"];
}
recipientsStr = [mailProperties objectForKey: MAPIPropertyKey (PidTagOriginalDisplayCc)];
if (recipientsStr)
{
list = [recipientsStr componentsSeparatedByString:@", "];
if ([list count])
[headers setObjects: list forKey: @"cc"];
}
[headers setObjects: list forKey: @"from"];
}
else
NSLog (@"message without recipients");
subject = [NSMutableString stringWithCapacity: 128];
subjectData = [mailProperties objectForKey: MAPIPropertyKey (PR_SUBJECT_PREFIX_UNICODE)];
@@ -771,12 +583,6 @@ 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)];
@@ -786,6 +592,8 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
date = [mailProperties objectForKey: MAPIPropertyKey (PR_CLIENT_SUBMIT_TIME)];
if (date)
{
date = [date addYear: 0 month: 0 day: 0
hour: 0 minute: 0 second: [[date timeZone] secondsFromGMT]];
[headers addObject: [date rfc822DateString] forKey: @"date"];
}
[headers addObject: @"1.0" forKey: @"MIME-Version"];
@@ -804,13 +612,6 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
{
[headers addObject: @"5 (Lowest)" forKey: @"X-Priority"];
}
msgClass = [mailProperties objectForKey: MAPIPropertyKey (PidTagMessageClass)];
if ([msgClass isEqualToString: @"IPM.Sharing"])
{
FillMessageHeadersFromSharingProperties (headers, mailProperties);
}
}
static NSArray *
@@ -871,9 +672,21 @@ MakeTextHtmlBody (NSDictionary *mailProperties, NSDictionary *attachmentParts,
{
/* charset */
codePage = [mailProperties objectForKey: MAPIPropertyKey (PR_INTERNET_CPID)];
charset = [Codepages getNameFromCodepage: codePage];
if (!charset)
charset = @"utf-8";
switch ([codePage intValue])
{
case 20127:
charset = @"us-ascii";
break;
case 28605:
charset = @"iso-8859-15";
break;
case 65001:
charset = @"utf-8";
break;
case 28591:
default:
charset = @"iso-8859-1";
}
htmlContentType = [NSString stringWithFormat: @"text/html; charset=%@",
charset];
@@ -1021,7 +834,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
messageBody = MakeMessageBody (properties, attachmentParts, &contentType);
if (messageBody)
{
[message setHeader: contentType forKey: @"content-type"];
[headers setObject: contentType forKey: @"content-type"];
[message setBody: messageBody];
}
@@ -1060,12 +873,12 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
id <SOGoAuthenticator> authenticator;
msgClass = [properties objectForKey: MAPIPropertyKey (PidTagMessageClass)];
if ([msgClass isEqualToString: @"IPM.Note"] || [msgClass isEqualToString: @"IPM.Sharing"]) /* we skip invitation replies */
if ([msgClass isEqualToString: @"IPM.Note"]) /* we skip invitation replies */
{
/* send mail */
messageData = [self _generateMailDataWithBcc: NO];
recipientEmails = [NSMutableArray arrayWithCapacity: 32];
recipients = [properties objectForKey: @"recipients"];
for (type = MAPI_ORIG; type <= MAPI_BCC; type++)
@@ -1083,7 +896,6 @@ 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]
-6
View File
@@ -49,19 +49,13 @@
- (NSString *) urlFromID: (uint64_t) idKey;
- (uint64_t) idFromURL: (NSString *) url;
- (uint64_t) idFromURL: (NSString *) url
isSoftDeleted: (bool *) softDeleted;
- (BOOL) registerURL: (NSString *) urlString
withID: (uint64_t) idNbr;
- (void) registerURLs: (NSArray *) urlString
withIDs: (NSArray *) idNbrs;
- (void) unregisterURLWithID: (uint64_t) idNbr;
- (void) unregisterURLWithID: (uint64_t) idNbr
andFlags: (uint8_t) flags;
- (void) updateID: (uint64_t) idNbr
withURL: (NSString *) urlString;
- (BOOL) updateURL: (NSString *) urlString
withID: (uint64_t) idNbr;
@end
+8 -57
View File
@@ -114,9 +114,6 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
{
ASSIGN (username, newUsername);
indexing = newIndexing;
/* Workaround so all indexing context are valid and won't be freed. */
// TODO refactor indexing interface
talloc_reference(memCtx, indexing);
}
return self;
@@ -160,21 +157,6 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
return NSNotFound;
}
- (uint64_t) idFromURL: (NSString *) url
isSoftDeleted: (bool *) softDeleted
{
enum mapistore_error ret;
uint64_t idNbr;
ret = indexing->get_fmid(indexing, [username UTF8String], [url UTF8String],
false, &idNbr, softDeleted);
if (ret != MAPISTORE_SUCCESS)
return NSNotFound;
return idNbr;
}
- (void) _updateFolderWithURL: (NSString *) oldURL
withURL: (NSString *) urlString
{
@@ -227,32 +209,12 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
}
}
- (BOOL) updateURL: (NSString *) urlString
withID: (uint64_t) idNbr
{
BOOL rc = NO;
uint64_t oldIDNbr;
oldIDNbr = [self idFromURL: urlString];
if (oldIDNbr)
{
[self logWithFormat: @"Updating URL: %@ with id %.16"PRIx64" from old id %.16"PRIx64,
urlString, idNbr, oldIDNbr];
[self unregisterURLWithID: oldIDNbr];
[self registerURL: urlString
withID: idNbr];
rc = YES;
}
return rc;
}
- (BOOL) registerURL: (NSString *) urlString
withID: (uint64_t) idNbr
{
NSString *oldURL;
uint64_t oldIdNbr;
bool softDeleted;
bool rc;
oldURL = [self urlFromID: idNbr];
if (oldURL != NULL)
@@ -263,20 +225,18 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
return NO;
}
oldIdNbr = [self idFromURL: urlString isSoftDeleted: &softDeleted];
oldIdNbr = [self idFromURL: urlString];
if (oldIdNbr != NSNotFound)
{
if (softDeleted)
[self logWithFormat: @"Attempt to register a soft-deleted %@", urlString];
else
[self errorWithFormat:
@"attempt to double register an entry with idNbr ('%@', %lld,"
@" 0x%.16"PRIx64", oldid=0x%.16"PRIx64")",
urlString, idNbr, idNbr, oldIdNbr];
[self errorWithFormat:
@"attempt to double register an entry with idNbr ('%@', %lld,"
@" 0x%.16"PRIx64", oldid=0x%.16"PRIx64")",
urlString, idNbr, idNbr, oldIdNbr];
return NO;
}
else
{
rc = YES;
// [self logWithFormat: @"registered url '%@' with id %lld (0x%.16"PRIx64")",
// urlString, idNbr, idNbr];
@@ -285,7 +245,7 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
idNbr, [urlString UTF8String]);
}
return YES;
return rc;
}
- (void) registerURLs: (NSArray *) urlStrings
@@ -315,13 +275,4 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
idNbr, MAPISTORE_PERMANENT_DELETE);
}
- (void) unregisterURLWithID: (uint64_t) idNbr
andFlags: (uint8_t) flags
{
indexing->del_fmid(indexing, [username UTF8String],
idNbr,
(flags == MAPISTORE_SOFT_DELETE) ? MAPISTORE_SOFT_DELETE : MAPISTORE_PERMANENT_DELETE);
}
@end
+72 -77
View File
@@ -178,101 +178,56 @@ 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)
recipientFullName = value;
[recipientProperties setObject: value forKey: @"fullName"];
value = [[recipientUser allEmails] objectAtIndex: 0];
if ([value length] > 0)
recipientEmail = value;
}
[recipientProperties setObject: value forKey: @"email"];
}
}
/* If we do not have values from the user object we try to get them from the parameters */
if (!recipientFullName && displayName)
else
{
value = [NSString stringWithUTF8String: displayName];
if ([value length] > 0)
recipientFullName = value;
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"];
}
}
if (!recipientEmail && email)
for (count = 0; count < columns->cValues; count++)
{
value = [NSString stringWithUTF8String: email];
if ([value length] > 0)
recipientEmail = value;
if (recipient->data[count])
{
value = NSObjectFromValuePointer (columns->aulPropTag[count],
recipient->data[count]);
if (value)
[recipientProperties setObject: value
forKey: MAPIPropertyKey (columns->aulPropTag[count])];
}
}
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;
}
@@ -510,15 +465,16 @@ rtf2html (NSData *compressedRTF)
enum mapistore_error rc;
NSArray *containerTables;
NSUInteger count, max;
struct mapistore_object_notification_parameters *notif_parameters;
uint64_t folderId;
struct mapistore_context *mstoreCtx;
MAPIStoreContext *context;
SOGoUser *ownerUser;
BOOL userIsOwner;
MAPIStoreMessage *mainMessage;
//[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
containerTables = nil;
max = 0;
context = [self context];
ownerUser = [[self userContext] sogoUser];
userIsOwner = [[context activeUser] isEqual: ownerUser];
@@ -540,6 +496,47 @@ rtf2html (NSData *compressedRTF)
/* notifications */
if ([container isKindOfClass: MAPIStoreFolderK])
{
folderId = [(MAPIStoreFolder *) container objectId];
mstoreCtx = [[self context] connectionInfo]->mstore_ctx;
/* folder modified */
notif_parameters
= talloc_zero(memCtx, struct mapistore_object_notification_parameters);
notif_parameters->object_id = folderId;
if (isNew)
{
notif_parameters->tag_count = 3;
notif_parameters->tags = talloc_array (notif_parameters,
enum MAPITAGS, 3);
notif_parameters->tags[0] = PR_CONTENT_COUNT;
notif_parameters->tags[1] = PR_MESSAGE_SIZE;
notif_parameters->tags[2] = PR_NORMAL_MESSAGE_SIZE;
notif_parameters->new_message_count = true;
notif_parameters->message_count
= [[(MAPIStoreFolder *) container messageKeys] count] + 1;
}
mapistore_push_notification (mstoreCtx,
MAPISTORE_FOLDER,
MAPISTORE_OBJECT_MODIFIED,
notif_parameters);
talloc_free (notif_parameters);
/* message created */
if (isNew)
{
notif_parameters
= talloc_zero(memCtx,
struct mapistore_object_notification_parameters);
notif_parameters->object_id = [self objectId];
notif_parameters->folder_id = folderId;
notif_parameters->tag_count = 0xffff;
mapistore_push_notification (mstoreCtx,
MAPISTORE_MESSAGE, MAPISTORE_OBJECT_CREATED,
notif_parameters);
talloc_free (notif_parameters);
}
/* we ensure the table caches are loaded so that old and new state
can be compared */
containerTables = [self activeContainerMessageTables];
@@ -785,7 +782,7 @@ rtf2html (NSData *compressedRTF)
return [self getLongZero: data inMemCtx: memCtx];
}
- (int) getPidTagSensitivity: (void **) data
- (int) getPidTagSensitivity: (void **) data // TODO -> subclass in calendar
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getLongZero: data inMemCtx: memCtx];
@@ -798,7 +795,7 @@ rtf2html (NSData *compressedRTF)
TALLOC_CTX *localMemCtx;
char *prefix, *normalizedSubject;
localMemCtx = talloc_zero (memCtx, TALLOC_CTX);
localMemCtx = talloc_zero (NULL, TALLOC_CTX);
if ([self getProperty: (void **) &prefix
withTag: PidTagSubjectPrefix
inMemCtx: localMemCtx]
@@ -810,8 +807,6 @@ rtf2html (NSData *compressedRTF)
if (rc == MAPISTORE_SUCCESS)
*data = talloc_asprintf (memCtx, "%s%s", prefix, normalizedSubject);
talloc_free(localMemCtx);
return rc;
}
+51
View File
@@ -87,7 +87,58 @@
- (void) notifyChangesForChild: (MAPIStoreMessage *) child
{
NSUInteger currentChildRow, newChildRow;
NSArray *list;
NSString *childName;
struct mapistore_table_notification_parameters notif_parameters;
struct mapistore_context *mstoreCtx;
mstoreCtx = [[(MAPIStoreFolder *) container context]
connectionInfo]->mstore_ctx;
notif_parameters.table_type = tableType;
notif_parameters.handle = handleId;
notif_parameters.folder_id = [(MAPIStoreFolder *) container objectId];
notif_parameters.object_id = [child objectId];
notif_parameters.instance_id = 0; /* TODO: always 0 ? */
childName = [child nameInContainer];
list = [self restrictedChildKeys];
currentChildRow = [list indexOfObject: childName];
notif_parameters.row_id = currentChildRow;
[self cleanupCaches];
list = [self restrictedChildKeys];
newChildRow = [list indexOfObject: childName];
if (currentChildRow == NSNotFound)
{
if (newChildRow != NSNotFound)
{
notif_parameters.row_id = newChildRow;
mapistore_push_notification (mstoreCtx,
MAPISTORE_TABLE,
MAPISTORE_OBJECT_CREATED,
&notif_parameters);
}
}
else
{
if (newChildRow == NSNotFound)
mapistore_push_notification (mstoreCtx,
MAPISTORE_TABLE,
MAPISTORE_OBJECT_DELETED,
&notif_parameters);
else
{
/* the fact that the row order has changed has no impact here */
notif_parameters.row_id = newChildRow;
mapistore_push_notification (mstoreCtx,
MAPISTORE_TABLE,
MAPISTORE_OBJECT_MODIFIED,
&notif_parameters);
}
}
}
@end
+1 -2
View File
@@ -45,8 +45,7 @@
context = talloc_zero(memCtx, struct mapistore_contexts_list);
context->url = talloc_asprintf (context, "sogo://%s@notes/",
[[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"] UTF8String]);
[userName UTF8String]);
// context->name = "Notes personnelles";
context->main_folder = true;
context->role = MAPISTORE_NOTES_ROLE;
+15 -3
View File
@@ -23,6 +23,7 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSObject+Logs.h>
#import <SOGo/SOGoObject.h>
#import <SOGo/SOGoUser.h>
@@ -244,16 +245,17 @@ static Class NSExceptionK, MAPIStoreFolderK;
struct SPropValue *cValue;
NSUInteger counter;
NSMutableDictionary *newProperties;
NSTimeZone *tz;
NSInteger tzOffset;
id value;
tz = nil;
newProperties = [NSMutableDictionary dictionaryWithCapacity: aRow->cValues];
for (counter = 0; counter < aRow->cValues; counter++)
{
cValue = aRow->lpProps + counter;
value = NSObjectFromSPropValue (cValue);
if (value == nil)
continue;
switch (cValue->ulPropTag & 0xffff)
{
case PT_STRING8:
@@ -262,6 +264,16 @@ static Class NSExceptionK, MAPIStoreFolderK;
@"attempting to set string property as PR_STRING8: %.8x",
cValue->ulPropTag];
break;
case PT_SYSTIME:
if (!tz)
{
tz = [[self userContext] timeZone];
tzOffset = -[tz secondsFromGMT];
}
value = [value addYear: 0 month: 0 day: 0
hour: 0 minute: 0 second: tzOffset];
[value setTimeZone: tz];
break;
}
[newProperties setObject: value
forKey: MAPIPropertyKey (cValue->ulPropTag)];
+1 -6
View File
@@ -25,8 +25,6 @@
#include <talloc.h>
#import <Foundation/NSTimeZone.h>
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalRecurrenceRule.h>
@@ -43,10 +41,7 @@
@interface iCalCalendar (MAPIStoreRecurrence)
- (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity
fromRecurrencePattern: (struct RecurrencePattern *) rp
withExceptions: (struct ExceptionInfo *) exInfos
andExceptionCount: (uint16_t) exInfoCount
inTimeZone: (NSTimeZone *) tz;
fromRecurrencePattern: (struct RecurrencePattern *) rp;
@end
+29 -52
View File
@@ -24,7 +24,6 @@
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSSet.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NSObject+Logs.h>
@@ -49,10 +48,6 @@
- (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity
fromRecurrencePattern: (struct RecurrencePattern *) rp
withExceptions: (struct ExceptionInfo *) exInfos
andExceptionCount: (uint16_t) exInfoCount
inTimeZone: (NSTimeZone *) tz
{
NSCalendarDate *startDate, *olEndDate, *untilDate, *exDate;
NSString *monthDay, *month;
@@ -219,42 +214,34 @@
/* exception dates:
- take all deleted instances
- remove all modified instances available in ExceptionInfo from the above set
- remove all modified instances from the above set
- add remaining instances, in chronological order
*/
exceptionDates = [NSMutableSet set];
for (count = 0; count < rp->DeletedInstanceCount; count++)
{
exDate
= [NSDate dateFromMinutesSince1601: rp->DeletedInstanceDates[count]];
exDate = [exDate hour: [startDate hourOfDay]
minute: [startDate minuteOfHour]
second: [startDate secondOfMinute]];
[exceptionDates addObject: exDate];
}
for (count = 0; count < rp->ModifiedInstanceCount; count++)
{
exDate
= [NSDate dateFromMinutesSince1601: rp->ModifiedInstanceDates[count]];
exDate = [exDate hour: [startDate hourOfDay]
minute: [startDate minuteOfHour]
second: [startDate secondOfMinute]];
[exceptionDates removeObject: exDate];
}
/* Heuristic to avoid these loops */
if (rp->DeletedInstanceCount != rp->ModifiedInstanceCount) {
exceptionDates = [NSMutableSet set];
for (count = 0; count < rp->DeletedInstanceCount; count++)
{
exDate
= [NSDate dateFromMinutesSince1601: rp->DeletedInstanceDates[count]];
exDate = [exDate hour: [startDate hourOfDay]
minute: [startDate minuteOfHour]
second: [startDate secondOfMinute]];
[exceptionDates addObject: exDate];
}
/* Read the exceptions to remove the instances that are modified and not deleted */
if (exInfos && exInfoCount > 0)
{
for (count = 0; count < exInfoCount; count++)
{
/* The OriginalStartDate is in local time */
exDate = [NSDate dateFromMinutesSince1601: exInfos[count].OriginalStartDate];
exDate = [exDate dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: - [tz secondsFromGMT]];
[exceptionDates removeObject: exDate];
}
}
realExDates = [[exceptionDates allObjects]
sortedArrayUsingSelector: @selector (compare:)];
max = [realExDates count];
for (count = 0; count < max; count++)
[entity addToExceptionDates: [realExDates objectAtIndex: count]];
}
realExDates = [[exceptionDates allObjects]
sortedArrayUsingSelector: @selector (compare:)];
max = [realExDates count];
for (count = 0; count < max; count++)
[entity addToExceptionDates: [realExDates objectAtIndex: count]];
}
@end
@@ -325,25 +312,15 @@
rp->RecurFrequency = RecurFrequency_Weekly;
rp->PatternType = PatternType_Week;
rp->Period = repeatInterval;
dayOfWeek = [startDate dayOfWeek];
mask = 0;
byDayMask = [self byDayMask];
if (byDayMask)
{
for (count = 0; count < 7; count++)
if ([byDayMask occursOnDay: count])
mask |= 1 << count;
}
else
{
/* Set the recurrence pattern using start date */
mask |= 1 << dayOfWeek;
}
for (count = 0; count < 7; count++)
if ([byDayMask occursOnDay: count])
mask |= 1 << count;
rp->PatternTypeSpecific.WeekRecurrencePattern = mask;
/* FirstDateTime */
dayOfWeek = [startDate dayOfWeek];
if (dayOfWeek)
beginOfWeek = [startDate dateByAddingYears: 0 months: 0
days: -dayOfWeek
+106 -44
View File
@@ -47,7 +47,6 @@
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
#include <libmapi/libmapi.h>
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
#include <execinfo.h>
@@ -59,27 +58,22 @@ static BOOL initialization_done = NO;
#define NS_CURRENT_THREAD_REGISTER() \
BOOL __nsrct_thread_registered = GSRegisterCurrentThread(); \
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] --->");
DEBUG(5, ("[SOGo: %s:%d] You should call sogo_backend_init() first. Current thread: %p, pid: %d\n", \
__FUNCTION__, __LINE__, GSCurrentThread(), getpid())); \
}
#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
@@ -150,7 +144,7 @@ sogo_backend_init (void)
GSRegisterCurrentThread();
if (initialization_done) {
OC_DEBUG(5, "[SOGo] SOGo backend already initialized.\n");
DEBUG(0, ("SOGo backend already initialized.\n"));
return MAPISTORE_SUCCESS;
}
@@ -195,34 +189,18 @@ sogo_backend_init (void)
[pool release];
OC_DEBUG(5, "[SOGo] backend init SUCCESS. Current thread: %p, pid: %d\n", GSCurrentThread(), getpid());
DEBUG(0, ("[SOGo: %s:%d] backend init SUCCESS. Current thread: %p, pid: %d\n", __FUNCTION__, __LINE__, GSCurrentThread(), getpid()));
initialization_done = YES;
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
@@ -235,6 +213,8 @@ sogo_backend_create_context(TALLOC_CTX *mem_ctx,
MAPIStoreContext *context;
int rc;
DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
NS_CURRENT_THREAD_REGISTER();
pool = [NSAutoreleasePool new];
@@ -270,6 +250,8 @@ sogo_backend_create_root_folder (const char *username,
NSString *mapistoreUri;
int rc;
DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
NS_CURRENT_THREAD_REGISTER();
pool = [NSAutoreleasePool new];
@@ -305,6 +287,8 @@ sogo_backend_list_contexts(const char *username, struct indexing_context *indexi
NSString *userName;
int rc;
DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
NS_CURRENT_THREAD_REGISTER();
pool = [NSAutoreleasePool new];
@@ -351,6 +335,8 @@ sogo_context_get_path(void *backend_object, TALLOC_CTX *mem_ctx,
MAPIStoreContext *context;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (backend_object)
{
wrapper = backend_object;
@@ -383,6 +369,8 @@ sogo_context_get_root_folder(void *backend_object, TALLOC_CTX *mem_ctx,
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (backend_object)
{
wrapper = backend_object;
@@ -424,6 +412,8 @@ sogo_folder_open_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid,
MAPIStoreFolder *folder, *childFolder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -451,7 +441,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
@@ -466,6 +456,8 @@ sogo_folder_create_folder(void *folder_object, TALLOC_CTX *mem_ctx,
MAPIStoreFolder *folder, *childFolder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -507,6 +499,8 @@ sogo_folder_delete(void *folder_object)
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -537,6 +531,8 @@ sogo_folder_get_child_count(void *folder_object, enum mapistore_table_type table
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -571,6 +567,8 @@ sogo_folder_open_message(void *folder_object,
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -611,6 +609,8 @@ sogo_folder_create_message(void *folder_object,
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -621,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)
@@ -645,6 +645,8 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags)
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -681,6 +683,8 @@ sogo_folder_move_copy_messages(void *folder_object,
struct MAPIStoreTallocWrapper *wrapper;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -723,6 +727,8 @@ sogo_folder_move_folder(void *folder_object, void *target_folder_object,
struct MAPIStoreTallocWrapper *wrapper;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -771,6 +777,8 @@ sogo_folder_copy_folder(void *folder_object, void *target_folder_object, TALLOC_
struct MAPIStoreTallocWrapper *wrapper;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -813,6 +821,8 @@ sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx,
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -850,6 +860,8 @@ sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx,
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -887,6 +899,8 @@ sogo_folder_modify_permissions(void *folder_object, uint8_t flags,
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -919,6 +933,8 @@ sogo_folder_preload_message_bodies(void *folder_object, enum mapistore_table_typ
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (folder_object)
{
wrapper = folder_object;
@@ -952,6 +968,8 @@ sogo_message_get_message_data(void *message_object,
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (message_object)
{
wrapper = message_object;
@@ -985,6 +1003,8 @@ sogo_message_create_attachment (void *message_object, TALLOC_CTX *mem_ctx, void
MAPIStoreAttachment *attachment;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (message_object)
{
wrapper = message_object;
@@ -996,6 +1016,7 @@ 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];
@@ -1019,6 +1040,8 @@ sogo_message_open_attachment (void *message_object, TALLOC_CTX *mem_ctx,
MAPIStoreAttachment *attachment;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (message_object)
{
wrapper = message_object;
@@ -1030,6 +1053,7 @@ 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];
@@ -1052,6 +1076,8 @@ sogo_message_get_attachment_table (void *message_object, TALLOC_CTX *mem_ctx, vo
MAPIStoreAttachmentTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (message_object)
{
wrapper = message_object;
@@ -1064,6 +1090,7 @@ 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];
@@ -1088,6 +1115,8 @@ sogo_message_modify_recipients (void *message_object,
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (message_object)
{
wrapper = message_object;
@@ -1099,6 +1128,7 @@ sogo_message_modify_recipients (void *message_object,
rc = [message modifyRecipientsWithRecipients: recipients
andCount: count
andColumns: columns];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
@@ -1120,6 +1150,8 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (message_object)
{
wrapper = message_object;
@@ -1129,6 +1161,7 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
TRYCATCH_START
rc = [message setReadFlag: flag];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
@@ -1150,6 +1183,8 @@ sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx)
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (message_object)
{
wrapper = message_object;
@@ -1159,6 +1194,7 @@ sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx)
TRYCATCH_START
rc = [message saveMessage: mem_ctx];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
@@ -1180,6 +1216,8 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags)
MAPIStoreMailVolatileMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (message_object)
{
wrapper = message_object;
@@ -1189,6 +1227,7 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags)
TRYCATCH_START
rc = [message submitWithFlags: flags];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
@@ -1215,6 +1254,8 @@ sogo_message_attachment_open_embedded_message (void *attachment_object,
MAPIStoreEmbeddedMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (attachment_object)
{
wrapper = attachment_object;
@@ -1254,6 +1295,8 @@ sogo_message_attachment_create_embedded_message (void *attachment_object,
MAPIStoreEmbeddedMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (attachment_object)
{
wrapper = attachment_object;
@@ -1288,6 +1331,8 @@ static enum mapistore_error sogo_table_get_available_properties(void *table_obje
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (table_object)
{
wrapper = table_object;
@@ -1318,6 +1363,8 @@ sogo_table_set_columns (void *table_object, uint16_t count, enum MAPITAGS *prope
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (table_object)
{
wrapper = table_object;
@@ -1349,6 +1396,8 @@ sogo_table_set_restrictions (void *table_object, struct mapi_SRestriction *restr
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (table_object)
{
wrapper = table_object;
@@ -1382,6 +1431,8 @@ sogo_table_set_sort_order (void *table_object, struct SSortOrderSet *sort_order,
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (table_object)
{
wrapper = table_object;
@@ -1417,6 +1468,8 @@ sogo_table_get_row (void *table_object, TALLOC_CTX *mem_ctx,
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (table_object)
{
wrapper = table_object;
@@ -1450,6 +1503,8 @@ sogo_table_get_row_count (void *table_object,
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (table_object)
{
wrapper = table_object;
@@ -1481,6 +1536,8 @@ sogo_table_handle_destructor (void *table_object, uint32_t handle_id)
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (table_object)
{
wrapper = table_object;
@@ -1513,6 +1570,8 @@ static enum mapistore_error sogo_properties_get_available_properties(void *objec
MAPIStoreObject *propObject;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (object)
{
wrapper = object;
@@ -1546,6 +1605,8 @@ sogo_properties_get_properties (void *object,
MAPIStoreObject *propObject;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (object)
{
wrapper = object;
@@ -1578,6 +1639,8 @@ sogo_properties_set_properties (void *object, struct SRow *aRow)
MAPIStoreObject *propObject;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (object)
{
wrapper = object;
@@ -1601,16 +1664,18 @@ 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;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (uri == NULL) return MAPISTORE_ERR_INVALID_PARAMETER;
/* This fixes a crash occurring during the instantiation of the
@@ -1628,10 +1693,7 @@ sogo_manager_generate_uri (TALLOC_CTX *mem_ctx,
username = [NSString stringWithUTF8String: (user ? user : "*")];
/* Do proper directory lookup here */
directory = [NSString stringWithUTF8String: (folder ? folder : "*")];
partialURLString = [NSString stringWithFormat: @"sogo://%@:*@%@",
[username stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
directory];
partialURLString = [NSString stringWithFormat: @"sogo://%@:*@%@", username, directory];
}
if (![partialURLString hasSuffix: @"/"])
partialURLString = [partialURLString stringByAppendingString: @"/"];
@@ -1656,9 +1718,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;
@@ -1714,7 +1776,7 @@ int mapistore_init_backend(void)
/* Register ourselves with the MAPISTORE subsystem */
ret = mapistore_backend_register (&backend);
if (ret != MAPISTORE_SUCCESS)
OC_DEBUG(0, "[SOGo] Failed to register the '%s' mapistore backend!\n", backend.backend.name);
DEBUG(0, ("Failed to register the '%s' mapistore backend!\n", backend.backend.name));
}
return ret;
+2 -5
View File
@@ -96,11 +96,8 @@ MAPIStoreInternalEntryId (struct ldb_context *samCtx, NSString *username)
[entryId appendUInt8: 0]; // end of string
}
else
{
NSLog (@"Error trying to generate EntryId for `%@`", username);
entryId = nil;
}
entryId = nil;
return entryId;
}
-101
View File
@@ -1,101 +0,0 @@
/* MAPIStoreSharingMessage.h - this file is part of SOGo-OpenChange
*
* Copyright (C) 2015 Enrique J. Hernández
*
* Author: Enrique J. Hernández <ejhernandez@zentyal.com>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef MAPISTORESHARINGMESSAGE_H
#define MAPISTORESHARINGMESSAGE_H
#import "MAPIStoreMailMessage.h"
#import "MAPIStoreObjectProxy.h"
#define SHARING_SPECIAL_FOLDER 0x40290
@interface MAPIStoreSharingMessage : MAPIStoreObjectProxy
{
struct mapistore_connection_info *connInfo;
NSMutableDictionary *properties;
}
- (id) initWithMailHeaders: (NSDictionary *) mailHeaders
andConnectionInfo: (struct mapistore_connection_info *) newConnInfo
fromMessage: (MAPIStoreMailMessage *) msg;
/* getters */
- (int) getPidLidSharingCapabilities: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingCapabilities: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingConfigurationUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingConfigUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingFlavor: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingFlavor: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingInitiatorEntryId: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingInitiatorName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingInitiatorSmtp: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingLocalType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingLocalType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingProviderGuid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingProviderGuid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingProviderName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingProviderName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingProviderUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingProviderUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingRemoteName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingRemoteName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingRemoteStoreUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingRemoteStoreUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingRemoteType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidTypeXSharingRemoteType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingResponseTime: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingResponseType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameContentClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
/* Save */
- (void) saveWithMessage: (MAPIStoreMailMessage *) msg
andSOGoObject: (SOGoMailObject *) sogoObject;
@end
#endif /* MAPISTORECALENDARWRAPPER_H */
-463
View File
@@ -1,463 +0,0 @@
/* MAPIStoreSharingMessage.m - this file is part of SOGo-OpenChange
*
* Copyright (C) 2015 Enrique J. Hernández
*
* Author: Enrique J. Hernández <ejhernandez@zentyal.com>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <talloc.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Mailer/SOGoMailObject.h>
#import <NGExtensions/NGBase64Coding.h>
#import "NSData+MAPIStore.h"
#import "NSDate+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import "NSValue+MAPIStore.h"
#import "MAPIStoreMailFolder.h"
#import "MAPIStoreSharingMessage.h"
#import "MAPIStoreTypes.h"
#include <gen_ndr/property.h>
#include <mapistore/mapistore_errors.h>
#include <mapistore/mapistore_nameid.h>
@implementation MAPIStoreSharingMessage
- (id) init
{
if ((self = [super init]))
{
connInfo = NULL;
properties = nil;
}
return self;
}
- (id) initWithMailHeaders: (NSDictionary *) mailHeaders
andConnectionInfo: (struct mapistore_connection_info *) newConnInfo
fromMessage: (MAPIStoreMailMessage *) msg
{
NSEnumerator *enumerator;
NSString *key;
if ((self = [self init]))
{
connInfo = newConnInfo;
enumerator = [mailHeaders keyEnumerator];
properties = [NSMutableDictionary new];
while ((key = [enumerator nextObject]))
{
if ([key hasPrefix: @"x-ms-sharing-"])
[properties setObject: [mailHeaders objectForKey: key]
forKey: key];
}
/* Set request properties from container folder */
NSDictionary *requestProps = [(MAPIStoreMailFolder *)[msg container]
extraPropertiesForMessage: [msg nameInContainer]];
if (requestProps)
[properties addEntriesFromDictionary: requestProps];
}
return self;
}
- (void) dealloc
{
[properties release];
[super dealloc];
}
- (enum mapistore_error) _getStringProperty: (NSString *) propertyName
inData: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: propertyName];
if (value)
{
*data = [value asUnicodeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidLidSharingCapabilities: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: @"x-ms-sharing-capabilities"];
if (value)
{
*data = MAPILongValue (memCtx, [value intValue]);
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidNameXSharingCapabilities: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: @"x-ms-sharing-capabilities"];
if (value)
{
*data = [[NSString stringWithFormat:@"%X", [value intValue]]
asUnicodeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidLidSharingConfigurationUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"" asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidNameXSharingConfigUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingConfigurationUrl: data inMemCtx: memCtx];
}
- (int) getPidLidSharingFlavor: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
/* See [MS-OXSHARE] Section 2.2.2.5 for details */
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value, auxValue;
value = [properties objectForKey: @"x-ms-sharing-flavor"];
if (value)
{
*data = MAPILongValue (memCtx, [value intValue]);
rc = MAPISTORE_SUCCESS;
}
else
{
/* Guess its value required by old clients based on other properties */
value = [properties objectForKey: @"x-ms-sharing-capabilities"];
if (value)
{
if ([value intValue] == SHARING_SPECIAL_FOLDER)
{
value = [properties objectForKey: @"x-ms-sharing-responsetime"];
auxValue = [properties objectForKey: @"x-ms-sharing-remoteuid"];
if (value) /* A sharing request */
{
if (auxValue)
*data = MAPILongValue (memCtx, SHARING_INVITATION_REQUEST_FOLDER);
else
*data = MAPILongValue (memCtx, SHARING_REQUEST_SPECIAL_FOLDER);
}
else
{
if (auxValue) /* It SHOULD be an invitation or response */
*data = MAPILongValue (memCtx, SHARING_INVITATION_SPECIAL_FOLDER);
else /* No remote info, then denial */
*data = MAPILongValue (memCtx, SHARING_DENY_REQUEST);
}
}
else
{
*data = MAPILongValue (memCtx, SHARING_INVITATION_FOLDER);
}
rc = MAPISTORE_SUCCESS;
}
}
return rc;
}
- (int) getPidNameXSharingFlavor: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: @"x-ms-sharing-flavor"];
if (value)
{
*data = [[NSString stringWithFormat:@"%X", [value intValue]]
asUnicodeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidLidSharingInitiatorEntryId: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
NSData *entryId;
value = [properties objectForKey: @"x-ms-sharing-initiatorentryid"];
if (value)
{
entryId = [value dataByDecodingBase64];
if (entryId)
{
*data = [entryId asBinaryInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
}
return rc;
}
- (int) getPidLidSharingInitiatorName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-initiatorname"
inData: data
inMemCtx: memCtx];
}
- (int) getPidLidSharingInitiatorSmtp: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-initiatorsmtp"
inData: data
inMemCtx: memCtx];
}
- (int) getPidLidSharingLocalType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-localtype"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingLocalType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingLocalType: data inMemCtx: memCtx];
}
- (int) getPidLidSharingProviderGuid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
const unsigned char providerGuidBytes[] = {0xAE, 0xF0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
NSData *providerGuid = [NSData dataWithBytes: providerGuidBytes length: 16];
*data = [providerGuid asBinaryInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidNameXSharingProviderGuid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"AEF0060000000000C000000000000046" asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidLidSharingProviderName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-providername"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingProviderName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingProviderName: data inMemCtx: memCtx];
}
- (int) getPidLidSharingProviderUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-providerurl"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingProviderUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingProviderUrl: data inMemCtx: memCtx];
}
- (int) getPidLidSharingRemoteName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-remotename"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingRemoteName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingRemoteName: data inMemCtx: memCtx];
}
- (int) getPidLidSharingRemoteStoreUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-remotestoreuid"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingRemoteStoreUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingRemoteStoreUid: data inMemCtx: memCtx];
}
- (int) getPidLidSharingRemoteType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-remotetype"
inData: data
inMemCtx: memCtx];
}
- (int) getPidTypeXSharingRemoteType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingRemoteType: data inMemCtx: memCtx];
}
- (int) getPidLidSharingRemoteUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-remoteuid"
inData: data
inMemCtx: memCtx];
}
- (int) getPidUidXSharingRemoteUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingRemoteUid: data inMemCtx: memCtx];
}
- (int) getPidLidSharingResponseTime: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: MAPIPropertyKey (PidLidSharingResponseTime)];
if (!value)
{
value = [properties objectForKey: @"x-ms-sharing-responsetime"];
if (value)
{
/* Here the value is a GSCBufferString */
NSString * responseTime = [NSString stringWithUTF8String: [value UTF8String]];
value = [NSDate dateWithString: responseTime];
}
}
if (value)
{
*data = [value asFileTimeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidLidSharingResponseType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: MAPIPropertyKey (PidLidSharingResponseType)];
if (!value)
value = [properties objectForKey: @"x-ms-sharing-responsetype"];
if (value)
{
*data = MAPILongValue (memCtx, [value intValue]);
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidNameContentClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = talloc_strdup (memCtx, "Sharing");
return MAPISTORE_SUCCESS;
}
- (void) saveWithMessage: (MAPIStoreMailMessage *) msg
andSOGoObject: (SOGoMailObject *) sogoObject
{
/* Store PidLidSharingResponseType and PidLidSharingResponseTime if
required in versions message from the container as I don't see
other straightforward place to put that information */
id response;
NSDictionary *propsToStore;
response = [[msg properties] objectForKey: MAPIPropertyKey (PidLidSharingResponseType)];
if (response)
{
/* FIXME: Is there any better way to increase the modseq? */
[sogoObject addFlags: @"\\Draft"];
[sogoObject removeFlags: @"\\Draft"];
/* Store this modification in container folder along the property values */
propsToStore = [NSDictionary dictionaryWithObjects:
[NSArray arrayWithObjects: response,
[[msg properties] objectForKey: MAPIPropertyKey (PidLidSharingResponseTime)],
nil]
forKeys:
[NSArray arrayWithObjects: MAPIPropertyKey (PidLidSharingResponseType),
MAPIPropertyKey (PidLidSharingResponseTime), nil]];
[(MAPIStoreMailFolder *)[msg container] setExtraProperties: propsToStore
forMessage: [msg nameInContainer]];
}
}
@end
+2 -4
View File
@@ -31,7 +31,6 @@
#import <Appointments/SOGoTaskObject.h>
#import "MAPIApplication.h"
#import "MAPIStoreUserContext.h"
#import "MAPIStoreTasksContext.h"
#import "MAPIStoreTasksMessage.h"
#import "MAPIStoreTasksMessageTable.h"
@@ -62,7 +61,6 @@
SOGoTaskObject *newEntry;
NSString *name;
[[[self context] userContext] activate];
name = [NSString stringWithFormat: @"%@.ics",
[SOGoObject globallyUniqueObjectId]];
newEntry = [SOGoTaskObject objectWithName: name
@@ -71,7 +69,7 @@
newMessage = [MAPIStoreTasksMessage mapiStoreObjectWithSOGoObject: newEntry
inContainer: self];
return newMessage;
}
@@ -118,7 +116,7 @@
rights |= RightsReadItems;
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
return rights;
}
+2 -20
View File
@@ -367,15 +367,13 @@
NSString *status, *priority, *tzName;
NSCalendarDate *now;
NSInteger tzOffset;
NSTimeZone *userTZ;
double doubleValue;
vToDo = [sogoObject component: YES secure: NO];
vCalendar = [vToDo parent];
[vCalendar setProdID: @"-//Inverse inc.//OpenChange+SOGo//EN"];
userTZ = [[self userContext] timeZone];
tzName = [userTZ name];
tzName = [[[self userContext] timeZone] name];
tz = [iCalTimeZone timeZoneForName: tzName];
[vCalendar addTimeZone: tz];
@@ -430,13 +428,6 @@
{
date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"dtstart"];
[date setTimeZone: tz];
/* The property is set to user's local time zone.
See: [MS-OXOTASK] 2.2.2.2.4
TODO: Ignore when the PT_SYSTIME is 0x5AE980E0*/
tzOffset = [userTZ secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];
[date setDateTime: value];
}
@@ -446,13 +437,6 @@
{
date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"due"];
[date setTimeZone: tz];
/* The property is set to user's local time zone.
See: [MS-OXOTASK] 2.2.2.2.5
TODO: Ignore when the PT_SYSTIME is 0x5AE980E0*/
tzOffset = [userTZ secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];
[date setDateTime: value];
}
@@ -461,9 +445,7 @@
if (value)
{
date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"completed"];
/* The property is set to midnight in local time zone converted to UTC:
See: [MS-OXOTASK] 2.2.2.2.9 */
tzOffset = [userTZ secondsFromGMTForDate: value];
tzOffset = [[value timeZone] secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];
-3
View File
@@ -157,9 +157,6 @@ static Class MAPIStoreTasksMessageK = Nil;
forKey: MAPIPropertyKey (PidLidTaskDueDate)];
[knownProperties setObject: @"c_creationdate"
forKey: MAPIPropertyKey (PidLidTaskOrdinal)];
/* Use by oxcfxics to sort the latest first */
[knownProperties setObject: @"c_lastmodified"
forKey: MAPIPropertyKey (PidTagMessageDeliveryTime)];
}
return [knownProperties objectForKey: MAPIPropertyKey (property)];
+4 -3
View File
@@ -119,7 +119,6 @@ NSObjectFromMAPISPropValue (const struct mapi_SPropValue *value)
break;
case PT_SYSTIME:
result = [NSCalendarDate dateFromFileTime: &(value->value.ft)];
[result setTimeZone: utcTZ];
break;
case PT_BINARY:
case PT_SVREID:
@@ -155,7 +154,8 @@ NSObjectFromMAPISPropValue (const struct mapi_SPropValue *value)
// #define PT_I8 0x14
// #define PT_SRESTRICT 0xFD
// #define PT_ACTIONS 0xFE
result = nil;
result = [NSNull null];
abort();
NSLog (@"%s: object type not handled: %d (0x%.4x)",
__PRETTY_FUNCTION__, valueType, valueType);
}
@@ -250,7 +250,8 @@ NSObjectFromSPropValue (const struct SPropValue *value)
// #define PT_I8 0x14
// #define PT_SRESTRICT 0xFD
// #define PT_ACTIONS 0xFE
result = nil;
result = [NSNull null];
abort();
NSLog (@"%s: object type not handled: %d (0x%.4x)",
__PRETTY_FUNCTION__, valueType, valueType);
}
-2
View File
@@ -86,8 +86,6 @@
/* SOGo hacky magic */
- (void) activateWithUser: (SOGoUser *) activeUser;
- (void) activate;
- (void) deactivate;
- (MAPIStoreAuthenticator *) authenticator;
- (WOContext *) woContext;
+10 -38
View File
@@ -39,7 +39,6 @@
#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>
@@ -159,8 +158,6 @@ static NSMapTable *contextsTable = nil;
if ([userPassword length] == 0)
userPassword = username;
[authenticator setPassword: userPassword];
// Activate the profile on initialization
[self activate];
}
return self;
@@ -217,7 +214,7 @@ static NSMapTable *contextsTable = nil;
if (!userFolder)
{
userFolder = [SOGoUserFolder objectWithName: username
inContainer: nil];
inContainer: MAPIApp];
[userFolder retain];
}
@@ -235,8 +232,7 @@ static NSMapTable *contextsTable = nil;
if (!rootFolders)
{
rootFolders = [NSMutableDictionary new];
[self activate];
[self userFolder]; // force lazy initialization
[self userFolder];
[woContext setClientObject: userFolder];
/* Calendar */
@@ -261,10 +257,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];
@@ -272,7 +268,8 @@ 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"];
}
@@ -314,9 +311,9 @@ static NSMapTable *contextsTable = nil;
parts in this url. We strip the '-' character in case we have
this in the domain part - like foo@bar-zot.com */
ocFSTableName = [NSString stringWithFormat: @"sogo_cache_folder_%@",
[[[user login] asCSSIdentifier]
stringByReplacingOccurrencesOfString: @"-"
withString: @"_"]];
[[[user loginInDomain] asCSSIdentifier]
stringByReplacingOccurrencesOfString: @"-"
withString: @"_"]];
[parts replaceObjectAtIndex: 4 withObject: ocFSTableName];
folderTableURL
= [NSURL URLWithString: [parts componentsJoinedByString: @"/"]];
@@ -341,7 +338,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:
@@ -358,7 +355,7 @@ static NSMapTable *contextsTable = nil;
[channel cancelFetch];
[cm releaseChannel: channel];
[cm releaseChannel: channel];
}
/* SOGo context objects */
@@ -372,11 +369,6 @@ static NSMapTable *contextsTable = nil;
return authenticator;
}
- (void) activate
{
[self activateWithUser: [self sogoUser]];
}
- (void) activateWithUser: (SOGoUser *) activeUser;
{
NSMutableDictionary *info;
@@ -387,24 +379,4 @@ 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
+39 -118
View File
@@ -26,7 +26,6 @@
// Useful macros
//
#define ADVANCE _bytes++; _current_pos++;
#define ADVANCE_N(N) _bytes += (N); _current_pos += (N);
#define REWIND _bytes--; _current_pos--;
@@ -413,46 +412,16 @@ const unsigned short ansicpg874[256] = {
- (const char *) parseControlWord: (unsigned int *) len
{
const char *start, *end;
start = ADVANCE;
/*
A control word is defined by:
\<ASCII Letter Sequence><Delimiter>
*/
while (isalpha(*_bytes))
while (isalnum(*_bytes) || *_bytes == '-')
{
ADVANCE;
}
/*
The <Delimiter> can be one of the following:
- A space. This serves only to delimit a control word and is
ignored in subsequent processing.
- A numeric digit or an ASCII minus sign (-), which indicates
that a numeric parameter is associated with the control word.
Only this case requires to include it in the control word.
- Any character other than a letter or a digit
*/
if (*_bytes == '-' || isdigit(*_bytes))
{
ADVANCE;
while (isdigit(*_bytes)) // TODO: Allow up to 10 digits
{
ADVANCE;
}
}
/* In this case, the delimiting character terminates the control
word and is not part of the control word. */
end = _bytes;
*len = end-start-1;
return start+1;
}
@@ -539,7 +508,6 @@ const unsigned short ansicpg874[256] = {
fontTable = [[[RTFFontTable alloc] init] autorelease];
fontName = nil;
fontInfo = nil;
count = 0;
do
@@ -575,7 +543,7 @@ const unsigned short ansicpg874[256] = {
// Skip our control word
if (strncmp((const char*)cw, "fonttbl", len) == 0)
continue;
// We must at least parse <fontnum><fontfamily><fcharset>
s = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1
length: len-1
@@ -590,18 +558,12 @@ const unsigned short ansicpg874[256] = {
// We now parse <fontfamily><fcharset>
cw = [self parseControlWord: &len];
if (len == 0) // Possibly parsing a space
cw = [self parseControlWord: &len];
fontInfo->family = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1
length: len-1
encoding: NSASCIIStringEncoding
freeWhenDone: NO];
cw = [self parseControlWord: &len];
if (len == 0) // Possibly parsing a space
cw = [self parseControlWord: &len];
fontInfo->charset = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1
length: len-1
encoding: NSASCIIStringEncoding
@@ -660,44 +622,13 @@ const unsigned short ansicpg874[256] = {
} while (count != 0);
}
- (void) parseIgnoringEverything
{
unsigned int count = 1;
// Ignore everything. But we cannot parse it blindly because it could have
// binary data with '}' and '{' bytes, so disasters can happen and they will
do
{
if (*_bytes == '\\')
{
unsigned int binary_size, len = 0, cw_len;
const char *cw = [self parseControlWord: &len];
cw_len = strlen("bin");
if (strncmp(cw, "bin", cw_len) == 0 && len > cw_len)
{
NSString *s;
s = [[NSString alloc] initWithBytesNoCopy: (void *) cw + cw_len
length: len - cw_len
encoding: NSASCIIStringEncoding
freeWhenDone: NO];
[s autorelease];
binary_size = [s intValue];
ADVANCE_N(binary_size);
}
}
if (*_bytes == '{') count++;
if (*_bytes == '}') count--;
ADVANCE;
}
while (count > 0);
}
//
//
//
- (void) parsePicture
{
[self parseIgnoringEverything];
// Do the same as -parseStyleSheet for now, that is, ignore everything.
[self parseStyleSheet];
}
//
@@ -717,7 +648,6 @@ const unsigned short ansicpg874[256] = {
fontTable = nil;
colorTable = nil;
charset = NULL;
formattingOptions = nil;
_html = [[NSMutableData alloc] init];
[_html appendBytes: "<html><meta charset='utf-8'><body>" length: 34];
@@ -764,7 +694,19 @@ const unsigned short ansicpg874[256] = {
}
else if (*(_bytes+1) == '*')
{
[self parseIgnoringEverything];
int cc = 1;
do
{
if (*_bytes == '{')
cc++;
if (*_bytes == '}')
cc--;
ADVANCE;
}
while (cc != 0);
continue;
}
@@ -784,16 +726,16 @@ const unsigned short ansicpg874[256] = {
{
// We rewind our buffer so we start at the beginning of {\fonttbl...
_bytes = cw-2;
_current_pos -= 9; // Length: {\fonttbl
_current_pos -= 10;
fontTable = [self parseFontTable];
// We go back 1 byte in order to end our section properly ('}' character)
// We go back 1 byte in order to end our section properly ('}' character
REWIND;
}
else if (strncmp(cw, "stylesheet", 10) == 0)
{
_bytes = cw-2;
_current_pos -= 12; // Length: {\stylesheet
_current_pos -= 13;
[self parseStyleSheet];
REWIND;
}
@@ -804,7 +746,7 @@ const unsigned short ansicpg874[256] = {
else if (strncmp(cw, "pict", 4) == 0)
{
_bytes = cw-2;
_current_pos -= 6; // Length: {\pict
_current_pos -= 7;
[self parsePicture];
REWIND;
}
@@ -824,19 +766,19 @@ const unsigned short ansicpg874[256] = {
int color_index;
char *v;
if (!formattingOptions) continue;
color_index = [[s substringFromIndex: 2] intValue];
colorDef = [colorTable colorDefAtIndex: color_index];
if (!colorDef) continue;
if (formattingOptions->color_index >= 0)
if (!formattingOptions)
continue;
if (formattingOptions->color_index >= 0) // && color_index != formattingOptions->color_index)
{
[_html appendBytes: "</font>" length: 7];
}
formattingOptions->color_index = color_index;
formattingOptions->color_index = color_index;
colorDef = [colorTable colorDefAtIndex: color_index];
v = malloc(23*sizeof(char));
memset(v, 0, 23);
sprintf(v, "<font color=\"#%02x%02x%02x\">", colorDef->red, colorDef->green, colorDef->blue);
@@ -872,41 +814,20 @@ const unsigned short ansicpg874[256] = {
if (!formattingOptions)
continue;
if (formattingOptions->font_index >= 0 &&
font_index != formattingOptions->font_index)
{
[_html appendBytes: "</font>" length: 7];
}
formattingOptions->font_index = font_index;
fontInfo = [fontTable fontInfoAtIndex: font_index];
char *v = NULL;
if (fontInfo && fontInfo->name)
{
if ([fontInfo->name length] < 128)
{
int tag_size = 15 + [fontInfo->name length];
v = calloc(tag_size, sizeof(char));
snprintf(v, tag_size, "<font face=\"%s\">", [fontInfo->name UTF8String]);
}
else
{
NSLog(@"RTFHandler: Font %u has %d chars length, parse error? "
"Ignored", font_index, [fontInfo->name length]);
v = calloc(7, sizeof(char));
sprintf(v, "<font>");
}
}
else
{
// RTF badformed? We don't know about that font (font_index).
// Anyhow, we still open the html tag because in the future
// we will close it (e.g. when new font is used).
v = calloc(7, sizeof(char));
sprintf(v, "<font>");
}
char *v = malloc(128*sizeof(char));
memset(v, 0, 128);
sprintf(v, "<font face=\"%s\">", [fontInfo->name UTF8String]);
[_html appendBytes: v length: strlen(v)];
free(v);
}
+3 -3
View File
@@ -39,7 +39,7 @@
#import <SOGo/BSONCodec.h>
#import "NSObject+PropertyList.h"
Class MAPIStoreUserContextK, SOGoCacheGCSObjectK;
Class MAPIStoreUserContextK, SOGoMAPIDBObjectK;
static void
DumpBSONData(NSData *data)
@@ -60,7 +60,7 @@ DbDumpObject (NSString *username, NSString *path)
ctx = [MAPIStoreUserContextK userContextWithUsername: username
andTDBIndexing: NULL];
dbobject = [SOGoCacheGCSObjectK new];
dbobject = [SOGoMAPIDBObjectK new];
[dbobject setTableUrl: [ctx folderTableURL]];
record = [dbobject lookupRecord: path newerThanVersion: -1];
if (record)
@@ -107,7 +107,7 @@ int main (int argc, char *argv[], char *envp[])
[loader loadProducts: [NSArray arrayWithObject: BACKEND_BUNDLE_NAME]];
MAPIStoreUserContextK = NSClassFromString (@"MAPIStoreUserContext");
SOGoCacheGCSObjectK = NSClassFromString (@"SOGoCacheGCSObject");
SOGoMAPIDBObjectK = NSClassFromString (@"SOGoMAPIDBObject");
arguments = [[NSProcessInfo processInfo] arguments];
if ([arguments count] > 2) {
+137 -162
View File
@@ -74,7 +74,6 @@
@implementation iCalEvent (MAPIStoreProperties)
- (void) _setupEventRecurrence: (NSData *) mapiRecurrenceData
inTimeZone: (NSTimeZone *) tz
inMemCtx: (TALLOC_CTX *) memCtx
{
struct Binary_r *blob;
@@ -82,18 +81,9 @@
blob = [mapiRecurrenceData asBinaryInMemCtx: memCtx];
pattern = get_AppointmentRecurrencePattern (memCtx, blob);
if (pattern == NULL) {
[self logWithFormat: @"Error parsing recurrence pattern. No changes in event recurrence will be done"];
return;
}
[(iCalCalendar *) parent setupRecurrenceWithMasterEntity: self
fromRecurrencePattern: &pattern->RecurrencePattern
withExceptions: pattern->ExceptionInfo
andExceptionCount: pattern->ExceptionCount
inTimeZone: tz
];
[(iCalCalendar *) parent
setupRecurrenceWithMasterEntity: self
fromRecurrencePattern: &pattern->RecurrencePattern];
//talloc_free (blob);
}
@@ -141,107 +131,6 @@
}
}
- (int) _updateFromAttendeeMAPIProperties: (NSArray *) recipients
withRole: (NSString *) role
outParam: (BOOL *) organizerIsSet
{
NSDictionary *dict;
NSString *attEmail;
iCalPerson *person;
iCalPersonPartStat newPartStat;
NSNumber *flags, *trackStatus;
int i, effective;
effective = 0;
for (i = 0; i < [recipients count]; i++)
{
dict = [recipients objectAtIndex: i];
person = [iCalPerson new];
[person setCn: [dict objectForKey: @"fullName"]];
attEmail = [dict objectForKey: @"email"];
[person setEmail: attEmail];
flags = [dict objectForKey: MAPIPropertyKey (PR_RECIPIENT_FLAGS)];
if (!flags)
{
[self logWithFormat:
@"no recipient flags specified: skipping recipient"];
continue;
}
if (([flags unsignedIntValue] & 0x0002)) /* recipOrganizer */
{
[self setOrganizer: person];
*organizerIsSet = YES;
[self logWithFormat: @"organizer set via recipient flags"];
}
else
{
BOOL isOrganizer = NO;
// /* Work-around: it happens that Outlook still passes the
// organizer as a recipient, maybe because of a feature
// documented in a pre-mesozoic PDF still buried in a
// cavern... In that case we remove it, and we keep the
// number of effective recipients in "effective". If the
// total is 0, we remove the "ORGANIZER" too. */
// if ([attEmail isEqualToString: orgEmail])
// {
// [self logWithFormat:
// @"avoiding setting organizer as recipient"];
// continue;
// }
trackStatus = [dict objectForKey: MAPIPropertyKey (PidTagRecipientTrackStatus)];
if (trackStatus)
{
/* FIXME: we should provide a data converter between OL
partstats and SOGo */
switch ([trackStatus unsignedIntValue])
{
case 0x01: /* respOrganized */
isOrganizer = YES;
break;
case 0x02: /* respTentative */
newPartStat = iCalPersonPartStatTentative;
break;
case 0x03: /* respAccepted */
newPartStat = iCalPersonPartStatAccepted;
break;
case 0x04: /* respDeclined */
newPartStat = iCalPersonPartStatDeclined;
break;
default:
newPartStat = iCalPersonPartStatNeedsAction;
}
if (isOrganizer)
{
[self setOrganizer: person];
*organizerIsSet = YES;
[self logWithFormat: @"organizer set via track status"];
}
else
{
[person setParticipationStatus: newPartStat];
[person setRsvp: @"TRUE"];
[person setRole: role];
[self addToAttendees: person];
effective++;
}
}
else
[self errorWithFormat: @"skipped recipient due"
@" to missing track status"];
}
[person release];
}
return effective;
}
- (void) updateFromMAPIProperties: (NSDictionary *) properties
inUserContext: (MAPIStoreUserContext *) userContext
withActiveUser: (SOGoUser *) activeUser
@@ -251,7 +140,7 @@
iCalDateTime *start, *end;
iCalTimeZone *tz;
NSTimeZone *userTimeZone;
NSString *priority, *class = nil;
NSString *priority;
NSUInteger responseStatus = 0;
NSInteger tzOffset;
SOGoUser *ownerUser;
@@ -318,7 +207,16 @@
value
= [properties objectForKey: MAPIPropertyKey (PidLidExceptionReplaceTime)];
if (value)
[self setRecurrenceId: value];
{
if (!isAllDay)
{
tzOffset = [userTimeZone secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
}
[self setRecurrenceId: value];
}
// start
value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentStartWhole)];
@@ -343,7 +241,13 @@
[start setTimeZone: nil];
}
else
{
tzOffset = [userTimeZone secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[start setDateTime: value];
}
}
/* end */
@@ -369,7 +273,13 @@
[end setTimeZone: nil];
}
else
{
tzOffset = [[value timeZone] secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[end setDateTime: value];
}
}
/* priority */
@@ -392,36 +302,6 @@
priority = @"0"; // None
[self setPriority: priority];
/* class */
/* See [MS-OXCICAL] Section 2.1.3.11.20.4 */
value = [properties objectForKey: MAPIPropertyKey(PR_SENSITIVITY)];
if (value)
{
switch ([value intValue])
{
case 1:
class = @"X-PERSONAL";
break;
case 2:
class = @"PRIVATE";
break;
case 3:
class = @"CONFIDENTIAL";
break;
default: /* 0 as well */
class = @"PUBLIC";
}
}
if (class)
[self setAccessClass: class];
/* Categories */
/* See [MS-OXCICAL] Section 2.1.3.1.1.20.3 */
value = [properties objectForKey: MAPIPropertyKey (PidNameKeywords)];
if (value)
[self setCategories: value];
/* show time as free/busy/tentative/out of office. Possible values are:
0x00000000 - olFree
0x00000001 - olTentative
@@ -467,7 +347,7 @@
value = [properties
objectForKey: MAPIPropertyKey (PidLidAppointmentRecur)];
if (value)
[self _setupEventRecurrence: value inTimeZone: userTimeZone inMemCtx: memCtx];
[self _setupEventRecurrence: value inMemCtx: memCtx];
/* alarm */
[self _setupEventAlarmFromProperties: properties];
@@ -476,28 +356,106 @@
value = [properties objectForKey: @"recipients"];
if (value)
{
NSArray *recipients;
NSDictionary *dict;
NSString *orgEmail, *sentBy;
NSString *orgEmail, *sentBy, *attEmail;
iCalPerson *person;
iCalPersonPartStat newPartStat;
int effective;
NSNumber *flags, *trackStatus;
int i, effective;
BOOL organizerIsSet = NO;
[self setOrganizer: nil];
[self removeAllAttendees];
/* In [MS-OXOCAL] Section 2.2.4.10.7 says the recipient type is 0x01 as Required
and 0x02 as Optional and other documents such [MS-OXCMSG] 2.2.3.1.2 indicates
that MAPI_TO is 0x01 and MAPI_CC is 0x02, that's why in SOGo is in 'to' and 'cc'
respectively. */
effective = [self _updateFromAttendeeMAPIProperties: [value objectForKey: @"to"]
withRole: @"REQ-PARTICIPANT"
outParam: &organizerIsSet];
effective += [self _updateFromAttendeeMAPIProperties: [value objectForKey: @"cc"]
withRole: @"OPT-PARTICIPANT"
outParam: &organizerIsSet];
recipients = [value objectForKey: @"to"];
effective = 0;
for (i = 0; i < [recipients count]; i++)
{
dict = [recipients objectAtIndex: i];
person = [iCalPerson new];
[person setCn: [dict objectForKey: @"fullName"]];
attEmail = [dict objectForKey: @"email"];
[person setEmail: attEmail];
flags = [dict objectForKey: MAPIPropertyKey (PR_RECIPIENT_FLAGS)];
if (!flags)
{
[self logWithFormat:
@"no recipient flags specified: skipping recipient"];
continue;
}
if (effective == 0) /* See work-around inside _updateFromAttendeeMAPIProperties */
if (([flags unsignedIntValue] & 0x0002)) /* recipOrganizer */
{
[self setOrganizer: person];
organizerIsSet = YES;
[self logWithFormat: @"organizer set via recipient flags"];
}
else
{
BOOL isOrganizer = NO;
// /* Work-around: it happens that Outlook still passes the
// organizer as a recipient, maybe because of a feature
// documented in a pre-mesozoic PDF still buried in a
// cavern... In that case we remove it, and we keep the
// number of effective recipients in "effective". If the
// total is 0, we remove the "ORGANIZER" too. */
// if ([attEmail isEqualToString: orgEmail])
// {
// [self logWithFormat:
// @"avoiding setting organizer as recipient"];
// continue;
// }
trackStatus = [dict objectForKey: MAPIPropertyKey (PidTagRecipientTrackStatus)];
if (trackStatus)
{
/* FIXME: we should provide a data converter between OL
partstats and SOGo */
switch ([trackStatus unsignedIntValue])
{
case 0x01: /* respOrganized */
isOrganizer = YES;
break;
case 0x02: /* respTentative */
newPartStat = iCalPersonPartStatTentative;
break;
case 0x03: /* respAccepted */
newPartStat = iCalPersonPartStatAccepted;
break;
case 0x04: /* respDeclined */
newPartStat = iCalPersonPartStatDeclined;
break;
default:
newPartStat = iCalPersonPartStatNeedsAction;
}
if (isOrganizer)
{
[self setOrganizer: person];
organizerIsSet = YES;
[self logWithFormat: @"organizer set via track status"];
}
else
{
[person setParticipationStatus: newPartStat];
[person setRsvp: @"TRUE"];
[person setRole: @"REQ-PARTICIPANT"];
[self addToAttendees: person];
effective++;
}
}
else
[self errorWithFormat: @"skipped recipient due"
@" to missing track status"];
}
[person release];
}
if (effective == 0) /* See work-around above */
[self setOrganizer: nil];
else
{
@@ -523,7 +481,7 @@
= [properties objectForKey: MAPIPropertyKey (PidLidResponseStatus)];
if (value)
responseStatus = [value unsignedLongValue];
/* FIXME: we should provide a data converter between OL partstats and
SOGo */
switch (responseStatus)
@@ -545,6 +503,23 @@
value = [properties objectForKey: MAPIPropertyKey (PidLidAttendeeCriticalChange)];
if (value && ![value isNever])
[self setTimeStampAsDate: value];
// if (newPartStat // != iCalPersonPartStatUndefined
// )
// {
// // iCalPerson *participant;
// // participant = [self userAsAttendee: ownerUser];
// // [participant setParticipationStatus: newPartStat];
// // [sogoObject saveComponent: self];
// [sogoObject changeParticipationStatus: newPartStat
// withDelegate: nil];
// // [[self context] tearDownRequest];
// }
// // }1005
// // else
// // {
}
}
else
@@ -559,7 +534,7 @@
[person setCn: [dict objectForKey: @"fullName"]];
orgEmail = [dict objectForKey: @"email"];
[person setEmail: orgEmail];
if (![activeUser isEqual: ownerUser])
{
dict = [activeUser primaryIdentity];
+1 -9
View File
@@ -51,7 +51,6 @@
NSArray *byMonth;
iCalByDayMask *mask;
NSCalendarDate *dateValue;
int16_t wDay;
rrule = [self recurrenceRule];
byMonth = [rrule byMonth];
@@ -60,14 +59,7 @@
tzData->wMonth = [[byMonth objectAtIndex: 0] intValue];
mask = [rrule byDayMask];
tzData->wDayOfWeek = [mask firstDay];
wDay = [mask firstOccurrence];
if (wDay < 0)
/* [MS-OXOCAL] the wDay field is set to indicate the
occurrence of the day of the week within the month (1 to
5, where 5 indicates the final occurrence during the
month if that day of the week does not occur 5 times). */
wDay += 6;
tzData->wDay = (uint16_t) wDay;
tzData->wDay = [mask firstOccurrence];
dateValue = [self startDate];
tzData->wHour = [dateValue hourOfDay];
-1
View File
@@ -4,6 +4,5 @@ import sys
import samba.param
a = samba.param.LoadParm()
a.set('debug level', '0')
a.load_default()
print a.get(sys.argv[1])
-27
View File
@@ -1,27 +0,0 @@
[![SOGo Logo](http://www.sogo.nu/fileadmin/sogo/logos/sogo.logo.png)](http://www.sogo.nu/)
Share your calendars, address books and mails in your community with a completely free and open source solution.
Let your Mozilla Thunderbird/Lightning, Microsoft Outlook, Apple iCal/iPhone, Android and BlackBerry users collaborate using a modern platform.
## What is SOGo?
SOGo is [fully supported](http://www.sogo.nu/support/commercial_support.html) and [trusted](http://www.sogo.nu/tour/testimonials.html) groupware server with a focus on scalability and open standards. SOGo is released under the GNU GPL/LGPL v2 and above.
SOGo provides a rich AJAX-based Web interface and supports multiple native clients through the use of standard protocols such as CalDAV, CardDAV and GroupDAV.
SOGo is the missing component of your infrastructure; it sits in the middle of your servers to offer your users an uniform and complete interface to access their information. It has been deployed in production environments where thousands of users are involved.
[![Sogo diagram](http://www.sogo.nu/uploads/pics/sogo.png)](http://www.sogo.nu/)
[Learn more...](http://www.sogo.nu/about/overview.html)
## Microsoft Outlook Compatible
SOGo offers native Microsoft Outlook compatibility using the [OpenChange](http://www.openchange.org/) backend developed by [Inverse](http://www.inverse.ca/). This means Microsoft Outlook 2003, 2007, 2010 and 2013 can talk directly to SOGo &ndash; just like if it was a Microsoft Exchange server. **No plugins are required in Outlook to make this work**.
The following screencast shows Outlook 2010 connected to SOGo as if it was an Exchange server, along the Web interface of SOGo.
[![SOGo Screencast](http://img.youtube.com/vi/1hcBSB4Kxww/0.jpg)](http://www.youtube.com/watch?v=1hcBSB4Kxww)
[![SOGo on GitHub](http://www.sogo.nu/fileadmin/images/icon.github.png)](https://github.com/inverse-inc/sogo/) [![SOGo Ohloh](http://www.sogo.nu/fileadmin/images/icon.ohloh.png)](https://www.ohloh.net/p/sogo) [![SOGo on Twitter](http://www.sogo.nu/fileadmin/images/icon.twitter.png)](http://twitter.com/scalableogo) [![SOGo on SourceForge](http://www.sogo.nu/fileadmin/images/icon.sourceforge.png)](http://sourceforge.net/projects/sogo-zeg) [![SOGo on free code](http://www.sogo.nu/fileadmin/images/icon.freecode.png)](https://freecode.com/projects/sogo-inverse) [![SOGo on LinkedIn](http://www.sogo.nu/fileadmin/images/icon.linkedin.png)](http://www.linkedin.com/groups/SOGo-Groupware-4164805)
+1 -1
View File
@@ -240,7 +240,7 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60;
handle = currentHandle;
else if (debugPools)
[self logWithFormat: @"DBPOOL: cannot use handle (%@ vs %@) ",
[_url absoluteString], [currentHandle->url absoluteString]];
[_url absoluteString], [handle->url absoluteString]];
return handle;
}
+1 -2
View File
@@ -20,7 +20,6 @@
*/
#import <Foundation/NSDictionary.h>
#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSSet.h>
#import <Foundation/NSString.h>
@@ -148,7 +147,7 @@
if ([keys count] == 0)
return folderQualifier;
bindings = [_folder dictionaryWithValuesForKeys:keys];
bindings = [_folder valuesForKeys:keys];
return [folderQualifier qualifierWithBindings:bindings
requiresAllVariables:NO];
}
+1 -6
View File
@@ -131,7 +131,7 @@
},
{
columnName = c_partstates;
sqlType = "CLOB";
sqlType = "VARCHAR2(255)";
allowsNull = YES;
},
{
@@ -154,10 +154,5 @@
sqlType = "INTEGER";
allowsNull = YES;
},
{
columnName = c_description;
sqlType = "CLOB";
allowsNull = YES;
}
);
}
+1 -6
View File
@@ -131,7 +131,7 @@
},
{
columnName = c_partstates;
sqlType = "TEXT";
sqlType = "VARCHAR(255)";
allowsNull = YES;
},
{
@@ -153,11 +153,6 @@
columnName = c_nextalarm;
sqlType = "INT";
allowsNull = YES;
},
{
columnName = c_description;
sqlType = "TEXT";
allowsNull = YES;
}
);
}
+4 -6
View File
@@ -59,10 +59,8 @@ static NGCardsSaxHandler *sax = nil;
[parser setErrorHandler:sax];
}
else
{
//NSLog(@"ERROR(%s): did not find a parser for text/x-vcard!",
// __PRETTY_FUNCTION__);
}
NSLog(@"ERROR(%s): did not find a parser for text/x-vcard!",
__PRETTY_FUNCTION__);
}
return parser;
@@ -172,8 +170,8 @@ static NGCardsSaxHandler *sax = nil;
{
if (![aChild isKindOfClass: mappedClass])
{
//NSLog (@"warning: new child to entity '%@': '%@' converted to '%@'",
// tag, childTag, NSStringFromClass(mappedClass));
NSLog (@"warning: new child to entity '%@': '%@' converted to '%@'",
tag, childTag, NSStringFromClass(mappedClass));
newChild = [aChild elementWithClass: mappedClass];
}
}
+1 -1
View File
@@ -54,7 +54,7 @@
- (BOOL)appendLine:(NSString *)_line {
if (self->isFinished) {
//NSLog(@"WARNING[%s]: already finished!", __PRETTY_FUNCTION__);
NSLog(@"WARNING[%s]: already finished!", __PRETTY_FUNCTION__);
return NO;
}
// limit length to 75 chars
+2
View File
@@ -55,6 +55,8 @@ static NSArray *privilegedTagNames = nil;
- (void) dealloc
{
if (content)
free (content);
[self reset];
[cards release];
[currentGroup release];
+2 -2
View File
@@ -77,8 +77,8 @@ static NSString *gmtcalfmt = @"%Y%m%dT%H%M%SZ";
return [self icalStringInGMT];
else {
/* not in GMT */
//NSLog(@"WARNING(%s): arbitary timezones not supported yet: %@",
// __PRETTY_FUNCTION__, _tz);
NSLog(@"WARNING(%s): arbitary timezones not supported yet: %@",
__PRETTY_FUNCTION__, _tz);
return [self icalStringInGMT];
}
}
+1 -3
View File
@@ -276,9 +276,7 @@
}
}
else
{
//NSLog(@"Cannot parse iCal duration value: '%@'", self);
}
NSLog(@"Cannot parse iCal duration value: '%@'", self);
if (isNegative)
ti = -ti;
+3 -4
View File
@@ -1,6 +1,8 @@
/* iCalByDayMask.h - this file is part of SOPE
*
* Copyright (C) 2010-2015 Inverse inc.
* Copyright (C) 2010 Wolfgang Sourdeau
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* 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
@@ -53,8 +55,6 @@ typedef iCalWeekOccurrence iCalWeekOccurrences[7];
- (id) initWithDays: (iCalWeekOccurrences) theDays;
+ (id) byDayMaskWithRuleString: (NSString *) byDayRule;
- (id) initWithRuleString: (NSString *) byDayRule;
+ (id) byDayMaskWithDaysAndOccurrences: (NSArray *) values;
- (id) initWithDaysAndOccurrences: (NSArray *) values;
- (BOOL) occursOnDay: (iCalWeekDay) weekDay;
- (BOOL) occursOnDay: (iCalWeekDay) weekDay
@@ -71,7 +71,6 @@ typedef iCalWeekOccurrence iCalWeekOccurrences[7];
- (NSString *) asRuleString;
- (NSString *) asRuleStringWithIntegers;
- (NSArray *) asRuleArray;
@end
+20 -159
View File
@@ -1,6 +1,8 @@
/* iCalByDayMask.m - this file is part of SOPE
*
* Copyright (C) 2010-2015 Inverse inc.
* Copyright (C) 2010 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* 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
@@ -19,9 +21,7 @@
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#import "iCalByDayMask.h"
@@ -39,10 +39,10 @@
+ (id) byDayMaskWithDays: (iCalWeekOccurrences) theDays
{
id o;
o = [[self alloc] initWithDays: theDays];
AUTORELEASE(o);
return o;
}
@@ -62,7 +62,7 @@
{
id o;
iCalWeekOccurrences d;
d[iCalWeekDaySunday] = 0;
d[iCalWeekDayMonday] = iCalWeekOccurrenceAll;
d[iCalWeekDayTuesday] = iCalWeekOccurrenceAll;
@@ -72,7 +72,7 @@
d[iCalWeekDaySaturday] = 0;
o = [[self alloc] initWithDays: d];
AUTORELEASE(o);
return o;
}
@@ -102,7 +102,7 @@
if (self)
{
memset(days, 0, 7 * sizeof(iCalWeekOccurrence));
if ([byDayRule length] > 0)
{
values = [byDayRule componentsSeparatedByString: @","];
@@ -120,7 +120,7 @@
[value getCharacters: chars
range: NSMakeRange(valueLength - 2, 2)];
switch (chars[0])
{
case 'M': day = iCalWeekDayMonday;
@@ -142,7 +142,7 @@
day = iCalWeekDaySunday;
break;
}
if (day != iCalWeekDayUnknown)
{
c = [value characterAtIndex: 0];
@@ -157,15 +157,15 @@
digitStart = 1;
c = [value characterAtIndex: 1];
}
i = digitStart;
while (i < valueLength && isdigit(c))
{
i++;
c = [value characterAtIndex: i];
}
if (i != digitStart)
order = [[value substringWithRange: NSMakeRange(digitStart, (i - digitStart))] intValue];
@@ -186,123 +186,7 @@
}
}
}
return self;
}
+ (id) byDayMaskWithDaysAndOccurrences: (NSArray *) values
{
id o;
o = [[self alloc] initWithDaysAndOccurrences: values];
AUTORELEASE(o);
return o;
}
- (id) initWithDaysAndOccurrences: (NSArray *) values
{
unsigned int count, max;
NSString *value;
unichar c, chars[2];
unsigned int valueLength, i, digitStart, order;
iCalWeekDay day;
id mask;
BOOL reverse;
self = [super init];
if (self)
{
memset(days, 0, 7 * sizeof(iCalWeekOccurrence));
max = [values count];
for (count = 0; count < max; count++)
{
mask = [values objectAtIndex: count];
if (![mask isKindOfClass: [NSDictionary class]])
continue;
value = [[mask objectForKey: @"day"] uppercaseString];
valueLength = [value length];
if (valueLength > 1)
{
day = iCalWeekDayUnknown;
reverse = NO;
digitStart = 0;
order = 0;
[value getCharacters: chars
range: NSMakeRange(0, valueLength)];
switch (chars[0])
{
case 'M': day = iCalWeekDayMonday;
break;
case 'W': day = iCalWeekDayWednesday;
break;
case 'F': day = iCalWeekDayFriday;
break;
case 'T':
if (chars[1] == 'U')
day = iCalWeekDayTuesday;
else if (chars[1] == 'H')
day = iCalWeekDayThursday;
break;
case 'S':
if (chars[1] == 'A')
day = iCalWeekDaySaturday;
else if (chars[1] == 'U')
day = iCalWeekDaySunday;
break;
}
if (day != iCalWeekDayUnknown)
{
value = [mask objectForKey: @"occurrence"];
valueLength = [value length];
if (valueLength > 0)
{
c = [value characterAtIndex: 0];
if (c == '-')
{
digitStart = 1;
reverse = YES;
}
else if (c == '+')
{
digitStart = 1;
}
i = digitStart;
while (i < valueLength)
{
c = [value characterAtIndex: i];
i++;
if (!isdigit(c))
break;
}
if (i != digitStart)
order = [[value substringWithRange: NSMakeRange(digitStart, (i - digitStart))] intValue];
}
if (order > 0 && order < 6)
{
order = pow (2, order - 1);
if (reverse)
order = order << 5;
days[day] |= order;
//NSLog(@"*** iCalByDayMask [%i] %@ : day = %i, order = %i, result = %i", count, byDayRule, day, order, days[day]);
}
else
{
days[day] = iCalWeekOccurrenceAll;
}
}
}
}
}
return self;
}
@@ -330,7 +214,7 @@
withWeekNumber: (int) week
{
unsigned int absWeek, order;
absWeek = abs (week);
order = 0;
if (absWeek > 0 && absWeek < 6)
@@ -339,7 +223,7 @@
if (week < 0)
order = order << 5;
}
return ((days[weekDay] & order) > 0);
}
@@ -365,7 +249,7 @@
if (days[i])
day = i;
}
return day;
}
@@ -376,10 +260,10 @@
occurrence = 0;
day = [self firstDay];
if (day > -1 && days[day] != iCalWeekOccurrenceAll)
occurrence = [self _iCalWeekOccurrenceIntValue: days[day]];
return occurrence;
}
@@ -439,7 +323,7 @@
[rules addObject: rule];
}
}
return [rules componentsJoinedByString: @","];
}
@@ -460,27 +344,4 @@
return s;
}
- (NSArray *) asRuleArray
{
NSMutableArray *rules;
NSMutableDictionary *rule;
int i;
rules = [NSMutableArray array];
for (i = 0; i < 7; i++)
{
if (days[i])
{
rule = [NSMutableDictionary dictionary];
if (days[i] != iCalWeekOccurrenceAll)
[rule setObject: [NSNumber numberWithInt: [self _iCalWeekOccurrenceIntValue: days[i]]]
forKey: @"occurrence"];
[rule setObject: iCalWeekDayString[i]
forKey: @"day"];
[rules addObject: rule];
}
}
return rules;
}
@end /* iCalByDayMask */
+2 -2
View File
@@ -94,8 +94,8 @@ typedef enum
- (void) increaseSequence;
/* url can either be set as NSString or NSURL */
- (void) setAttach: (NSArray *) _value;
- (NSArray *) attach;
- (void) setAttach: (id) _value;
- (NSURL *) attach;
- (void) setUrl: (id) _value;
- (NSURL *) url;
+15 -32
View File
@@ -400,49 +400,32 @@
return [self childrenWithTag: @"valarm"];
}
- (void) setAttach: (NSArray *) _value
- (void) setAttach: (id) _value
{
NSString *aString;
id anObject;
int count, max;
max = [_value count];
for (count = 0; count < max; count++)
{
anObject = [_value objectAtIndex: count];
if ([anObject isKindOfClass: [NSURL class]])
{
aString = [anObject absoluteString];
}
else
aString = anObject;
[self addChild: [CardElement simpleElementWithTag: @"attach" value: aString]];
}
if ([_value isKindOfClass: [NSString class]])
aString = _value;
else if ([_value isKindOfClass: [NSURL class]])
aString = [_value absoluteString];
else
aString = @"";
[[self uniqueChildWithTag: @"attach"] setSingleValue: aString forKey: @""];
}
- (NSArray *) attach
- (NSURL *) attach
{
NSArray *elements;
NSMutableArray *attachUrls;
NSString *stringAttach;
NSURL *url;
int count, max;
elements = [self childrenWithTag: @"attach"];
max = [elements count];
attachUrls = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{
stringAttach = [[elements objectAtIndex: count] flattenedValuesForKey: @""];
url = [NSURL URLWithString: stringAttach];
stringAttach = [[self uniqueChildWithTag: @"attach"] flattenedValuesForKey: @""];
url = [NSURL URLWithString: stringAttach];
if (!url && [stringAttach length] > 0)
url = [NSURL URLWithString: [NSString stringWithFormat: @"http://%@", stringAttach]];
[attachUrls addObject: [url absoluteString]];
}
if (!url && [stringAttach length] > 0)
url = [NSURL URLWithString: [NSString stringWithFormat: @"http://%@", stringAttach]];
return attachUrls;
return url;
}
- (void) setUrl: (id) _value
+2 -2
View File
@@ -59,8 +59,8 @@ static NSTimeZone *defTZ = nil;
[self takeValue:_value forXKey:_key];
}
else {
//NSLog(@"0x%08x[%@]: ignoring attempt to set unbound key '%@'",
// self, NSStringFromClass([self class]), _key);
NSLog(@"0x%08x[%@]: ignoring attempt to set unbound key '%@'",
self, NSStringFromClass([self class]), _key);
}
}
-2
View File
@@ -44,8 +44,6 @@ typedef enum {
@interface iCalPerson : CardElement
+ (NSString *) descriptionForParticipationStatus: (iCalPersonPartStat) _status;
/* accessors */
- (void)setCn:(NSString *)_s;
+34 -45
View File
@@ -25,48 +25,6 @@
@implementation iCalPerson
+ (NSString *) descriptionForParticipationStatus: (iCalPersonPartStat) _status
{
NSString *stat;
switch (_status) {
case iCalPersonPartStatUndefined:
stat = @"";
break;
case iCalPersonPartStatAccepted:
stat = @"ACCEPTED";
break;
case iCalPersonPartStatDeclined:
stat = @"DECLINED";
break;
case iCalPersonPartStatTentative:
stat = @"TENTATIVE";
break;
case iCalPersonPartStatDelegated:
stat = @"DELEGATED";
break;
case iCalPersonPartStatCompleted:
stat = @"COMPLETED";
break;
case iCalPersonPartStatInProcess:
stat = @"IN-PROCESS";
break;
case iCalPersonPartStatExperimental:
case iCalPersonPartStatOther:
// [NSException raise:NSInternalInconsistencyException
// format:@"Attempt to set meaningless "
// @"participationStatus (%d)!", _status];
stat = nil; /* keep compiler happy */
break;
default:
stat = @"NEEDS-ACTION";
break;
}
return stat;
}
/* accessors */
- (void) setCn: (NSString *) _s
@@ -174,13 +132,44 @@
{
NSString *stat;
stat = [iCalPerson descriptionForParticipationStatus: _status];
switch (_status) {
case iCalPersonPartStatUndefined:
stat = @"";
break;
case iCalPersonPartStatAccepted:
stat = @"ACCEPTED";
break;
case iCalPersonPartStatDeclined:
stat = @"DECLINED";
break;
case iCalPersonPartStatTentative:
stat = @"TENTATIVE";
break;
case iCalPersonPartStatDelegated:
stat = @"DELEGATED";
break;
case iCalPersonPartStatCompleted:
stat = @"COMPLETED";
break;
case iCalPersonPartStatInProcess:
stat = @"IN-PROCESS";
break;
case iCalPersonPartStatExperimental:
case iCalPersonPartStatOther:
// [NSException raise:NSInternalInconsistencyException
// format:@"Attempt to set meaningless "
// @"participationStatus (%d)!", _status];
stat = nil; /* keep compiler happy */
break;
default:
stat = @"NEEDS-ACTION";
break;
}
if (stat)
[self setPartStat:stat];
}
- (iCalPersonPartStat) participationStatus {
- (iCalPersonPartStat)participationStatus {
NSString *stat;
stat = [[self partStat] uppercaseString];
-1
View File
@@ -75,7 +75,6 @@ extern NSString *iCalWeekDayString[];
- (void) setFrequency: (iCalRecurrenceFrequency) _frequency;
- (iCalRecurrenceFrequency) frequency;
- (iCalRecurrenceFrequency) valueForFrequency: (NSString *) value;
- (NSString *) frequencyForValue: (iCalRecurrenceFrequency) freq;
- (void) setRepeatInterval: (int) _repeatInterval;
- (int) repeatInterval;
+2 -3
View File
@@ -1,6 +1,6 @@
/* iCalTimeZone.m - this file is part of SOPE
*
* Copyright (C) 2006-2015 Inverse inc.
* Copyright (C) 2006-2014 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -147,8 +147,7 @@ static NSArray *knownTimeZones;
if (ext.location != NSNotFound)
{
zone = [zone substringToIndex: ext.location];
if (![timeZoneNames containsObject: zone])
[timeZoneNames addObject: zone];
[timeZoneNames addObject: zone];
}
}
}
-1
View File
@@ -39,7 +39,6 @@
- (NSString *) percentComplete;
- (void) setDue: (NSCalendarDate *) _date;
- (void) setAllDayDue: (NSCalendarDate *) _date;
- (NSCalendarDate *) due;
- (void) setCompleted: (NSCalendarDate *) _date;
-6
View File
@@ -65,12 +65,6 @@
setDateTime: newDueDate];
}
- (void) setAllDayDue: (NSCalendarDate *) newDueDate
{
[(iCalDateTime *) [self uniqueChildWithTag: @"due"]
setDate: newDueDate];
}
- (NSCalendarDate *) due
{
return [(iCalDateTime *) [self uniqueChildWithTag: @"due"]
-2
View File
@@ -34,8 +34,6 @@
- (NSCalendarDate *) nextAlarmDate;
- (NSDictionary *) asDictionary;
@end
#endif /* __NGCards_iCalTrigger_H__ */
-74
View File
@@ -20,9 +20,7 @@
*/
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#import "iCalEvent.h"
#import "iCalTrigger.h"
@@ -54,78 +52,6 @@
return [self value: 0 ofAttribute: @"related"];
}
- (NSDictionary *) asDictionary
{
NSDictionary *data;
NSString *duration, *relation, *reference, *quantity, *unit;
NSUInteger i;
unichar c;
data = nil;
if (![[self valueType] length] ||
[[self valueType] caseInsensitiveCompare: @"DURATION"] == NSOrderedSame)
{
relation = [[self relationType] uppercaseString];
duration = [self flattenedValuesForKey: @""];
i = 0;
c = [duration characterAtIndex: i];
if (c == '-')
{
reference = @"BEFORE";
i++;
}
else
{
reference = @"AFTER";
}
c = [duration characterAtIndex: i];
if (c == 'P')
{
quantity = @"";
unit = @"";
// Parse duration -- ignore first character (P)
for (i++; i < [duration length]; i++)
{
c = [duration characterAtIndex: i];
if (c == 't' || c == 'T')
// time -- ignore character
continue;
else if (isdigit (c))
quantity = [quantity stringByAppendingFormat: @"%c", c];
else
{
switch (c)
{
case 'D': /* day */
unit = @"DAYS";
break;
case 'H': /* hour */
unit = @"HOURS";
break;
case 'M': /* min */
unit = @"MINUTES";
break;
case 'W': /* week */
unit = @"WEEKS";
break;
default:
NSLog(@"Cannot process duration unit: '%c'", c);
break;
}
}
}
}
data = [NSDictionary dictionaryWithObjectsAndKeys:
relation, @"relation",
reference, @"reference",
[NSNumber numberWithInt: [quantity intValue]], @"quantity",
unit, @"unit",
nil];
}
return data;
}
- (NSCalendarDate *) nextAlarmDate
{
NSCalendarDate *relationDate, *nextAlarmDate;
@@ -1075,12 +1075,6 @@ static NSCharacterSet *whitespaceCharSet = nil;
// FIXME: Data is not always utf-8.....
source = [[[NSString alloc] initWithData: _data encoding: encoding]
autorelease];
// We fallback to ISO-8859-1 string encoding
if (!source)
source = [[[NSString alloc] initWithData: _data encoding: NSISOLatin1StringEncoding]
autorelease];
if (!source)
{
e = (id)[SaxParseException exceptionWithName: @"SaxIOException"
-14
View File
@@ -1,14 +0,0 @@
[Unit]
Description=SOGo is a groupware server
After=network.target
[Service]
Environment="PREFORK=3"
EnvironmentFile=-/etc/sysconfig/sogo
Type=forking
ExecStart=/usr/sbin/sogod -WOWorkersCount ${PREFORK} -WOPidFile /var/run/sogo/sogo.pid -WOLogFile /var/log/sogo/sogo.log
PIDFile=/var/run/sogo/sogo.pid
User=sogo
[Install]
WantedBy=multi-user.target
Loaded 100 of 1361 files, more files were not shown because too many files have changed in this diff. Show more