Compare commits

..
Author SHA1 Message Date
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
1771 changed files with 85033 additions and 178205 deletions

No files matched your search

+13 -27
View File
@@ -1,32 +1,18 @@
config.make
tags
*._*
*.css
*.pyc
*.sax
*.swp
*.wox/
*/*/*.SOGo/
*/*/*/obj/
*/*/obj/
*/obj/
.scss-lint-config.yml_
ActiveSync/ActiveSync.SOGo
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/*.js
UI/WebServerResources/js/*.js.map
UI/WebServerResources/js/vendor/*.js
UI/WebServerResources/js/vendor/*.js.map
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
-66
View File
@@ -12,26 +12,20 @@ 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.hr_HR = UI/MailerUI/Croatian.lproj/Localizable.strings
trans.hu = UI/MailerUI/Hungarian.lproj/Localizable.strings
trans.is = UI/MailerUI/Icelandic.lproj/Localizable.strings
trans.it = UI/MailerUI/Italian.lproj/Localizable.strings
trans.mk_MK = UI/MailerUI/Macedonian.lproj/Localizable.strings
trans.nb_NO = UI/MailerUI/NorwegianBokmal.lproj/Localizable.strings
trans.nl = UI/MailerUI/Dutch.lproj/Localizable.strings
trans.nn_NO = UI/MailerUI/NorwegianNynorsk.lproj/Localizable.strings
trans.pl = UI/MailerUI/Polish.lproj/Localizable.strings
trans.pt = UI/MailerUI/Portuguese.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
@@ -44,26 +38,20 @@ 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.hr_HR = UI/PreferencesUI/Croatian.lproj/Localizable.strings
trans.hu = UI/PreferencesUI/Hungarian.lproj/Localizable.strings
trans.is = UI/PreferencesUI/Icelandic.lproj/Localizable.strings
trans.it = UI/PreferencesUI/Italian.lproj/Localizable.strings
trans.mk_MK = UI/PreferencesUI/Macedonian.lproj/Localizable.strings
trans.nb_NO = UI/PreferencesUI/NorwegianBokmal.lproj/Localizable.strings
trans.nl = UI/PreferencesUI/Dutch.lproj/Localizable.strings
trans.nn_NO = UI/PreferencesUI/NorwegianNynorsk.lproj/Localizable.strings
trans.pl = UI/PreferencesUI/Polish.lproj/Localizable.strings
trans.pt = UI/PreferencesUI/Portuguese.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
@@ -76,26 +64,20 @@ 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.hr_HR = UI/Scheduler/Croatian.lproj/Localizable.strings
trans.hu = UI/Scheduler/Hungarian.lproj/Localizable.strings
trans.is = UI/Scheduler/Icelandic.lproj/Localizable.strings
trans.it = UI/Scheduler/Italian.lproj/Localizable.strings
trans.mk_MK = UI/Scheduler/Macedonian.lproj/Localizable.strings
trans.nb_NO = UI/Scheduler/NorwegianBokmal.lproj/Localizable.strings
trans.nl = UI/Scheduler/Dutch.lproj/Localizable.strings
trans.nn_NO = UI/Scheduler/NorwegianNynorsk.lproj/Localizable.strings
trans.pl = UI/Scheduler/Polish.lproj/Localizable.strings
trans.pt = UI/Scheduler/Portuguese.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
@@ -108,26 +90,20 @@ 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.hr_HR = UI/Contacts/Croatian.lproj/Localizable.strings
trans.hu = UI/Contacts/Hungarian.lproj/Localizable.strings
trans.is = UI/Contacts/Icelandic.lproj/Localizable.strings
trans.it = UI/Contacts/Italian.lproj/Localizable.strings
trans.mk_MK = UI/Contacts/Macedonian.lproj/Localizable.strings
trans.nb_NO = UI/Contacts/NorwegianBokmal.lproj/Localizable.strings
trans.nl = UI/Contacts/Dutch.lproj/Localizable.strings
trans.nn_NO = UI/Contacts/NorwegianNynorsk.lproj/Localizable.strings
trans.pl = UI/Contacts/Polish.lproj/Localizable.strings
trans.pt = UI/Contacts/Portuguese.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
@@ -140,26 +116,20 @@ 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.hr_HR = UI/MainUI/Croatian.lproj/Localizable.strings
trans.hu = UI/MainUI/Hungarian.lproj/Localizable.strings
trans.is = UI/MainUI/Icelandic.lproj/Localizable.strings
trans.it = UI/MainUI/Italian.lproj/Localizable.strings
trans.mk_MK = UI/MainUI/Macedonian.lproj/Localizable.strings
trans.nb_NO = UI/MainUI/NorwegianBokmal.lproj/Localizable.strings
trans.nl = UI/MainUI/Dutch.lproj/Localizable.strings
trans.nn_NO = UI/MainUI/NorwegianNynorsk.lproj/Localizable.strings
trans.pl = UI/MainUI/Polish.lproj/Localizable.strings
trans.pt = UI/MainUI/Portuguese.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
@@ -172,26 +142,20 @@ 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.hr_HR = UI/Common/Croatian.lproj/Localizable.strings
trans.hu = UI/Common/Hungarian.lproj/Localizable.strings
trans.is = UI/Common/Icelandic.lproj/Localizable.strings
trans.it = UI/Common/Italian.lproj/Localizable.strings
trans.mk_MK = UI/Common/Macedonian.lproj/Localizable.strings
trans.nb_NO = UI/Common/NorwegianBokmal.lproj/Localizable.strings
trans.nl = UI/Common/Dutch.lproj/Localizable.strings
trans.nn_NO = UI/Common/NorwegianNynorsk.lproj/Localizable.strings
trans.pl = UI/Common/Polish.lproj/Localizable.strings
trans.pt = UI/Common/Portuguese.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
@@ -204,26 +168,20 @@ 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.hr_HR = UI/AdministrationUI/Croatian.lproj/Localizable.strings
trans.hu = UI/AdministrationUI/Hungarian.lproj/Localizable.strings
trans.is = UI/AdministrationUI/Icelandic.lproj/Localizable.strings
trans.it = UI/AdministrationUI/Italian.lproj/Localizable.strings
trans.mk_MK = UI/AdministrationUI/Macedonian.lproj/Localizable.strings
trans.nb_NO = UI/AdministrationUI/NorwegianBokmal.lproj/Localizable.strings
trans.nl = UI/AdministrationUI/Dutch.lproj/Localizable.strings
trans.nn_NO = UI/AdministrationUI/NorwegianNynorsk.lproj/Localizable.strings
trans.pl = UI/AdministrationUI/Polish.lproj/Localizable.strings
trans.pt = UI/AdministrationUI/Portuguese.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
@@ -236,26 +194,20 @@ 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.hr_HR = SoObjects/Appointments/Croatian.lproj/Localizable.strings
trans.hu = SoObjects/Appointments/Hungarian.lproj/Localizable.strings
trans.is = SoObjects/Appointments/Icelandic.lproj/Localizable.strings
trans.it = SoObjects/Appointments/Italian.lproj/Localizable.strings
trans.mk_MK = SoObjects/Appointments/Macedonian.lproj/Localizable.strings
trans.nb_NO = SoObjects/Appointments/NorwegianBokmal.lproj/Localizable.strings
trans.nl = SoObjects/Appointments/Dutch.lproj/Localizable.strings
trans.nn_NO = SoObjects/Appointments/NorwegianNynorsk.lproj/Localizable.strings
trans.pl = SoObjects/Appointments/Polish.lproj/Localizable.strings
trans.pt = SoObjects/Appointments/Portuguese.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
@@ -268,26 +220,20 @@ 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.hr_HR = SoObjects/Contacts/Croatian.lproj/Localizable.strings
trans.hu = SoObjects/Contacts/Hungarian.lproj/Localizable.strings
trans.is = SoObjects/Contacts/Icelandic.lproj/Localizable.strings
trans.it = SoObjects/Contacts/Italian.lproj/Localizable.strings
trans.mk_MK = SoObjects/Contacts/Macedonian.lproj/Localizable.strings
trans.nb_NO = SoObjects/Contacts/NorwegianBokmal.lproj/Localizable.strings
trans.nl = SoObjects/Contacts/Dutch.lproj/Localizable.strings
trans.nn_NO = SoObjects/Contacts/NorwegianNynorsk.lproj/Localizable.strings
trans.pl = SoObjects/Contacts/Polish.lproj/Localizable.strings
trans.pt = SoObjects/Contacts/Portuguese.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
@@ -300,26 +246,20 @@ 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.hr_HR = SoObjects/Mailer/Croatian.lproj/Localizable.strings
trans.hu = SoObjects/Mailer/Hungarian.lproj/Localizable.strings
trans.is = SoObjects/Mailer/Icelandic.lproj/Localizable.strings
trans.it = SoObjects/Mailer/Italian.lproj/Localizable.strings
trans.mk_MK = SoObjects/Mailer/Macedonian.lproj/Localizable.strings
trans.nb_NO = SoObjects/Mailer/NorwegianBokmal.lproj/Localizable.strings
trans.nl = SoObjects/Mailer/Dutch.lproj/Localizable.strings
trans.nn_NO = SoObjects/Mailer/NorwegianNynorsk.lproj/Localizable.strings
trans.pl = SoObjects/Mailer/Polish.lproj/Localizable.strings
trans.pt = SoObjects/Mailer/Portuguese.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
@@ -332,23 +272,17 @@ 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.hr_HR = UI/MailPartViewers/Croatian.lproj/Localizable.strings
trans.hu = UI/MailPartViewers/Hungarian.lproj/Localizable.strings
trans.is = UI/MailPartViewers/Icelandic.lproj/Localizable.strings
trans.it = UI/MailPartViewers/Italian.lproj/Localizable.strings
trans.mk_MK = UI/MailPartViewers/Macedonian.lproj/Localizable.strings
trans.nb_NO = UI/MailPartViewers/NorwegianBokmal.lproj/Localizable.strings
trans.nl = UI/MailPartViewers/Dutch.lproj/Localizable.strings
trans.nn_NO = UI/MailPartViewers/NorwegianNynorsk.lproj/Localizable.strings
trans.pl = UI/MailPartViewers/Polish.lproj/Localizable.strings
trans.pt = UI/MailPartViewers/Portuguese.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
+1 -4
View File
@@ -1,4 +1 @@
ifeq ($(HAS_LIBRARY_ssl),yes)
ADDITIONAL_CPPFLAGS += -DHAVE_OPENSSL=1
BUNDLE_LIBS += -lcrypto
endif
# compilation settings
+1 -1
View File
@@ -101,7 +101,7 @@ static NSArray *asElementArray = nil;
int i, count;
if (!asElementArray)
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", @"Category", @"Exception", nil];
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", @"Category", nil];
data = [NSMutableDictionary dictionary];
+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;
}
+51 -185
View File
@@ -33,7 +33,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSString+misc.h>
@@ -48,42 +47,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@implementation NGVCard (ActiveSync)
//
// This function is called for each elements which can be ghosted according to specs.
// https://msdn.microsoft.com/en-us/library/gg650908%28v=exchg.80%29.aspx
//
- (BOOL) _isGhosted: (NSString *) element
inContext: (WOContext *) context
{
NSArray *supportedElements;
supportedElements = [context objectForKey: @"SupportedElements"];
// If the client does not include a Supported element in the initial Sync command request for
// a folder, then all of the elements that can be ghosted are considered not ghosted.
if (!supportedElements)
return NO;
// If the client includes an empty Supported element in the initial Sync command request for
// a folder, then all elements that can be ghosted are considered ghosted.
if (![supportedElements count])
return YES;
// If the client includes a Supported element that contains child elements in the initial
// Sync command request for a folder, then each child element of that Supported element is
// considered not ghosted. All elements that can be ghosted that are not included as child
// elements of the Supported element are considered ghosted.
if (!([supportedElements indexOfObject: element] == NSNotFound))
return YES;
return NO;
}
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSArray *emails, *addresses, *categories, *elements;
CardElement *n, *homeAdr, *workAdr;
NSMutableString *s, *a;
NSMutableString *s;
NSString *url;
id o;
@@ -94,7 +62,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ((o = [n flattenedValueAtIndex: 0 forKey: @""]))
[s appendFormat: @"<LastName xmlns=\"Contacts:\">%@</LastName>", [o activeSyncRepresentationInContext: context]];
if ((o = [n flattenedValueAtIndex: 1 forKey: @""]))
[s appendFormat: @"<FirstName xmlns=\"Contacts:\">%@</FirstName>", [o activeSyncRepresentationInContext: context]];
@@ -177,22 +145,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ([addresses count])
{
homeAdr = [addresses objectAtIndex: 0];
a = [NSMutableString string];
if ((o = [homeAdr flattenedValueAtIndex: 2 forKey: @""]))
[a appendString: o];
if ((o = [homeAdr flattenedValueAtIndex: 1 forKey: @""]) && [o length])
[a appendFormat: @"\n%@", o];
[s appendFormat: @"<HomeStreet xmlns=\"Contacts:\">%@</HomeStreet>", [o activeSyncRepresentationInContext: context]];
[s appendFormat: @"<HomeStreet xmlns=\"Contacts:\">%@</HomeStreet>", [a activeSyncRepresentationInContext: context]];
if ((o = [homeAdr flattenedValueAtIndex: 3 forKey: @""]))
[s appendFormat: @"<HomeCity xmlns=\"Contacts:\">%@</HomeCity>", [o activeSyncRepresentationInContext: context]];
if ((o = [homeAdr flattenedValueAtIndex: 4 forKey: @""]))
[s appendFormat: @"<HomeState xmlns=\"Contacts:\">%@</HomeState>", [o activeSyncRepresentationInContext: context]];
if ((o = [homeAdr flattenedValueAtIndex: 5 forKey: @""]))
[s appendFormat: @"<HomePostalCode xmlns=\"Contacts:\">%@</HomePostalCode>", [o activeSyncRepresentationInContext: context]];
@@ -208,15 +170,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ([addresses count])
{
workAdr = [addresses objectAtIndex: 0];
a = [NSMutableString string];
if ((o = [workAdr flattenedValueAtIndex: 2 forKey: @""]))
[a appendString: o];
if ((o = [workAdr flattenedValueAtIndex: 1 forKey: @""]) && [o length])
[a appendFormat: @"\n%@", o];
[s appendFormat: @"<BusinessStreet xmlns=\"Contacts:\">%@</BusinessStreet>", [a activeSyncRepresentationInContext: context]];
[s appendFormat: @"<BusinessStreet xmlns=\"Contacts:\">%@</BusinessStreet>", [o activeSyncRepresentationInContext: context]];
if ((o = [workAdr flattenedValueAtIndex: 3 forKey: @""]))
[s appendFormat: @"<BusinessCity xmlns=\"Contacts:\">%@</BusinessCity>", [o activeSyncRepresentationInContext: context]];
@@ -237,12 +193,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ((o = [self note]))
{
// 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];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
@@ -260,7 +215,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inContext: (WOContext *) context
{
CardElement *element;
NSMutableArray *addressLines;
id o;
// Contact's note
@@ -270,20 +224,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Categories
if ((o = [theValues objectForKey: @"Categories"]) && [o length])
[self setCategories: o];
else
[[self children] removeObjectsInArray: [self childrenWithTag: @"Categories"]];
// Birthday
if ((o = [theValues objectForKey: @"Birthday"]))
{
o = [o calendarDate];
[self setBday: [o descriptionWithCalendarFormat: @"%Y-%m-%d" timeZone: nil locale: nil]];
[self setBday: [o descriptionWithCalendarFormat: @"%Y-%m-%d"]];
}
else if (![self _isGhosted: @"Birthday" inContext: context])
{
[self setBday: @""];
}
//
// Business address information
@@ -295,48 +242,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// BusinessCountry
//
element = [self elementWithTag: @"adr" ofType: @"work"];
if ((o = [theValues objectForKey: @"BusinessStreet"]) || ![self _isGhosted: @"BusinessStreet" inContext: context])
{
addressLines = [NSMutableArray arrayWithArray: [o componentsSeparatedByString: @"\n"]];
[element setSingleValue: @""
atIndex: 1 forKey: @""];
[element setSingleValue: [addressLines count] ? [addressLines objectAtIndex: 0] : @""
atIndex: 2 forKey: @""];
// Extended address line. If there are more than 2 address lines we add them to the extended address line.
if ([addressLines count] > 1)
{
[addressLines removeObjectAtIndex: 0];
[element setSingleValue: [addressLines componentsJoinedByString: @" "]
atIndex: 1 forKey: @""];
}
}
if ((o = [theValues objectForKey: @"BusinessCity"]) || ![self _isGhosted: @"BusinessCity" inContext: context])
{
[element setSingleValue: [theValues objectForKey: @"BusinessCity"]
atIndex: 3 forKey: @""];
}
if ((o = [theValues objectForKey: @"BusinessState"]) || ![self _isGhosted: @"BusinessState" inContext: context])
{
[element setSingleValue: [theValues objectForKey: @"BusinessState"]
atIndex: 4 forKey: @""];
}
if ((o = [theValues objectForKey: @"BusinessPostalCode"]) || ![self _isGhosted: @"BusinessPostalCode" inContext: context])
{
[element setSingleValue: [theValues objectForKey: @"BusinessPostalCode"]
atIndex: 5 forKey: @""];
}
if ((o = [theValues objectForKey: @"BusinessCountry"]) || ![self _isGhosted: @"BusinessCountry" inContext: context])
{
[element setSingleValue: [theValues objectForKey: @"BusinessCountry"]
atIndex: 6 forKey: @""];
}
[element setSingleValue: @""
atIndex: 1 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"BusinessStreet"]
atIndex: 2 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"BusinessCity"]
atIndex: 3 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"BusinessState"]
atIndex: 4 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"BusinessPostalCode"]
atIndex: 5 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"BusinessCountry"]
atIndex: 6 forKey: @""];
//
// Home address information
@@ -348,69 +265,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// HomeCountry
//
element = [self elementWithTag: @"adr" ofType: @"home"];
if ((o = [theValues objectForKey: @"HomeStreet"]) || ![self _isGhosted: @"HomeStreet" inContext: context])
{
addressLines = [NSMutableArray arrayWithArray: [o componentsSeparatedByString: @"\n"]];
[element setSingleValue: @""
atIndex: 1 forKey: @""];
[element setSingleValue: [addressLines count] ? [addressLines objectAtIndex: 0] : @""
atIndex: 2 forKey: @""];
// Extended address line. If there are more then 2 address lines we add them to the extended address line.
if ([addressLines count] > 1)
{
[addressLines removeObjectAtIndex: 0];
[element setSingleValue: [addressLines componentsJoinedByString: @" "]
atIndex: 1 forKey: @""];
}
}
if ((o = [theValues objectForKey: @"HomeCity"]) || ![self _isGhosted: @"HomeCity" inContext: context])
{
[element setSingleValue: [theValues objectForKey: @"HomeCity"]
atIndex: 3 forKey: @""];
}
if ((o = [theValues objectForKey: @"HomeState"]) || ![self _isGhosted: @"HomeState" inContext: context])
{
[element setSingleValue: [theValues objectForKey: @"HomeState"]
atIndex: 4 forKey: @""];
}
if ((o = [theValues objectForKey: @"HomePostalCode"]) || ![self _isGhosted: @"HomePostalCode" inContext: context])
{
[element setSingleValue: [theValues objectForKey: @"HomePostalCode"]
atIndex: 5 forKey: @""];
}
if ((o = [theValues objectForKey: @"HomeCountry"]) || ![self _isGhosted: @"HomeCountry" inContext: context])
{
[element setSingleValue: [theValues objectForKey: @"HomeCountry"]
atIndex: 6 forKey: @""];
}
[element setSingleValue: @""
atIndex: 1 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"HomeStreet"]
atIndex: 2 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"HomeCity"]
atIndex: 3 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"HomeState"]
atIndex: 4 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"HomePostalCode"]
atIndex: 5 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"HomeCountry"]
atIndex: 6 forKey: @""];
// Company's name
if ((o = [theValues objectForKey: @"CompanyName"]))
[self setOrg: o units: nil];
else if (![self _isGhosted: @"CompanyName" inContext: context])
[self setOrg: @"" units: nil];
// Department
if ((o = [theValues objectForKey: @"Department"]))
[self setOrg: nil units: [NSArray arrayWithObjects:o,nil]];
else if (![self _isGhosted: @"Department" inContext: context])
[self setOrg: nil units: [NSArray arrayWithObjects:@"",nil]];
// Email addresses
if ((o = [theValues objectForKey: @"Email1Address"]) || ![self _isGhosted: @"Email1Address" inContext: context])
if ((o = [theValues objectForKey: @"Email1Address"]))
{
element = [self elementWithTag: @"email" ofType: @"work"];
[element setSingleValue: [o pureEMailAddress] forKey: @""];
}
if ((o = [theValues objectForKey: @"Email2Address"]) || ![self _isGhosted: @"Email2Address" inContext: context])
if ((o = [theValues objectForKey: @"Email2Address"]))
{
element = [self elementWithTag: @"email" ofType: @"home"];
[element setSingleValue: [o pureEMailAddress] forKey: @""];
@@ -418,7 +301,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// SOGo currently only supports 2 email addresses ... but AS clients might send 3
// FIXME: revise this when the GUI revamp is done in SOGo
if ((o = [theValues objectForKey: @"Email3Address"]) || ![self _isGhosted: @"Email3Address" inContext: context])
if ((o = [theValues objectForKey: @"Email3Address"]))
{
element = [self elementWithTag: @"email" ofType: @"three"];
[element setSingleValue: [o pureEMailAddress] forKey: @""];
@@ -428,62 +311,45 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// MiddleName
// Suffix (II)
// Title (Mr.)
if ((o = [theValues objectForKey: @"FileAs"]) || ![self _isGhosted: @"FileAs" inContext: context])
[self setFn: [theValues objectForKey: @"FileAs"]];
[self setFn: [theValues objectForKey: @"FileAs"]];
[self setNWithFamily: [theValues objectForKey: @"LastName"]
given: [theValues objectForKey: @"FirstName"]
additional: nil prefixes: nil suffixes: nil];
// IM information
if ((o = [theValues objectForKey: @"IMAddress"]) || ![self _isGhosted: @"IMAddress" inContext: context])
[[self uniqueChildWithTag: @"x-aim"]
setSingleValue: [theValues objectForKey: @"IMAddress"]
forKey: @""];
[[self uniqueChildWithTag: @"x-aim"]
setSingleValue: [theValues objectForKey: @"IMAddress"]
forKey: @""];
//
// Phone numbrrs
//
if ((o = [theValues objectForKey: @"BusinessPhoneNumber"]) || ![self _isGhosted: @"BusinessPhoneNumber" inContext: context])
{
element = [self elementWithTag: @"tel" ofType: @"work"];
[element setSingleValue: [theValues objectForKey: @"BusinessPhoneNumber"] forKey: @""];
}
element = [self elementWithTag: @"tel" ofType: @"work"];
[element setSingleValue: [theValues objectForKey: @"BusinessPhoneNumber"] forKey: @""];
if ((o = [theValues objectForKey: @"HomePhoneNumber"]) || ![self _isGhosted: @"HomePhoneNumber" inContext: context])
{
element = [self elementWithTag: @"tel" ofType: @"home"];
[element setSingleValue: [theValues objectForKey: @"HomePhoneNumber"] forKey: @""];
}
element = [self elementWithTag: @"tel" ofType: @"home"];
[element setSingleValue: [theValues objectForKey: @"HomePhoneNumber"] forKey: @""];
if ((o = [theValues objectForKey: @"MobilePhoneNumber"]) || ![self _isGhosted: @"MobilePhoneNumber" inContext: context])
{
element = [self elementWithTag: @"tel" ofType: @"cell"];
[element setSingleValue: [theValues objectForKey: @"MobilePhoneNumber"] forKey: @""];
}
element = [self elementWithTag: @"tel" ofType: @"cell"];
[element setSingleValue: [theValues objectForKey: @"MobilePhoneNumber"] forKey: @""];
if ((o = [theValues objectForKey: @"BusinessFaxNumber"]) || ![self _isGhosted: @"BusinessFaxNumber" inContext: context])
{
element = [self elementWithTag: @"tel" ofType: @"fax"];
[element setSingleValue: [theValues objectForKey: @"BusinessFaxNumber"] forKey: @""];
}
element = [self elementWithTag: @"tel" ofType: @"fax"];
[element setSingleValue: [theValues objectForKey: @"BusinessFaxNumber"] forKey: @""];
if ((o = [theValues objectForKey: @"PagerNumber"]) || ![self _isGhosted: @"PagerNumber" inContext: context])
{
element = [self elementWithTag: @"tel" ofType: @"pager"];
[element setSingleValue: [theValues objectForKey: @"PagerNumber"] forKey: @""];
}
element = [self elementWithTag: @"tel" ofType: @"pager"];
[element setSingleValue: [theValues objectForKey: @"PagerNumber"] forKey: @""];
// Job's title
if ((o = [theValues objectForKey: @"JobTitle"]) || ![self _isGhosted: @"JobTitle" inContext: context])
if ((o = [theValues objectForKey: @"JobTitle"]))
[self setTitle: o];
// WebPage (work)
if ((o = [theValues objectForKey: @"WebPage"]) || ![self _isGhosted: @"WebPage" inContext: context])
if ((o = [theValues objectForKey: @"WebPage"]))
[[self elementWithTag: @"url" ofType: @"work"]
setSingleValue: o forKey: @""];
if ((o = [theValues objectForKey: @"NickName"]) || ![self _isGhosted: @"NickName" inContext: context])
if ((o = [theValues objectForKey: @"NickName"]))
[self setNickname: o];
if ((o = [theValues objectForKey: @"Picture"]))
+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
+8 -139
View File
@@ -33,7 +33,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <Foundation/NSCalendarDate.h>
#include <Foundation/NSData.h>
#include <Foundation/NSDate.h>
#include <Foundation/NSTimeZone.h>
#include <SOGo/NSString+Utilities.h>
#include <SOGo/NSData+Crypto.h>
@@ -46,99 +45,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] < 0x20 || 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 +64,11 @@ static NSArray *easCommandParameters = nil;
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
return [self _stringByEscapingXMLStringUsingCharacters];
NSString *s;
s = [self safeString];
return [s stringByEscapingHTMLString];
}
- (int) activeSyncFolderType
@@ -217,17 +127,13 @@ static NSArray *easCommandParameters = nil;
//
- (NSCalendarDate *) calendarDate
{
NSString *s;
id o;
// We force parsing in the GMT timezone. If we don't do that, the date will be parsed
// in the default timezone.
s = [NSString stringWithFormat: @"%@ GMT", self];
o = [NSCalendarDate dateWithString: s calendarFormat: @"%Y%m%dT%H%M%SZ %Z"];
o = [NSCalendarDate dateWithString: self calendarFormat: @"%Y%m%dT%H%M%SZ"];
if (!o)
o = [NSCalendarDate dateWithString: s calendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ %Z"];
o = [NSCalendarDate dateWithString: self calendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ"];
return o;
}
@@ -387,43 +293,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.
//
+1 -1
View File
@@ -4,7 +4,7 @@ to negotiate the fees associated to your user base.
To contact Microsoft, please visit:
http://www.microsoft.com/en-us/legal/intellectualproperty/
http://www.microsoft.com/en-us/legal/intellectualproperty/IPLicensing/Programs/exchangeactivesyncprotocol.aspx
and send an email to iplicreq@microsoft.com
File diff suppressed because it is too large. Load diff
+1 -11
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
@@ -31,25 +31,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "SOGoActiveSyncConstants.h"
@class NSCalendarDate;
@class NSException;
@class NSMutableDictionary;
@class NSURL;
@class NSNumber;
@interface SOGoActiveSyncDispatcher : NSObject
{
NSURL *folderTableURL;
NSDictionary *imapFolderGUIDS;
id context;
NSNumber *syncRequest;
BOOL debugOn;
}
- (NSMutableDictionary *) globalMetadataForDevice;
- (id) collectionFromId: (NSString *) theCollectionId
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType;
File diff suppressed because it is too large. Load diff
+79 -494
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];
}
@@ -373,7 +282,7 @@ struct GlobalObjectId {
performed: b];
}
}
else if ([thePart isKindOfClass: [NGMimeBodyPart class]] || [thePart isKindOfClass: [NGMimeMessage class]])
else if ([thePart isKindOfClass: [NGMimeBodyPart class]])
{
NGMimeFileData *fdata;
id body;
@@ -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];
}
@@ -456,7 +366,8 @@ struct GlobalObjectId {
if (message)
{
[self _sanitizedMIMEPart: message performed: &b];
[self _sanitizedMIMEPart: [message body]
performed: &b];
if (b)
{
@@ -472,46 +383,18 @@ struct GlobalObjectId {
return d;
}
//
//
//
- (BOOL) _sanitinizeNeeded: (NSArray *) theParts
{
NSString *encoding, *charset;
int i;
for (i = 0; i < [theParts count]; i++)
{
encoding = [[theParts objectAtIndex: i ] objectForKey: @"encoding"];
charset = [[[theParts objectAtIndex: i ] objectForKey: @"parameterList"] objectForKey: @"charset"];
if (encoding && [encoding caseInsensitiveCompare: @"8bit"] == NSOrderedSame &&
charset && ![charset caseInsensitiveCompare: @"utf-8"] == NSOrderedSame
&& ![charset caseInsensitiveCompare: @"us-ascii"] == NSOrderedSame)
{
return YES;
}
if ([self _sanitinizeNeeded: [[theParts objectAtIndex: i ] objectForKey: @"parts"]])
return YES;
}
return NO;
}
//
//
//
- (NSData *) _preferredBodyDataUsingType: (int) theType
mimeSupport: (int) theMimeSupport
nativeType: (int *) theNativeType
{
NSString *type, *subtype, *encoding;
NSData *d;
BOOL isSMIME, sanitinizeNeeded;
type = [[[self bodyStructure] valueForKey: @"type"] lowercaseString];
subtype = [[[self bodyStructure] valueForKey: @"subtype"] lowercaseString];
isSMIME = NO;
d = nil;
// We determine the native type
@@ -522,23 +405,17 @@ struct GlobalObjectId {
else if ([type isEqualToString: @"multipart"])
*theNativeType = 4;
if (([subtype isEqualToString: @"signed"] || [subtype isEqualToString: @"pkcs7-mime"] ) && theMimeSupport > 0)
{
*theNativeType = 4;
isSMIME = YES;
}
// We get the right part based on the preference
if ((theType == 1 || theType == 2) && !isSMIME)
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: @""];
@@ -552,30 +429,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 || isSMIME)
else if (theType == 4)
{
// We sanitize the content if the content-transfer-encoding is 8bit and charset is not utf-8 or us-ascii.
sanitinizeNeeded = [self _sanitinizeNeeded: [NSArray arrayWithObject: [self bodyStructure]]];
if (sanitinizeNeeded && !isSMIME)
// We sanitize the content *ONLY* for Outlook clients. Outlook has strange issues
// with quoted-printable/base64 encoded text parts. It just doesn't decode them.
if ([[context objectForKey: @"DeviceType"] isEqualToString: @"WindowsOutlook15"])
d = [self _sanitizedMIMEMessage];
else
d = [self content];
@@ -584,65 +456,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"];
@@ -690,18 +512,12 @@ struct GlobalObjectId {
{
NSData *d, *globalObjId;
NSArray *attachmentKeys;
iCalCalendar *calendar;
NSString *p, *subtype;
NSMutableString *s;
id value;
iCalCalendar *calendar;
int preferredBodyType, mimeSupport, nativeBodyType;
uint32_t v;
subtype = [[[self bodyStructure] valueForKey: @"subtype"] lowercaseString];
preferredBodyType = [[context objectForKey: @"BodyPreferenceType"] intValue];
mimeSupport = [[context objectForKey: @"MIMESupport"] intValue];
int preferredBodyType, nativeBodyType;
s = [NSMutableString string];
@@ -721,7 +537,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
@@ -737,34 +553,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)];
@@ -828,18 +618,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];
@@ -887,9 +677,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
@@ -898,12 +686,7 @@ struct GlobalObjectId {
else
{
// MesssageClass and ContentClass
if ([subtype isEqualToString: @"signed"])
[s appendFormat: @"<MessageClass xmlns=\"Email:\">%@</MessageClass>", @"IPM.Note.SMIME.MultipartSigned"];
else if ([subtype isEqualToString: @"pkcs7-mime"])
[s appendFormat: @"<MessageClass xmlns=\"Email:\">%@</MessageClass>", @"IPM.Note.SMIME"];
else
[s appendFormat: @"<MessageClass xmlns=\"Email:\">%@</MessageClass>", @"IPM.Note"];
[s appendFormat: @"<MessageClass xmlns=\"Email:\">%@</MessageClass>", @"IPM.Note"];
[s appendFormat: @"<ContentClass xmlns=\"Email:\">%@</ContentClass>", @"urn:content-classes:message"];
}
@@ -917,82 +700,17 @@ struct GlobalObjectId {
[s appendFormat: @"<InternetCPID xmlns=\"Email:\">%@</InternetCPID>", @"65001"];
// Body - namespace 17
preferredBodyType = [[context objectForKey: @"BodyPreferenceType"] intValue];
nativeBodyType = 1;
d = [self _preferredBodyDataUsingType: preferredBodyType mimeSupport: mimeSupport 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];
}
}
d = [self _preferredBodyDataUsingType: preferredBodyType nativeType: &nativeBodyType];
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
@@ -1002,57 +720,36 @@ 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.
// For s/mime mails type is always 4 if mimeSupport is 1 or 2.
if (preferredBodyType == 2 && nativeBodyType == 1)
[s appendString: @"<Type>1</Type>"];
else if (([subtype isEqualToString: @"signed"] || [subtype isEqualToString: @"pkcs7-mime"] ) && mimeSupport > 0)
[s appendString: @"<Type>4</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
attachmentKeys = [self fetchFileAttachmentKeys];
if ([attachmentKeys count] && !([subtype isEqualToString: @"signed"]))
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];
@@ -1063,22 +760,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>"];
}
@@ -1089,52 +775,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"])
{
id value;
NSString *reference;
value = [[self mailHeaders] objectForKey: @"references"];
if ([value isKindOfClass: [NSArray class]])
reference = [[[value objectAtIndex: 0] componentsSeparatedByString: @" "] objectAtIndex: 0];
else
reference = [[value componentsSeparatedByString: @" "] objectAtIndex: 0];
if ([reference length] > 0)
[s appendFormat: @"<ConversationId xmlns=\"Email2:\">%@</ConversationId>", [[reference dataUsingEncoding: NSUTF8StringEncoding] activeSyncRepresentationInContext: context]];
else if ([[self inReplyTo] length] > 0)
[s appendFormat: @"<ConversationId xmlns=\"Email2:\">%@</ConversationId>", [[[self inReplyTo] dataUsingEncoding: NSUTF8StringEncoding] activeSyncRepresentationInContext: context]];
else if ([[self messageId] length] > 0)
[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.
@@ -1193,65 +837,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
-1
View File
@@ -37,7 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@interface SOGoSyncCacheObject : NSObject
{
@public
id _uid;
id _sequence;
}
+14 -23
View File
@@ -32,17 +32,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSNull.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
static Class NSNullK;
@implementation SOGoSyncCacheObject
+ (void) initialize
{
NSNullK = [NSNull class];
}
- (id) init
{
if ((self = [super init]))
@@ -54,16 +46,16 @@ static Class NSNullK;
return self;
}
+ (id) syncCacheObjectWithUID: (id) theUID sequence: (id) theSequence
+ (id) syncCacheObjectWithUID: (id) theUID sequence: (id) theSequence;
{
id o;
o = [[self alloc] init];
[o setUID: [NSNumber numberWithInt: [theUID intValue]]];
[o setSequence: ([theSequence isKindOfClass: NSNullK] ? theSequence : [NSNumber numberWithInt: [theSequence intValue]])];
[o setUID: theUID];
[o setSequence: theSequence];
return [o autorelease];
return o;
}
- (void) dealloc
@@ -75,7 +67,7 @@ static Class NSNullK;
- (id) uid
{
return [_uid description];
return _uid;
}
- (void) setUID: (id) theUID
@@ -85,7 +77,7 @@ static Class NSNullK;
- (id) sequence
{
return ([_sequence isKindOfClass: NSNullK] ? _sequence : [_sequence description]);
return _sequence;
}
- (void) setSequence: (id) theSequence
@@ -96,7 +88,7 @@ static Class NSNullK;
- (NSComparisonResult) compareUID: (SOGoSyncCacheObject *) theSyncCacheObject
{
return [self->_uid compare: theSyncCacheObject->_uid];
return [[self uid] compare: [theSyncCacheObject uid]];
}
//
@@ -105,21 +97,21 @@ static Class NSNullK;
//
- (NSComparisonResult) compareSequence: (SOGoSyncCacheObject *) theSyncCacheObject
{
if ([self->_sequence isEqual: [NSNull null]] &&
[theSyncCacheObject->_sequence isEqual: [NSNull null]])
if ([[self sequence] isEqual: [NSNull null]] &&
[[theSyncCacheObject sequence] isEqual: [NSNull null]])
return [self compareUID: theSyncCacheObject];
if (![self->_sequence isEqual: [NSNull null]] && [theSyncCacheObject->_sequence isEqual: [NSNull null]])
if (![[self sequence] isEqual: [NSNull null]] && [[theSyncCacheObject sequence] isEqual: [NSNull null]])
return NSOrderedDescending;
if ([self->_sequence isEqual: [NSNull null]] && ![theSyncCacheObject->_sequence isEqual: [NSNull null]])
if ([[self sequence] isEqual: [NSNull null]] && ![[theSyncCacheObject sequence] isEqual: [NSNull null]])
return NSOrderedAscending;
// Must check this here, to avoid comparing NSNull objects
if ([self->_sequence compare: theSyncCacheObject->_sequence] == NSOrderedSame)
if ([[self sequence] compare: [theSyncCacheObject sequence]] == NSOrderedSame)
return [self compareUID: theSyncCacheObject];
return [self->_sequence compare: theSyncCacheObject->_sequence];
return [[self sequence] compare: [theSyncCacheObject sequence]];
}
- (NSString *) description
@@ -128,4 +120,3 @@ static Class NSNullK;
}
@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"];
}
+1 -1
View File
@@ -20,7 +20,7 @@ ADDITIONAL_LIB_DIRS += \
-L../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR)/ \
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \
-L/usr/local/lib \
-Wl,-rpath,$(SOGO_SYSLIBDIR)/sogo
-Wl,-rpath,$(GNUSTEP_SYSTEM_LIBRARIES)/sogo
BUNDLE_LIBS += \
-lSOGo \
+1 -1
View File
@@ -58,7 +58,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// don't send negative reminder - not supported
if (delta > 0)
[s appendFormat: @"<Reminder xmlns=\"Calendar:\">%d</Reminder>", (int)delta];
[s appendFormat: @"<Reminder xmlns=\"Calendar:\">%d</Reminder>", delta];
}
return s;
+1 -3
View File
@@ -41,9 +41,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
- (void) changeParticipationStatus: (NSDictionary *) theValues
inContext: (WOContext *) context
component: (id) component;
@end
#endif
+70 -416
View File
@@ -38,26 +38,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSString+misc.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WORequest.h>
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalDateTime.h>
#import <NGCards/iCalPerson.h>
#import <NGCards/NSCalendarDate+NGCards.h>
#import <NGCards/NSString+NGCards.h>
#import <NGCards/iCalCalendar.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/WORequest+SOGo.h>
#import <Appointments/iCalEntityObject+SOGo.h>
#import <Appointments/iCalRepeatableEntityObject+SOGo.h>
#import <Appointments/SOGoAppointmentObject.h>
#include "iCalAlarm+ActiveSync.h"
#include "iCalRecurrenceRule+ActiveSync.h"
@@ -85,13 +76,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSMutableString *s;
NSArray *attendees, *categories;
NSArray *attendees;
iCalPerson *organizer, *attendee;
iCalTimeZone *tz;
id o;
int v, i, meetingStatus;
int v;
NSTimeZone *userTimeZone;
userTimeZone = [[[context activeUser] userDefaults] timeZone];
@@ -106,13 +97,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else if ([self created])
[s appendFormat: @"<DTStamp xmlns=\"Calendar:\">%@</DTStamp>", [[self created] activeSyncRepresentationWithoutSeparatorsInContext: context]];
// Timezone
tz = [(iCalDateTime *)[self firstChildWithTag: @"dtstart"] timeZone];
// StartTime -- http://msdn.microsoft.com/en-us/library/ee157132(v=exchg.80).aspx
if ([self startDate])
{
if ([self isAllDay] && !tz)
if ([self isAllDay])
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>",
[[[self startDate] dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
@@ -125,7 +113,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// EndTime -- http://msdn.microsoft.com/en-us/library/ee157945(v=exchg.80).aspx
if ([self endDate])
{
if ([self isAllDay] && !tz)
if ([self isAllDay])
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>",
[[[self endDate] dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
@@ -135,18 +123,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>", [[self endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
}
// Timezone
tz = [(iCalDateTime *)[self firstChildWithTag: @"dtstart"] timeZone];
if (!tz)
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
if (![self recurrenceId])
[s appendFormat: @"<TimeZone xmlns=\"Calendar:\">%@</TimeZone>", [tz activeSyncRepresentationInContext: context]];
[s appendFormat: @"<TimeZone xmlns=\"Calendar:\">%@</TimeZone>", [tz activeSyncRepresentationInContext: context]];
// Organizer and other invitations related properties
if ((organizer = [self organizer]))
{
meetingStatus = 1; // meeting and the user is the meeting organizer.
o = [organizer rfc822Email];
if (![self recurrenceId] && [o length])
if ([o length])
{
[s appendFormat: @"<Organizer_Email xmlns=\"Calendar:\">%@</Organizer_Email>", o];
@@ -170,7 +159,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendString: @"<Attendee xmlns=\"Calendar:\">"];
attendee = [attendees objectAtIndex: i];
[s appendFormat: @"<Attendee_Email xmlns=\"Calendar:\">%@</Attendee_Email>", [[attendee rfc822Email] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<Attendee_Email xmlns=\"Calendar:\">%@</Attendee_Email>", [attendee rfc822Email]];
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee cn] activeSyncRepresentationInContext: context]];
attendee_status = [self _attendeeStatus: attendee];
@@ -188,10 +177,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
[s appendString: @"</Attendees>"];
}
else
{
meetingStatus = 0; // appointment
}
// This depends on the 'NEEDS-ACTION' parameter.
// This will trigger the SendMail command
@@ -201,21 +186,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
int attendee_status;
meetingStatus = 3; // event is a meeting, and the user is not the meeting organizer
attendee = [self userAsAttendee: [context activeUser]];
attendee_status = [self _attendeeStatus: attendee];
[s appendFormat: @"<ResponseRequested xmlns=\"Calendar:\">%d</ResponseRequested>", 1];
[s appendFormat: @"<ResponseType xmlns=\"Calendar:\">%d</ResponseType>", attendee_status];
[s appendFormat: @"<MeetingStatus xmlns=\"Calendar:\">%d</MeetingStatus>", 3];
[s appendFormat: @"<DisallowNewTimeProposal xmlns=\"Calendar:\">%d</DisallowNewTimeProposal>", 1];
// BusyStatus -- http://msdn.microsoft.com/en-us/library/ee202290(v=exchg.80).aspx
[s appendFormat: @"<BusyStatus xmlns=\"Calendar:\">%d</BusyStatus>", 2];
}
[s appendFormat: @"<MeetingStatus xmlns=\"Calendar:\">%d</MeetingStatus>", meetingStatus];
// Subject -- http://msdn.microsoft.com/en-us/library/ee157192(v=exchg.80).aspx
if ([[self summary] length])
[s appendFormat: @"<Subject xmlns=\"Calendar:\">%@</Subject>", [[self summary] activeSyncRepresentationInContext: context]];
@@ -235,59 +217,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//[s appendFormat: @"<Importance xmlns=\"Calendar:\">%d</Importance>", v];
// UID -- http://msdn.microsoft.com/en-us/library/ee159919(v=exchg.80).aspx
if (![self recurrenceId] && [[self uid] length])
[s appendFormat: @"<UID xmlns=\"Calendar:\">%@</UID>", [[self uid] activeSyncRepresentationInContext: context]];
// Recurrence rules
if ([self isRecurrent])
[s appendString: [[[self recurrenceRules] lastObject] activeSyncRepresentationInContext: context]];
// Comment
o = [self comment];
//if (![self recurrenceId] && [o length])
if ([o length])
{
// 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>", (int)[o length]];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
}
if ([[self uid] length])
[s appendFormat: @"<UID xmlns=\"Calendar:\">%@</UID>", [self uid]];
// Sensitivity
if ([[self accessClass] isEqualToString: @"PRIVATE"])
v = 2;
else if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
v = 3;
else
v = 0;
[s appendFormat: @"<Sensitivity xmlns=\"Calendar:\">%d</Sensitivity>", v];
categories = [self categories];
if ([categories count])
{
[s appendFormat: @"<Categories xmlns=\"Calendar:\">"];
for (i = 0; i < [categories count]; i++)
{
[s appendFormat: @"<Category xmlns=\"Calendar:\">%@</Category>", [[categories objectAtIndex: i] activeSyncRepresentationInContext: context]];
}
[s appendFormat: @"</Categories>"];
}
// Reminder -- http://msdn.microsoft.com/en-us/library/ee219691(v=exchg.80).aspx
// TODO: improve this to handle more alarm types
if ([self hasAlarms])
@@ -298,79 +240,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendString: [alarm activeSyncRepresentationInContext: context]];
}
// Exceptions
// Recurrence rules
if ([self isRecurrent])
{
NSMutableArray *components, *exdates;
iCalEvent *current_component;
NSString *recurrence_id;
unsigned int count, max, i;
components = [NSMutableArray arrayWithArray: [[self parent] events]];
max = [components count];
if (max > 1 || [self hasExceptionDates])
{
exdates = [NSMutableArray arrayWithArray: [self exceptionDates]];
[s appendString: @"<Exceptions xmlns=\"Calendar:\">"];
for (count = 1; count < max; count++)
{
current_component = [components objectAtIndex: count] ;
if ([self isAllDay])
{
recurrence_id = [NSString stringWithFormat: @"%@",
[[[current_component recurrenceId] dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -[userTimeZone secondsFromGMTForDate:
[current_component recurrenceId]]]
activeSyncRepresentationWithoutSeparatorsInContext: context]];
}
else
{
recurrence_id = [NSString stringWithFormat: @"%@", [[current_component recurrenceId]
activeSyncRepresentationWithoutSeparatorsInContext: context]];
}
[s appendString: @"<Exception>"];
[s appendFormat: @"<Exception_StartTime xmlns=\"Calendar:\">%@</Exception_StartTime>", recurrence_id];
[s appendFormat: @"%@", [current_component activeSyncRepresentationInContext: context]];
[s appendString: @"</Exception>"];
}
for (i = 0; i < [exdates count]; i++)
{
[s appendString: @"<Exception>"];
[s appendString: @"<Exception_Deleted>1</Exception_Deleted>"];
if ([self isAllDay])
{
recurrence_id = [NSString stringWithFormat: @"%@",
[[[[exdates objectAtIndex: i] asCalendarDate] dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -[userTimeZone secondsFromGMTForDate:
[[exdates objectAtIndex: i] asCalendarDate]]]
activeSyncRepresentationWithoutSeparatorsInContext: context]];
}
else
{
recurrence_id = [NSString stringWithFormat: @"%@", [[[exdates objectAtIndex: i] asCalendarDate]
activeSyncRepresentationWithoutSeparatorsInContext: context]];
}
[s appendFormat: @"<Exception_StartTime xmlns=\"Calendar:\">%@</Exception_StartTime>", recurrence_id];
[s appendString: @"</Exception>"];
}
[s appendString: @"</Exceptions>"];
}
[s appendString: [[[self recurrenceRules] lastObject] activeSyncRepresentationInContext: context]];
}
if (![self recurrenceId])
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
// Comment
o = [self comment];
if ([o length])
{
o = [o activeSyncRepresentationInContext: context];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
return s;
}
@@ -416,19 +305,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context
{
iCalDateTime *start, *end; //, *oldstart;
NSCalendarDate *oldstart;
iCalDateTime *start, *end;
NSTimeZone *userTimeZone;
iCalTimeZone *tz;
id o;
int deltasecs;
NSInteger tzOffset;
BOOL isAllDay;
NSMutableArray *occurences;
occurences = [NSMutableArray arrayWithArray: [[self parent] events]];
if ((o = [theValues objectForKey: @"UID"]))
[self setUid: o];
@@ -441,11 +325,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
isAllDay = YES;
}
else if ([occurences count] && !([theValues objectForKey: @"AllDayEvent"]))
{
// If the occurence has no AllDay tag use it from master.
isAllDay = [[occurences objectAtIndex: 0] isAllDay];
}
//
// 0- free, 1- tentative, 2- busy and 3- out of office
@@ -458,7 +337,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// 0- normal, 1- personal, 2- private and 3-confidential
//
if ((o = [theValues objectForKey: @"Sensitivity"]))
if ((o = [theValues objectForKey: @"Sensitivy"]))
{
switch ([o intValue])
{
@@ -474,37 +353,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[self setAccessClass: @"PUBLIC"];
}
}
// Categories
if ((o = [theValues objectForKey: @"Categories"]) && [o length])
[self setCategories: o];
// We ignore TimeZone sent by mobile devices for now.
// Some Windows devices don't send during event updates.
//if ((o = [theValues objectForKey: @"TimeZone"]))
// {
// }
//else
{
// We haven't received a timezone, let's use the user's timezone
// specified in SOGo for now.
userTimeZone = [[[context activeUser] userDefaults] timeZone];
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
[(iCalCalendar *) parent addTimeZone: tz];
}
userTimeZone = [[[context activeUser] userDefaults] timeZone];
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
[(iCalCalendar *) parent addTimeZone: tz];
//}
// 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];
@@ -512,24 +374,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
o = [o calendarDate];
start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
oldstart = [start dateTime];
[start setTimeZone: tz];
if (isAllDay)
{
if (isAllDay)
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[start setDate: o];
[start setTimeZone: nil];
}
else
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[start setDateTime: o];
}
// Calculate delta if start date has been changed.
if (oldstart)
deltasecs = [[start dateTime ] timeIntervalSinceDate: oldstart] * -1;
else
deltasecs = 0;
}
if ((o = [theValues objectForKey: @"EndTime"]))
@@ -540,11 +403,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (isAllDay)
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[end setDate: o];
[end setTimeZone: nil];
}
else
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[end setDateTime: o];
}
}
@@ -588,177 +459,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
RELEASE(rule);
[rule takeActiveSyncValues: o inContext: context];
// Exceptions
if ((o = [theValues objectForKey: @"Exceptions"]) && [o isKindOfClass: [NSArray class]])
{
NSCalendarDate *recurrenceId, *adjustedRecurrenceId, *currentId;
NSMutableArray *exdates, *exceptionstouched;
iCalEvent *currentOccurence;
NSDictionary *exception;
unsigned int i, count, max;
[self removeAllExceptionDates];
exdates = [NSMutableArray array];
exceptionstouched = [NSMutableArray array];
for (i = 0; i < [o count]; i++)
{
exception = [o objectAtIndex: i];
if (![[exception objectForKey: @"Exception_Deleted"] intValue])
{
recurrenceId = [[exception objectForKey: @"Exception_StartTime"] asCalendarDate];
if (isAllDay)
recurrenceId = [recurrenceId dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: [userTimeZone secondsFromGMTForDate:recurrenceId]];
// When moving the calendar entry (i.e. changing the startDate) iOS and Android sometimes send a value for
// Exception_StartTime which is not what we expect.
// With this we make sure the recurrenceId is always correct.
//
// iOS problem - If the master is a no-allday-event but the exception is, an invalid Exception_StartTime is in the request.
// e.g. it sends 20150409T040000Z instead of 20150409T060000Z;
// This might be a special case since iPhone doesn't allow an allday-exception on a non-allday-event.
if (!([[start dateTime] compare: [[start dateTime] hour:[recurrenceId hourOfDay] minute:[recurrenceId minuteOfHour]]] == NSOrderedSame))
recurrenceId = [recurrenceId hour:[[start dateTime] hourOfDay] minute:[[start dateTime] minuteOfHour]];
// We need to store the recurrenceIds and exception dates adjusted by deltasecs.
// This ensures that the adjustment in SOGoCalendarComponent->updateComponent->_updateRecurrenceIDsWithEvent gives the correct dates.
adjustedRecurrenceId = [recurrenceId dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0 seconds: deltasecs];
// search for an existing occurence and update it
max = [occurences count];
currentOccurence = nil;
count = 1;
while (count < max)
{
currentOccurence = [occurences objectAtIndex: count] ;
currentId = [currentOccurence recurrenceId];
if ([currentId compare: adjustedRecurrenceId] == NSOrderedSame)
{
[exceptionstouched addObject: adjustedRecurrenceId];
[currentOccurence takeActiveSyncValues: exception inContext: context];
break;
}
count++;
currentOccurence = nil;
}
// Create a new occurence if we found none to update.
if (!currentOccurence)
{
iCalDateTime *recid;
currentOccurence = [self mutableCopy];
[currentOccurence removeAllRecurrenceRules];
[currentOccurence removeAllExceptionRules];
[currentOccurence removeAllExceptionDates];
[[self parent] addToEvents: currentOccurence];
[currentOccurence takeActiveSyncValues: exception inContext: context];
recid = (iCalDateTime *)[currentOccurence uniqueChildWithTag: @"recurrence-id"];
if (isAllDay)
[recid setDate: adjustedRecurrenceId];
else
[recid setDateTime: adjustedRecurrenceId];
[exceptionstouched addObject: [recid dateTime]];
}
}
else if ([[exception objectForKey: @"Exception_Deleted"] intValue])
{
recurrenceId = [[exception objectForKey: @"Exception_StartTime"] asCalendarDate];
if (isAllDay)
recurrenceId = [recurrenceId dateByAddingYears: 0 months: 0
days: 0 hours: 0 minutes: 0
seconds: [userTimeZone secondsFromGMTForDate:recurrenceId]];
// We add only valid exception dates.
if ([self doesOccurOnDate: recurrenceId] &&
([[start dateTime] compare: [[start dateTime] hour:[recurrenceId hourOfDay]
minute:[recurrenceId minuteOfHour]]] == NSOrderedSame))
{
// We need to store the recurrenceIds and exception dates adjusted by deltasecs.
// This ensures that the adjustment in SOGoCalendarComponent->updateComponent->_updateRecurrenceIDsWithEvent gives the correct dates.
[exdates addObject: [recurrenceId dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: deltasecs]];
}
}
}
// Update exception dates in master event.
max = [exdates count];
if (max > 0)
{
for (count = 0; count < max; count++)
{
if (([exceptionstouched indexOfObject: [exdates objectAtIndex: count]] == NSNotFound))
[self addToExceptionDates: [exdates objectAtIndex: count]];
}
}
// Remove all exceptions included in the request.
max = [occurences count];
count = 1; // skip the master event
while (count < max)
{
currentOccurence = [occurences objectAtIndex: count] ;
currentId = [currentOccurence recurrenceId];
// Delete all occurences which are not touched (modified/added).
if (([exceptionstouched indexOfObject: currentId] == NSNotFound))
[[[self parent] children] removeObject: currentOccurence];
count++;
}
}
else if ([self isRecurrent])
{
// We have no exceptions in request but there is a recurrence rule.
// Remove all excpetions and exception dates.
iCalEvent *currentOccurence;
unsigned int count, max;
[self removeAllExceptionDates];
max = [occurences count];
count = 1; // skip the master event
while (count < max)
{
currentOccurence = [occurences objectAtIndex: count];
[[[self parent] children] removeObject: currentOccurence];
count++;
}
}
}
else if ([self isRecurrent])
{
// We have no recurrence rule in request.
// Remove all exceptions, exception dates and recurrence rules.
iCalEvent *currentOccurence;
unsigned int count, max;
[self removeAllRecurrenceRules];
[self removeAllExceptionRules];
[self removeAllExceptionDates];
max = [occurences count];
count = 1; // skip the master event
while (count < max)
{
currentOccurence = [occurences objectAtIndex: count];
[[[self parent] children] removeObject: currentOccurence];
count++;
}
}
// Organizer - we don't touch the value unless we're the organizer
@@ -766,7 +466,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
([self userIsOrganizer: [context activeUser]] || [[context activeUser] hasEmail: o]))
{
iCalPerson *person;
person = [iCalPerson elementWithTag: @"organizer"];
[person setEmail: o];
[person setCn: [theValues objectForKey: @"Organizer_Name"]];
@@ -774,14 +474,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;
@@ -791,20 +491,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];
}
}
@@ -814,7 +500,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
// Windows phones sens sometimes an empty Attendees tag.
// We check it's an array before processing it.
if ((o = [theValues objectForKey: @"Attendees"]) && [o isKindOfClass: [NSArray class]])
if ((o = [theValues objectForKey: @"Attendees"])&& [o isKindOfClass: [NSArray class]])
{
NSMutableArray *attendees;
NSDictionary *attendee;
@@ -863,36 +549,4 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
}
- (void) changeParticipationStatus: (NSDictionary *) theValues
inContext: (WOContext *) context
component: (id) component
{
NSString *status;
id o;
// See: https://msdn.microsoft.com/en-us/library/ee202290(v=exchg.80).aspx
//
// 0 == Free
// 1 == Tentative
// 2 == Busy
// 3 == Out of Office
// 4 == Working elsehwere
//
if ((o = [theValues objectForKey: @"BusyStatus"]))
{
// We translate >= 2 into ACCEPTED
if ([o intValue] == 0)
status = @"NEEDS-ACTION";
else if ([o intValue] >= 2)
status = @"ACCEPTED";
else
status = @"TENTATIVE";
// There's no delegate in EAS
[(SOGoAppointmentObject *) component changeParticipationStatus: status
withDelegate: nil
alarm: nil];
}
}
@end
+1 -1
View File
@@ -140,7 +140,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Simple reccurrence rule of type "Monthly"
type = 2;
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"Calendar:\">%d</Recurrence_DayOfMonth>",
(int)[[[self parent] startDate] dayOfMonth]];
[[[self parent] startDate] dayOfMonth]];
}
}
else if ([self frequency] == iCalRecurrenceFrequenceYearly)
+28 -92
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,24 +49,23 @@ 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
{
NSMutableString *s;
NSArray *categories;
id o;
int v, i;
int v;
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,28 +96,9 @@ 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"])
v = 3;
else
v = 0;
[s appendFormat: @"<Sensitivity xmlns=\"Tasks:\">%d</Sensitivity>", v];
categories = [self categories];
if ([categories count])
{
[s appendFormat: @"<Categories xmlns=\"Tasks:\">"];
for (i = 0; i < [categories count]; i++)
{
[s appendFormat: @"<Category xmlns=\"Tasks:\">%@</Category>", [[categories objectAtIndex: i] activeSyncRepresentationInContext: context]];
}
[s appendFormat: @"</Categories>"];
}
// Sensitivity - FIXME
[s appendFormat: @"<Sensitivity xmlns=\"Tasks:\">%d</Sensitivity>", 0];
// Subject
o = [self summary];
if ([o length])
@@ -127,23 +106,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ((o = [self comment]))
{
// 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>", (int)[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: @"<Truncated>%d</Truncated>", 0];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
return s;
@@ -156,6 +125,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
iCalTimeZone *tz;
id o;
NSInteger tzOffset;
userTimeZone = [[[context activeUser] userDefaults] timeZone];
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
[(iCalCalendar *) parent addTimeZone: tz];
@@ -165,16 +136,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"])) )
@@ -183,32 +147,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
o = [o calendarDate];
completed = (iCalDateTime *) [self uniqueChildWithTag: @"completed"];
//tzOffset = [[o timeZone] secondsFromGMTForDate: o];
//o = [o dateByAddingYears: 0 months: 0 days: 0
// hours: 0 minutes: 0
// seconds: -tzOffset];
[completed setDate: o];
[self setStatus: @"COMPLETED"];
}
else
{
[self setStatus: @"IN-PROCESS"];
[self setCompleted: nil];
}
if ((o = [theValues objectForKey: @"DueDate"]))
{
iCalDateTime *due;
o = [o calendarDate];
due = (iCalDateTime *) [self uniqueChildWithTag: @"due"];
[due setTimeZone: tz];
[due setDateTime: o];
}
if ((o = [theValues objectForKey: @"StartDate"]))
{
iCalDateTime *due;
o = [o calendarDate];
due = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
[due setTimeZone: tz];
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[due setDateTime: o];
}
@@ -223,29 +182,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[self setPriority: @"9"];
}
//
// 0- normal, 1- personal, 2- private and 3-confidential
//
if ((o = [theValues objectForKey: @"Sensitivity"]))
{
switch ([o intValue])
{
case 2:
[self setAccessClass: @"PRIVATE"];
break;
case 3:
[self setAccessClass: @"CONFIDENTIAL"];
break;
case 0:
case 1:
default:
[self setAccessClass: @"PUBLIC"];
}
}
// Categories
if ((o = [theValues objectForKey: @"Categories"]) && [o length])
[self setCategories: o];
if ((o = [theValues objectForKey: @"ReminderTime"]))
{
+2 -3
View File
@@ -70,8 +70,8 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
<Proxy http://127.0.0.1:20000/SOGo>
## adjust the following to your configuration
RequestHeader set "x-webobjects-server-port" "443"
# RequestHeader set "x-webobjects-server-name" "yourhostname"
# RequestHeader set "x-webobjects-server-url" "https://yourhostname"
RequestHeader set "x-webobjects-server-name" "yourhostname"
RequestHeader set "x-webobjects-server-url" "https://yourhostname"
## When using proxy-side autentication, you need to uncomment and
## adjust the following line:
@@ -90,6 +90,5 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
<IfModule rewrite_module>
RewriteEngine On
RewriteRule ^/.well-known/caldav/?$ /SOGo/dav [R=301]
RewriteRule ^/.well-known/carddav/?$ /SOGo/dav [R=301]
</IfModule>
-24790
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
-161
View File
@@ -1,161 +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
~~~~
JavaScript libraries
~~~~~~~~~~~~~~~~~~~~
* https://angularjs.org/
* http://angular-ui.github.io/ui-router/
* https://material.angularjs.org/
* http://lodash.com/
* https://github.com/nervgh/angular-file-upload
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
* When returning JSON from an object extending UIxComponent, use the following method:
- (WOResponse *) responseWithStatus: (unsigned int) status
andJSONRepresentation: (NSObject *) contentObject;
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
* http://jshint.com/
* https://github.com/angular/material/tree/master/docs/guides
* 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/{Common,Contacts,Mailer,Preferences,Scheduler}/*.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/
* http://cssguidelin.es/
* http://sixrevisions.com/css/css-methodologies/
* https://css-tricks.com/what-a-css-code-review-might-look-like/
* http://una.im/classy-css/
A `@mixin` is like a stamp: it creates a duplicated version of the property block (optionally) with arguments provided. An `@extend` appends the element you are extending to the property block. It is your "yes, and ___" statement.
* 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
^^^^^
* [Mozilla Fira](http://mozilla.github.io/Fira/)
* [Material icons](https://www.google.com/design/icons/)
Version Control
---------------
* https://devcharm.com/articles/46/improve-your-git-workflow/
* https://github.com/angular/material/blob/master/docs/guides/CONTRIBUTING.md#-commit-message-format
* 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
+42 -226
View File
@@ -1,7 +1,5 @@
Installation and Configuration Guide
====================================
:toc: left
:icons: font
////
@@ -56,7 +54,7 @@ at http://www.sogo.nu/
Architecture and Compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
image::images/architecture.png[System Architecture, 400, 964]
image::images/architecture.png[System Architecture]
Standard protocols such as CalDAV, CardDAV, GroupDAV, HTTP, IMAP and
SMTP are used to communicate with the SOGo platform or its
@@ -82,12 +80,6 @@ and others) 
* SMTP server (Postfix, Sendmail and others)
* IMAP server (Courier, Cyrus IMAP Server, Dovecot and others)
If you plan to use ActiveSync, an IMAP server supporting the ACL,
UIDPLUS, QRESYNC, ANNOTATE (or X-GUID) IMAP extensions is required,
such as Cyrus IMAP version 2.4 or later, or Dovecot version
2.1 or later. If your current IMAP server does not support these
extensions, you can use Dovecot's proxying capabilities.
In this guide, we assume that all those components are running on the
same server (i.e., `localhost` or `127.0.0.1`) that SOGo will be
installed on.
@@ -169,10 +161,10 @@ 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)
* Ubuntu 12.04 (Precise) to 14.04 (Trusty)
* 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
and that they are running before proceeding with the SOGo configuration.
@@ -181,7 +173,7 @@ standard distribution. For example, if you are using Red Hat Enterprise
Linux 5, you have to be subscribed to the Red Hat Network before
continuing with the SOGo software installation.
NOTE: This document covers the installation of SOGo under RHEL 6.
This document covers the installation of SOGo under RHEL 6.
For installation instructions on Debian and Ubuntu, please refer
directly to the SOGo website at http://www.sogo.nu/.
@@ -196,8 +188,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
~~~~~~~~~~~~~~~~~~
@@ -296,7 +287,7 @@ associated to a domain is limited to access only the users data from the
same domain. Consequently, the configuration parameters of SOGo are
defined on three levels:
image::images/preferences-hierarchy.png[Preferences Hierarchy, 400, 400]
image::images/preferences-hierarchy.png[Preferences Hierarchy]
Each level inherits the preferences of the parent level. Therefore,
domain preferences define the defaults values of the user preferences,
@@ -569,29 +560,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
@@ -664,7 +643,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
@@ -858,7 +837,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
@@ -926,8 +905,7 @@ resource if the entry has the calendarresource objectClass set.
to which a resource can be part of at any point in time.
If this is set to `0`, or if the attribute is missing, it means no
limit. If set to `-1`, no limit is imposed but the resource will
be marked as busy the first time it is booked.
limit.
|filter (optional)
|The filter to use for LDAP queries, it should be defined as an
@@ -1014,17 +992,7 @@ context as Dovecot stores in its database.
|passwordPolicy
|If set to `YES`, SOGo will use the extended LDAP Password Policies
attributes. If you LDAP server does not support those and you activate
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.
this feature, every LDAP requests will fail.
|isAddressBook
|If set to `YES`, this LDAP source is used as a shared address book
@@ -1037,8 +1005,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 = {
@@ -1063,11 +1031,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.
@@ -1127,7 +1090,7 @@ fax number, one could map it to the _facsimiletelephonenumber_ attribute
like this:
----
mapping = {
mapping = \{
  facsimiletelephonenumber = ("fax", "facsimiletelephonenumber");
};
----
@@ -1357,27 +1320,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
@@ -1507,10 +1470,7 @@ case, SOGo will consider the returned entry to be a resource.
which a resource can be part of at any point in time.
If this is set to `0`, or if the attribute is missing, it means no
limit and the resource will always be marked as free. If set to `-1`,
no limit is imposed but the resource will be marked as busy the first
time it is booked. If greater than 0, the resource will get marked as
busy once it reaches the value.
limit.
|DomainFieldName (optional)
|If set, SOGo will use the value of that field as the domain associated
@@ -1630,16 +1590,6 @@ Defaults to `Trash` when unset.
Use a `/` as a hierarchy separator if referring to an IMAP subfolder.
For example: `INBOX/Trash`.
|U |SOGoJunkFolderName
|Parameter used to set the IMAP folder name used to store junk
messages.
Defaults to `Junk` when unset.
Use a `/` as a hierarchy separator if referring to an IMAP subfolder.
For example: `INBOX/Junk`. Also see the SOGoMailJunkSettings for
more options regarding junk/not-junk actions.
|D |SOGoIMAPCASServiceName
|Parameter used to set the CAS service name (URL) of the imap service.
This is useful if SOGo is connecting to the IMAP service through a
@@ -1719,13 +1669,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.
@@ -1829,12 +1772,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
@@ -1932,11 +1869,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.
@@ -2094,21 +2030,7 @@ Defaults to `%{FolderName} (%{UserName} <%{Email}>)` when unset.
the template named `UIxAdditionalPreferences.wox`. This template should
be put under `~sogo/GNUstep/Library/SOGo/Templates/PreferencesUI/`.
|D |SOGoMailJunkSettings
|Parameter used to enable email junk settings. The value is a dictionary
and the follow keys are supported: `vendor` (which must be set to "generic"
for now), `junkEmailAddress` which sets the email address to whom SOGo will
send junk mails to, `notJunkEmailAddress` which sets the email address to
whome SOGo will send non-junk mails to and `limit`, which is an integer value
and sets the maximum number of mails that will be attached to a
junk/not junk report sent by SOGo. Example: `SOGoMailJunkSettings = {
vendor = "generic"; junkEmailAddress = "spam@foo.com";
notJunkEmailAddress = "ham@foo.com"; limit = 10;
};`
|D |SOGoMailKeepDraftsAfterSend
|Parameter used to keep mails in the drafts folder once they have been
sent by SOGo. Defaults to `NO` when unset.
Defaults to `NO` when unset.
|=======================================================================
SOGo Configuration Summary
@@ -2137,7 +2059,6 @@ like this:
SOGoDraftsFolderName = Drafts;
SOGoSentFolderName = Sent;
SOGoTrashFolderName = Trash;
SOGoJunkFolderName = Junk;
SOGoMailingMechanism = smtp;
SOGoSMTPServer = 127.0.0.1;
SOGoUserSources = (
@@ -2164,8 +2085,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):
@@ -2173,7 +2093,7 @@ coyote.com):
{
...
domains = {
acme.com = {
acme = {
SOGoMailDomain = acme.com;
SOGoDraftsFolderName = Drafts;
SOGoUserSources = (
@@ -2194,7 +2114,7 @@ coyote.com):
}
);
};
coyote.com = {
coyote = {
SOGoMailDomain = coyote.com;
SOGoIMAPServer = imap.coyote.com;
SOGoUserSources = (
@@ -2225,7 +2145,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
@@ -2414,8 +2334,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.
@@ -2464,15 +2384,6 @@ _SOGoMaximumPingInterval_.
If not set, it defaults to `10` seconds.
|S |SOGoMaximumSyncResponseSize
|Parameter used to overwrite the maximum response size during
a Sync operation. The value is in kilobytes. Setting this to 512
means the response size will be of 524288 bytes or less. Note that
if you set the value too low and a mail message (or any other object)
surpasses it, it will still be synced but only this item will be.
Defaults to `0`, which means no overwrite is performed.
|S |SOGoMaximumSyncWindowSize
|Parameter used to overwrite the maximum number of items returned during
a Sync operation.
@@ -2481,31 +2392,28 @@ 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:
* Currently, only the personal calendar and address book are
synchronized. Adding support for all folders is planned.
* 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.
authentication. Alternatively, when supporting more than just the
personal address book, we'll also be able to expose the LDAP/SQL based
address books in SOGo over ActiveSync.
* 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
see the warning and thus, preventing any synchronization to happen.
* ActiveSync clients keep connections open for a while. Each connection
will grab a hold on a sogod process so you will need a lot of processes
to handle many clients. Make sure you tune your SOGo server when having
lots of ActiveSync clients.
to handle many clients. This limitation will eventually be overcome in
SOGo.
* Repetitive events with occurrences exceptions are currently not
supported.
* Outlook 2013 Autodiscovery is currently not supported.
@@ -2527,90 +2435,13 @@ user base.
To contact Microsoft, please visit:
http://www.microsoft.com/en-us/legal/intellectualproperty/
http://www.microsoft.com/en-us/legal/intellectualproperty/IPLicensing/Programs/exchangeactivesyncprotocol.aspx
 
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
----------
@@ -2740,21 +2571,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:
@@ -233,14 +233,13 @@ Installation
This section will guide you through the installation of the native
Microsoft Outlook compatibility layer SOGo offers.
////
Red Hat Enterprise Linux v6 x86_64
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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
@@ -267,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
@@ -302,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
@@ -317,10 +313,12 @@ from this guide.
On Ubuntu 12.04, the Samba init scripts need to be modified to
disable the upstart check. For more details, refer to:
https://wiki.samba.org/index.php/Samba4/InitScript
////
Debian 8 (Jessie) and Ubuntu 14.04 (Trusty Tahr)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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
@@ -343,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
-------------
@@ -388,7 +372,7 @@ Run the following commands as root: 
----
samba-tool domain provision --realm=example.com \
--domain=EXAMPLE \
--domain=OPENCHANGE \
--adminpass='%1OpenChange' \
--server-role='domain controller'
@@ -396,7 +380,7 @@ samba-tool user setexpiry administrator --noexpiry
----
You might consider changing the realm and domain used, to suit your
environment.
enviroment.
You might also have to
remove `/etc/samba/smb.conf` prior running this command.
@@ -406,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
@@ -424,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
@@ -442,7 +424,7 @@ Your Samba 4 configuration file should look like this:
OpenChange Configuration
~~~~~~~~~~~~~~~~~~~~~~~~
Since v2.2, OpenChange stores its metadata in MySQL so you need to have it installed.
OpenChange 2.2 stores its metadata in MySQL so you need to have it installed.
First, create the OpenChange MySQL user:
@@ -513,11 +495,9 @@ mapistore:indexing_backend = mysql://openchange-user:openchange$123@localhost/op
mapiproxy:openchangedb = mysql://openchange-user:openchange$123@localhost/openchange
----
////
On RHEL, make sure SELinux is disabled:
setenforce 0
////
Next, you can start Samba using the usual command:
@@ -548,14 +528,12 @@ This service runs as a WSGI application under apache (mod_wsgi).
While HTTPS is not required to access this service, it is strongly
recommended.
////
On RHEL-based distributions, the apache configuration required by these
services can be found in `/etc/httpd/conf.d/ocsmanager.conf` and
`/etc/httpd/conf.d/rpcproxy.conf`.
////
For Debian-based distributions, these files can be found
in `/etc/apache2/conf.d/` or `/etc/apache2/conf-available`.
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
@@ -563,19 +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
@@ -587,112 +559,17 @@ To avoid this problem, use a much higher timeout or disable the module:
a2dismod reqtimeout
You should now restart the Apache service and make sure it will start on
boot.
////
On RHEL-based distributions, do:
boot. On RHEL-based distributions, do:
chkconfig httpd on && /etc/init.d/httpd restart
////
On Debian-based distributions, do:
update-rc.d apache2 defaults && /etc/init.d/apache2 restart
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -818,10 +695,11 @@ can be ignored for now. This feature is currently not supported.
remove any data associated with the user from the SOGo server and
recreate a Microsoft Outlook profile.
To remove any data associated to a user, use
the `openchange_user_cleanup` script distributed with OpenChange. The script
can be found in `/usr/share/openchange/`.
the `openchange_user_cleanup` script distributed with SOGo. The script
can be found in `/usr/share/doc/sogo/` (`/usr/share/sogo-VERSION/` on
RHEL).
To reset a user, run the script as root:
`openchange_user_cleanup username`. See the usage output for additional options.
`python openchange_user_cleanup username`. See the usage output for additional options.
* The "Out of Office Assistant" will not currently work. This feature
has not been implemented.
* Creating folders below INBOX (when not normally permitted by the IMAP
+3 -3
View File
@@ -1,7 +1,7 @@
<!-- TODO have the build system take care of this -->
<releaseinfo>Version 3.0.0 - January 2016</releaseinfo>
<subtitle>for version 3.0.0</subtitle>
<date>2016-01-27</date>
<releaseinfo>Version 2.2.11 - December 2014</releaseinfo>
<subtitle>for version 2.2.11</subtitle>
<date>2014-12-09</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

@@ -6,13 +6,13 @@
Authors:
- Inverse inc. <info@inverse.ca>
Copyright (C) 2008-2016 Inverse inc.
Copyright (C) 2008-2014 Inverse inc.
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
////
// TODO have the build system take care of this
:release_version: 3.0.0
:release_version: 2.2.11
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:
+1 -1
View File
@@ -6,7 +6,7 @@ include ../Version
ADDITIONAL_OBJCFLAGS += -fPIE
ADDITIONAL_INCLUDE_DIRS +=
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed -fPIE -pie -Wl,--rpath,$(SOGO_SYSLIBDIR)/sogo
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed -fPIE -pie -Wl,--rpath,$(GNUSTEP_SYSTEM_LIBRARIES)/sogo
SOGOD = sogod
TOOL_NAME = $(SOGOD)
+1 -1
View File
@@ -267,7 +267,7 @@
NSObject <DOMNodeList> *list;
NSObject <DOMNode> *valueNode;
NSArray *elements;
NSString *property=nil, *match=nil;
NSString *property, *match;
list = [searchElement getElementsByTagName: @"prop"];
if ([list length])
+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.
+8 -393
View File
@@ -1,388 +1,3 @@
3.0.0 (2016-01-27)
------------------
New features
- complete rewrite of the JavaScript frontend using Angular and AngularMaterial
- responsive design and accessible options focused on mobile devices
- horizontal 3-pane view for a better experience on large desktop screens
- new color palette and better contrast ratio as recommended by the W3C
- improved accessibility to persons with disabilities by enabling common ARIA attributes
- use of Mozilla's Fira Sans typeface
- and many more!
2.3.7 (2016-01-25)
------------------
New features
- new junk/not junk capability with generic SMTP integration
Enhancements
- newly created folders using EAS are always sync'ed by default (#3454)
- added Croatian (hr_HR) translation - thanks to Jens Riecken
Bug fixes
- now always generate invitation updates when using EAS
- rewrote the string sanitization to be 32-bit Unicode safe
- do not try to decode non-wbxml responses for debug output (#3444)
2.3.6 (2016-01-18)
------------------
New features
- now able to sync only default mail folders when using EAS
Enhancements
- Unit testing for RTFHandler
- JUnit output for sogo-tests
Bug fixes
- don't unescape twice mail folder names (#3423)
- don't consider mobile Outlook EAS clients as DAV ones (#3431)
- we now follow 301 redirects when fetching ICS calendars
- when deleting an event using EAS, properly invoke the auto-scheduling code
- do not include failure attachments (really long filenames)
- fix encoding of email subjects with non-ASCII characters
- fix appointment notification mails using SOGoEnableDomainBasedUID configuration
- fix shifts in event times on Outlook
2.3.5 (2016-01-05)
------------------
Enhancements
- return an error to openchange if mail message delivery fails
- return the requested elements on complex requests from Outlook when downloading changes
- user sources can be loaded dynamically
- unify user sources API
- updated Russian translation (#3383)
Bug fixes
- properly compute the last week number for the year (#1010)
- share calendar, tasks and contacts folders in Outlook 2013 with editor permissions
- priorize filename in Content-Disposition against name in Content-Type to get the filename of an attachment in mail
- request all contacts when there is no filter in Contacts menu in Webmail
- personal contacts working properly on Outlook
- fixes on RTF parsing used by event/contact description and mail as RTF to read non-ASCII characters:
better parsing of font table, when using a font, switch to its character set, correct parsing of
escaped characters and Unicode character command word support for unicode characters greater than 32767
- no crash resolving recipients after reconnecting LDAP connection
- avoid creation of phantom contacts in SOGo from distribution list synced from Outlook.
- accepted & updated event names are now shown correctly in Outlook
- provide safe guards in mail and calendar to avoid exceptions while syncing
2.3.4 (2015-12-15)
------------------
New features
- initial support for EAS calendar exceptions
Enhancements
- limit the maximum width of toolbar buttons (#3381)
- updated CKEditor to version 4.5.6
Bug fixes
- JavaScript exception when printing events from calendars with no assigned color (#3203)
- EAS fix for wrong charset being used (#3392)
- EAS fix on qp-encoded subjects (#3390)
- correctly handle all-day event exceptions when the master event changes
- prevent characters in calendar component UID causing issues during import process
- avoid duplicating attendees when accepting event using a different identity over CalDAV
2.3.3a (2015-11-18)
-------------------
Bug fixes
- expanded mail folders list is not saved (#3386)
- cleanup translations
2.3.3 (2015-11-11)
------------------
New features
- initial S/MIME support for EAS (#3327)
- now possible to choose which folders to sync over EAS
Enhancements
- we no longer always entirely rewrite messages for Outlook 2013 when using EAS
- support for ghosted elements on contacts over EAS
- added Macedonian (mk_MK) translation - thanks to Miroslav Jovanovic
- added Portuguese (pt) translation - thanks to Eduardo Crispim
Bug fixes
- numerous EAS fixes when connections are dropped before the EAS client receives the response (#3058, #2849)
- correctly handle the References header over EAS (#3365)
- make sure English is always used when generating Date headers using EAS (#3356)
- don't escape quoted strings during versit generation
- we now return all cards when we receive an empty addressbook-query REPORT
- avoid crash when replying to a mail with no recipients (#3359)
- inline images sent from SOGo webmail are not displayed in Mozilla Thunderbird (#3271)
- prevent postal address showing on single line over EAS (#2614)
- display missing events when printing working hours only
- fix corner case making server crash when syncing hard deleted messages when clear offline items was set up (Zentyal)
- avoid infinite Outlook client loops trying to set read flag when it is already set (Zentyal)
- avoid crashing when calendar metadata is missing in the cache (Zentyal)
- fix recurrence pattern event corner case created by Mozilla Thunderbird which made server crash (Zentyal)
- fix corner case that removes attachments on sending messages from Outlook (Zentyal)
- freebusy on web interface works again in multidomain environments (Zentyal)
- fix double creation of folders in Outlook when the folder name starts with a digit (Zentyal)
- avoid crashing Outlook after setting a custom view in a calendar folder (Zentyal)
- handle emails having an attachment as their content
- fixed JavaScript syntax error in attendees editor
- fixed wrong comparison of meta vs. META tag in HTML mails
- fixed popup menu position when moved to the left (#3381)
- fixed dialog position when at the bottom of the window (#2646, #3378)
2.3.2 (2015-09-16)
------------------
Enhancements
- improved EAS speed and memory usage, avoiding many IMAP LIST commands (#3294)
- improved EAS speed during initial syncing of large mailboxes (#3293)
- updated CKEditor to version 4.5.3
Bug fixes
- fixed display of whitelisted attendees in Preferences window on Firefox (#3285)
- non-latin subfolder names are displayed correctly on Outlook (Zentyal)
- fixed several sync issues on environments with multiple users (Zentyal)
- folders from other users will no longer appear on your Outlook (Zentyal)
- use right auth in multidomain environments in contacts and calendar from Outlook (Zentyal)
- session fix when SOGoEnableDomainBasedUID is enabled but logins are domain-less
- less sync issues when setting read flag (Zentyal)
- attachments with non-latin filenames sent by Outlook are now received (Zentyal)
- support attachments from more mail clients (Zentyal)
- avoid conflicting message on saving a draft mail (Zentyal)
- less conflicting messages in Outlook while moving messages between folders (Zentyal)
- start/end shifting by 1 hour due to timezone change on last Sunday of October 2015 (#3344)
- fixed localization of calendar categories with empty profile (#3295)
- fixed options availability in contextual menu of Contacts module (#3342)
2.3.1 (2015-07-23)
------------------
Enhancements
- improved EAS speed, especially when fetching big attachments
- now always enforce the organizer's default identity in appointments
- improved the handling of default calendar categories/colors (#3200)
- added support for DeletesAsMoves over EAS
- added create-folder subcommand to sogo-tool to create contact and calendar folders
- group mail addresses can be used as recipient in Outlook
- added 'ActiveSync' module constraints
- updated CKEditor to version 4.5.1
- added Slovenian translation - thanks to Jens Riecken
- added Chinese (Taiwan) translation
Bug fixes
- EAS's GetItemEstimate/ItemOperations now support fetching mails and empty folders
- 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)
-------------------
Enhancements
- MultipleBookingsFieldName can be set to -1 to show busy status when booked at least once
- handle multipart objects in EAS/ItemOperations
Bug fixes
- fixed calendar selection in event and task editors (#3049, #3050)
- check for resources existence when listing subscribed ones (#3054)
- correctly recognize Apple Calendar on Yosemite (#2960)
- fixed two potential autorelease pool leaks (#3026 and #3051)
- fixed birthday offset in EAS
- fixed From's full name over EAS
- fixed potential issue when handling multiple Add/Change/Delete/Fetch EAS commands (#3057)
- fixed wrong timezone calculation on recurring events
2.2.13 (2014-12-30)
-------------------
Enhancements
- initial support for empty sync request/response for EAS
- added the SOGoMaximumSyncResponseSize EAS configuration parameter to
support memory-limited sync response sizes
- we now not only use the creation date for event's cutoff date (EAS)
Bug fixes
- fixed contact description truncation on WP8 phones (#3028)
- fixed freebusy information not always returned
- fixed tz issue when the user one was different from the system one with EAS
2.2.12a (2014-12-19)
--------------------
Bug fixes
- fixed empty HTML mails being sent (#3034)
2.2.12 (2014-12-18)
-------------------
New features
- allow including or not freebusy info from subscribed calendars
- now possible to set an autosave timer for draft messages
- now possible to set alarms on event invitations (#76)
Enhancements
- updated CKEditor to version 4.4.6 and added the 'Source Area' plugin
- avoid testing for IMAP ANNOTATION when X-GUID is available (#3018)
- updated Czech, Dutch, Finnish, French, German, Polish and Spanish (Spain) translations
Bug fixes
- fixed for privacy and categories for EAS (#3022)
- correctly set MeetingStatus for EAS on iOS devices
- Ubuntu Lucid fixes for EAS
- fixed calendar reminders for future events (#3008)
- make sure all text parts are UTF-8 re-encoded for Outlook 2013 over EAS (#3003)
- fixed task description truncation affecting WP8 phones over EAS (#3028)
2.2.11a (2014-12-10)
--------------------
Bug fixes
- make sure all address books returned using EAS are GCS ones
2.2.11 (2014-12-09)
-------------------
@@ -390,16 +5,16 @@ New features
- sogo-tool can now be used to manage EAS metadata for all devices
Enhancements
- improved the SAML2 documentation
- radically reduced AES memory usage
- Improved the SAML2 documentation
- Radically reduced AES memory usage
Bug fixes
- now possible to specify the username attribute for SAML2 (SOGoSAML2LoginAttribute) (#2381)
- added support for IdP-initiated SAML2 logout (#2377)
- we now generate SAML2 metadata on the fly (#2378)
- we now handle correctly the SOGo logout when using SAML (#2376 and #2379)
- fixed freebusy lookups going off bounds for resources (#3010)
- fixed EAS clients moving mails between folders but disconnecting before receiving server's response (#2982)
- Now possible to specify the username attribute for SAML2 (SOGoSAML2LoginAttribute) (#2381)
- Added support for IdP-initiated SAML2 logout (#2377)
- We now generate SAML2 metadata on the fly (#2378)
- We now handle correctly the SOGo logout when using SAML (#2376 and #2379)
- Fixed freebusy lookups going off bounds for resources (#3010)
- Fixed EAS clients moving mails between folders but disconnecting before receiving server's response (#2982)
2.2.10 (2014-11-21)
-------------------
-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
+4 -10
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 += \
@@ -145,8 +140,7 @@ $(DBMSGREADER_TOOL)_LIB_DIRS += \
-L../SoObjects/SOGo/SOGo.framework/sogo -lSOGo \
-L../SOPE/GDLContentStore/obj/ -lGDLContentStore \
-L../SOPE/NGCards/obj/ -lNGCards \
-lNGObjWeb \
$(LIBMAPI_LIBS)
-lNGObjWeb
TEST_TOOL_NAME += $(PLREADER_TOOL) $(DBMSGREADER_TOOL)
@@ -177,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
+3 -2
View File
@@ -24,7 +24,6 @@
#define MAPISTORECALENDARWRAPPER_H
#import <NGCards/iCalPerson.h>
#import <NGCards/iCalTimeZone.h>
#import <Appointments/iCalEntityObject+SOGo.h>
#import "MAPIStoreObjectProxy.h"
@@ -43,7 +42,7 @@
iCalCalendar *calendar;
iCalEvent *firstEvent;
iCalEvent *event;
iCalTimeZone *timeZone;
NSTimeZone *timeZone;
SOGoUser *user;
NSString *senderEmail;
NSData *globalObjectId;
@@ -58,10 +57,12 @@
+ (id) wrapperWithICalEvent: (iCalEvent *) newEvent
andUser: (SOGoUser *) newUser
andSenderEmail: (NSString *) newSenderEmail
inTimeZone: (NSTimeZone *) newTimeZone
withConnectionInfo: (struct mapistore_connection_info *) newConnInfo;
- (id) initWithICalEvent: (iCalEvent *) newEvent
andUser: (SOGoUser *) newUser
andSenderEmail: (NSString *) newSenderEmail
inTimeZone: (NSTimeZone *) newTimeZone
withConnectionInfo: (struct mapistore_connection_info *) newConnInfo;
/* getters */
+122 -130
View File
@@ -37,9 +37,7 @@
#import <NGCards/iCalEventChanges.h>
#import <NGCards/iCalPerson.h>
#import <NGCards/iCalTrigger.h>
#import <NGCards/iCalTimeZonePeriod.h>
#import <NGCards/NSString+NGCards.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserManager.h>
@@ -47,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"
@@ -82,6 +79,7 @@ static NSCharacterSet *hexCharacterSet = nil;
+ (id) wrapperWithICalEvent: (iCalEvent *) newEvent
andUser: (SOGoUser *) newUser
andSenderEmail: (NSString *) newSenderEmail
inTimeZone: (NSTimeZone *) newTimeZone
withConnectionInfo: (struct mapistore_connection_info *) newConnInfo
{
MAPIStoreAppointmentWrapper *wrapper;
@@ -89,6 +87,7 @@ static NSCharacterSet *hexCharacterSet = nil;
wrapper = [[self alloc] initWithICalEvent: newEvent
andUser: newUser
andSenderEmail: newSenderEmail
inTimeZone: newTimeZone
withConnectionInfo: newConnInfo];
[wrapper autorelease];
@@ -182,10 +181,10 @@ static NSCharacterSet *hexCharacterSet = nil;
- (id) initWithICalEvent: (iCalEvent *) newEvent
andUser: (SOGoUser *) newUser
andSenderEmail: (NSString *) newSenderEmail
inTimeZone: (NSTimeZone *) newTimeZone
withConnectionInfo: (struct mapistore_connection_info *) newConnInfo
{
NSArray *events;
iCalTimeZone *tz;
if ((self = [self init]))
{
@@ -194,20 +193,9 @@ static NSCharacterSet *hexCharacterSet = nil;
event = newEvent;
events = [calendar events];
firstEvent = [events objectAtIndex: 0];
ASSIGN (timeZone, newTimeZone);
ASSIGN (user, newUser);
ASSIGN (senderEmail, newSenderEmail);
/* If newEvent comes from the client, we set its time zone in
updateFromMAPIProperties. If it is not present, we use the
time zone of the user */
tz = (iCalTimeZone *) [calendar firstChildWithTag: @"vtimezone"];
if (!tz)
{
tz = [iCalTimeZone timeZoneForName: [[[user userDefaults] timeZone] name]];
if (!tz)
[self logWithFormat: @"no time zone could be set"];
}
ASSIGN (timeZone, tz);
[self _setupITIPContext];
}
@@ -275,16 +263,16 @@ static NSCharacterSet *hexCharacterSet = nil;
if (contactInfos)
{
username = [contactInfos objectForKey: @"sAMAccountName"];
username = [contactInfos objectForKey: @"c_uid"];
recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (connInfo, username);
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username);
}
else
{
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;
@@ -294,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++;
@@ -376,9 +364,9 @@ static NSCharacterSet *hexCharacterSet = nil;
if (contactInfos)
{
username = [contactInfos objectForKey: @"sAMAccountName"];
username = [contactInfos objectForKey: @"c_uid"];
recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (connInfo, username);
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username);
}
else
{
@@ -394,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++;
@@ -732,15 +720,22 @@ static NSCharacterSet *hexCharacterSet = nil;
inMemCtx: (TALLOC_CTX *) memCtx
{
NSCalendarDate *dateValue;
NSInteger offset;
// if ([event isRecurrent])
// dateValue = [event firstRecurrenceStartDate];
// else
dateValue = [event startDate];
if ([event isAllDay])
dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
{
offset = -[timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
}
[dateValue setTimeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
@@ -753,14 +748,22 @@ static NSCharacterSet *hexCharacterSet = nil;
exceptions, where it is the normal start date for the day of the
exception. */
NSCalendarDate *dateValue;
NSInteger offset;
dateValue = [event recurrenceId];
if (!dateValue)
dateValue = [event startDate];
[dateValue setTimeZone: timeZone];
if ([event isAllDay])
dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
{
offset = -[timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
}
[dateValue setTimeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
@@ -768,12 +771,19 @@ static NSCharacterSet *hexCharacterSet = nil;
inMemCtx: (TALLOC_CTX *) memCtx
{
NSCalendarDate *dateValue;
NSInteger offset;
dateValue = [firstEvent startDate];
if ([firstEvent isAllDay])
dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
{
offset = -[timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
}
[dateValue setTimeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
@@ -781,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: utcTZ];
dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
dateValue = [[event startDate] hour: 0 minute: 0 second: 0];
*data = [dateValue asFileTimeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
@@ -818,7 +819,7 @@ static NSCharacterSet *hexCharacterSet = nil;
dateValue = [event startDate];
offset = [event durationAsTimeInterval];
if ([event isAllDay])
offset -= [[timeZone periodForDate: dateValue] secondsOffsetFromGMT];
offset -= [timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
@@ -836,14 +837,15 @@ static NSCharacterSet *hexCharacterSet = nil;
dateValue = [event recurrenceId];
if (!dateValue)
dateValue = [event startDate];
[dateValue setTimeZone: timeZone];
offset = [firstEvent durationAsTimeInterval];
if ([firstEvent isAllDay])
offset -= [[timeZone periodForDate: dateValue] secondsOffsetFromGMT];
offset -= [timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
*data = [dateValue asFileTimeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
@@ -859,7 +861,7 @@ static NSCharacterSet *hexCharacterSet = nil;
dateValue = [firstEvent startDate];
offset = [firstEvent durationAsTimeInterval];
if ([event isAllDay])
offset -= [[timeZone periodForDate: dateValue] secondsOffsetFromGMT];
offset -= [timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
@@ -873,17 +875,26 @@ static NSCharacterSet *hexCharacterSet = nil;
{
enum mapistore_error rc;
NSCalendarDate *dateValue;
NSInteger offset;
iCalRecurrenceRule *rrule;
if ([event isRecurrent])
{
rrule = [[event recurrenceRules] objectAtIndex: 0];
dateValue = [rrule untilDate];
if (dateValue && [event isAllDay])
dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
if (dateValue)
{
if ([event isAllDay])
offset = -[timeZone secondsFromGMTForDate: dateValue];
else
offset = 0;
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
}
else
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;
@@ -910,8 +921,8 @@ static NSCharacterSet *hexCharacterSet = nil;
contactInfos = [mgr contactInfosForUserWithUIDorEmail: email];
if (contactInfos)
{
username = [contactInfos objectForKey: @"sAMAccountName"];
entryId = MAPIStoreInternalEntryId (connInfo, username);
username = [contactInfos objectForKey: @"c_uid"];
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username);
}
else
entryId = MAPIStoreExternalEntryId (cn, email);
@@ -1180,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
@@ -1223,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
{
@@ -1256,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)];
}
@@ -1317,14 +1292,21 @@ static NSCharacterSet *hexCharacterSet = nil;
{
enum mapistore_error rc;
NSCalendarDate *dateValue;
NSInteger offset;
dateValue = [event recurrenceId];
if (dateValue)
{
rc = MAPISTORE_SUCCESS;
if ([event isAllDay])
dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
{
offset = -[timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
}
[dateValue setTimeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx];
}
else
@@ -1349,6 +1331,7 @@ static NSCharacterSet *hexCharacterSet = nil;
iCalEventChanges *changes;
NSArray *changedProperties;
NSCalendarDate *dateValue;
NSInteger offset;
changes = [iCalEventChanges changesFromEvent: event toEvent: exceptionEvent];
@@ -1356,17 +1339,28 @@ static NSCharacterSet *hexCharacterSet = nil;
memset (extendedException, 0, sizeof (struct ExtendedException));
extendedException->ChangeHighlight.Size = sizeof (uint32_t);
dateValue = [timeZone computedDateForDate: [exceptionEvent startDate]];
dateValue = [exceptionEvent startDate];
offset = [timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
exceptionInfo->StartDateTime = [dateValue asMinutesSince1601];
extendedException->ChangeHighlight.Value = BIT_CH_START;
extendedException->StartDateTime = exceptionInfo->StartDateTime;
dateValue = [timeZone computedDateForDate: [exceptionEvent endDate]];
dateValue = [exceptionEvent endDate];
offset = [timeZone secondsFromGMTForDate: dateValue];
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
exceptionInfo->EndDateTime = [dateValue asMinutesSince1601];
extendedException->ChangeHighlight.Value |= BIT_CH_END;
extendedException->EndDateTime = exceptionInfo->EndDateTime;
dateValue = [timeZone computedDateForDate: [exceptionEvent recurrenceId]];
dateValue = [[exceptionEvent recurrenceId]
dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: offset];
exceptionInfo->OriginalStartDate = [dateValue asMinutesSince1601];
extendedException->OriginalStartDate = exceptionInfo->OriginalStartDate;
@@ -1421,20 +1415,17 @@ static NSCharacterSet *hexCharacterSet = nil;
firstStartDate = [event firstRecurrenceStartDate];
if (firstStartDate)
{
[firstStartDate setTimeZone: timeZone];
arp = talloc_zero (NULL, struct AppointmentRecurrencePattern);
[rule fillRecurrencePattern: &arp->RecurrencePattern
withEvent: event
inTimeZone: timeZone
inMemCtx: arp];
arp->ReaderVersion2 = 0x00003006;
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 = [timeZone computedDateForDate: firstStartDate];
startMinutes = ([firstStartDate hourOfDay] * 60
+ [firstStartDate minuteOfHour]);
arp->StartTimeOffset = startMinutes;
@@ -1660,16 +1651,15 @@ ReservedBlockEE2Size: 00 00 00 00
fromDate: (NSCalendarDate *) instanceDate;
{
uint16_t year;
NSCalendarDate *dateValue;
if (instanceDate)
{
dateValue = [timeZone computedDateForDate: instanceDate];
year = [dateValue yearOfCommonEra];
[instanceDate setTimeZone: timeZone];
year = [instanceDate yearOfCommonEra];
newGlobalId->YH = year >> 8;
newGlobalId->YL = year & 0xff;
newGlobalId->Month = [dateValue monthOfYear];
newGlobalId->D = [dateValue dayOfMonth];
newGlobalId->Month = [instanceDate monthOfYear];
newGlobalId->D = [instanceDate dayOfMonth];
}
}
@@ -1836,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;
@@ -1934,6 +1915,7 @@ ReservedBlockEE2Size: 00 00 00 00
if (alarm)
{
alarmDate = [alarm nextAlarmDate];
[alarmDate setTimeZone: utcTZ];
*data = [alarmDate asFileTimeInMemCtx: memCtx];
}
else
@@ -1995,7 +1977,8 @@ ReservedBlockEE2Size: 00 00 00 00
enum mapistore_error rc;
NSString *tzid;
tzid = [timeZone tzId];
tzid = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"]
value: 0 ofAttribute: @"tzid"];
if ([tzid length] > 0)
{
*data = [tzid asUnicodeInMemCtx: memCtx];
@@ -2011,9 +1994,16 @@ ReservedBlockEE2Size: 00 00 00 00
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc;
iCalTimeZone *icalTZ;
*data = [timeZone asTimeZoneStructInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
icalTZ = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] timeZone];
if (icalTZ)
{
*data = [icalTZ asTimeZoneStructInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
@@ -2022,17 +2012,19 @@ ReservedBlockEE2Size: 00 00 00 00
inMemCtx: (TALLOC_CTX *) memCtx
{
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] | [event isRecurrent])
if ([event isRecurrent])
{
/* [MS-OXOCAL] 2.2.1.42: This property can only have the E flag set in the
TimeZoneDefinition struct */
*data = [timeZone 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;
-3
View File
@@ -46,9 +46,6 @@
forURL: (NSURL *) server
forceRenew: (BOOL) renew;
- (NSString *) passwordInContext: (WOContext *) context;
@end
#endif /* MAPISTOREAUTHENTICATOR_H */
-4
View File
@@ -72,8 +72,4 @@
return imapPassword;
}
- (NSString *) passwordInContext: (WOContext *) context
{
return password;
}
@end
@@ -58,6 +58,7 @@
wrapperWithICalEvent: [newContainer event]
andUser: [userContext sogoUser]
andSenderEmail: nil
inTimeZone: [userContext timeZone]
withConnectionInfo: [context connectionInfo]];
[self addProxy: appointmentWrapper];
}
+10 -42
View File
@@ -63,31 +63,24 @@
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;
}
- (NSArray *) rolesForExchangeRights: (uint32_t) rights
{
/* Limitations
Following rights are not supported by SOGo specifically:
- DeleteOwned : Delete only own objects
- EditOwned : Edit only own objects
- CreateSubfolders: No calendar subfolders
- FolderOwner: No sharing folder ownership?
- FolderContact: No support to store this information
- FolderVisible: It is inferred by other rights when extracting
*/
NSMutableArray *roles;
roles = [NSMutableArray arrayWithCapacity: 6];
@@ -107,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];
@@ -128,29 +113,20 @@
if ([roles containsObject: SOGoRole_ObjectCreator])
rights |= RightsCreateItems;
if ([roles containsObject: SOGoRole_ObjectEraser])
rights |= RightsDeleteAll | RightsDeleteOwn;
rights |= RightsDeleteAll;
if ([roles containsObject: SOGoCalendarRole_PublicModifier]
&& [roles containsObject: SOGoCalendarRole_PrivateModifier]
&& [roles containsObject: SOGoCalendarRole_ConfidentialModifier])
rights |= RightsReadItems | RightsEditAll | RightsEditOwn | RightsFreeBusySimple | RightsFreeBusyDetailed;
rights |= RightsReadItems | RightsEditAll;
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;
if ((rights & RightsReadItems) != 0 || (rights & RightsCreateItems) != 0 || (rights & RightsDeleteAll) != 0)
rights |= RightsReadItems | 0x1800;
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
// [self logWithFormat: @"rights for roles (%@) = %.8x", roles, rights];
return rights;
}
@@ -193,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
{
+92 -72
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];
@@ -197,6 +190,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
= [MAPIStoreAppointmentWrapper wrapperWithICalEvent: masterEvent
andUser: [userContext sogoUser]
andSenderEmail: nil
inTimeZone: [userContext timeZone]
withConnectionInfo: [context connectionInfo]];
[self addProxy: appointmentWrapper];
}
@@ -211,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
{
@@ -340,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;
@@ -493,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)
{
@@ -577,7 +597,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
}
}
- (void) save: (TALLOC_CTX *) memCtx
- (void) save: (TALLOC_CTX *) memCtx
{
// iCalCalendar *vCalendar;
// NSCalendarDate *now;
@@ -634,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];
@@ -670,7 +690,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
return newAttachment;
}
- (enum mapistore_error) setReadFlag: (uint8_t) flag
- (int) setReadFlag: (uint8_t) flag
{
return MAPISTORE_SUCCESS;
}
@@ -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)];
+4 -7
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];
@@ -96,14 +93,14 @@
if ([roles containsObject: SOGoRole_ObjectCreator])
rights |= RightsCreateItems;
if ([roles containsObject: SOGoRole_ObjectEraser])
rights |= RightsDeleteAll | RightsDeleteOwn;
rights |= RightsDeleteAll;
if ([roles containsObject: SOGoRole_ObjectEditor])
rights |= RightsEditAll | RightsEditOwn;
rights |= RightsEditAll;
if ([roles containsObject: SOGoRole_ObjectViewer])
rights |= RightsReadItems;
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
return rights;
}
File diff suppressed because it is too large. Load diff
@@ -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];
}
+18 -40
View File
@@ -102,7 +102,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
{
value = get_SPropValue_SRow (aRow, PidTagDisplayName_string8);
if (value)
folderName = [NSString stringWithUTF8String: (const char *) value->value.lpszA];
folderName = [NSString stringWithUTF8String: value->value.lpszA];
else
folderName = nil;
}
@@ -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;
}
}
@@ -321,9 +299,9 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
if ([roles containsObject: MAPIStoreRightDeleteOwn])
rights |= RightsDeleteOwn;
if ([roles containsObject: MAPIStoreRightEditAll])
rights |= RightsEditAll | RightsEditOwn;
rights |= RightsEditAll;
if ([roles containsObject: MAPIStoreRightDeleteAll])
rights |= RightsDeleteAll | RightsDeleteOwn;
rights |= RightsDeleteAll;
if ([roles containsObject: MAPIStoreRightCreateSubfolders])
rights |= RightsCreateSubfolders;
if ([roles containsObject: MAPIStoreRightFolderOwner])
@@ -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)];
+15 -231
View File
@@ -22,7 +22,6 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
@@ -35,7 +34,6 @@
#import "MAPIStoreDBFolder.h"
#import "MAPIStoreDBMessage.h"
#import "MAPIStoreTypes.h"
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
@@ -45,41 +43,26 @@
@implementation MAPIStoreDBMessage
+ (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP
inMemCtx: (TALLOC_CTX *) memCtx
+ (int) getAvailableProperties: (struct SPropTagArray **) propertiesP
inMemCtx: (TALLOC_CTX *) memCtx
{
struct SPropTagArray *properties;
NSUInteger count;
enum MAPITAGS faiProperties[] = {
0x68330048, /* PR_VIEW_CLSID */
0x68350102, /* PR_VIEW_STATE */
0x683c0102,
0x683d0040,
0x683e0102,
0x683f0102, /* PR_VIEW_VIEWTYPE_KEY */
0x68410003,
0x68420102,
0x68450102,
0x68460003,
0x7006001F, /* PR_VD_NAME_W */
0x70030003, /* PR_VD_FLAGS */
0x70070003 /* PR_VD_VERSION */
};
size_t faiSize = sizeof(faiProperties) / sizeof(enum MAPITAGS);
enum MAPITAGS faiProperties[] = { 0x68350102, 0x683c0102, 0x683e0102,
0x683f0102, 0x68410003, 0x68420102,
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];
@@ -88,13 +71,6 @@
return MAPISTORE_SUCCESS;
}
- (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP
inMemCtx: (TALLOC_CTX *) memCtx
{
return [[self class] getAvailableProperties: propertiesP
inMemCtx: memCtx];
}
- (id) initWithSOGoObject: (id) newSOGoObject
inContainer: (MAPIStoreObject *) newContainer
{
@@ -109,173 +85,22 @@
return self;
}
- (NSString *) description
{
id key, value;
NSEnumerator *propEnumerator;
NSMutableString *description;
description = [NSMutableString stringWithFormat: @"%@ %@. Properties: {", NSStringFromClass ([self class]),
[self url]];
propEnumerator = [properties keyEnumerator];
while ((key = [propEnumerator nextObject]))
{
uint32_t proptag = 0;
if ([key isKindOfClass: [NSString class]] && [(NSString *)key intValue] > 0)
proptag = [(NSString *)key intValue];
else if ([key isKindOfClass: [NSNumber class]])
proptag = [key unsignedLongValue];
if (proptag > 0)
{
const char *propTagName = get_proptag_name ([key unsignedLongValue]);
NSString *propName;
if (propTagName)
propName = [NSString stringWithCString: propTagName
encoding: NSUTF8StringEncoding];
else
propName = [NSString stringWithFormat: @"0x%.4x", [key unsignedLongValue]];
[description appendFormat: @"'%@': ", propName];
}
else
[description appendFormat: @"'%@': ", key];
value = [properties objectForKey: key];
[description appendFormat: @"%@ (%@), ", value, NSStringFromClass ([value class])];
}
[description appendString: @"}\n"];
return description;
}
- (uint64_t) objectVersion
{
/* Return the global counter from CN structure.
See [MS-OXCFXICS] Section 2.2.2.1 */
NSNumber *versionNbr, *cn;
NSNumber *versionNbr;
uint64_t objectVersion;
[(SOGoMAPIDBMessage *) sogoObject reloadIfNeeded];
versionNbr = [properties objectForKey: @"version_number"];
versionNbr = [properties objectForKey: @"version"];
if (versionNbr)
objectVersion = exchange_globcnt ([versionNbr unsignedLongLongValue]);
objectVersion = (([versionNbr unsignedLongLongValue] >> 16)
& 0x0000ffffffffffffLL);
else
{
/* Old version which stored the CN structure not useful for searching */
cn = [properties objectForKey: @"version"];
if (cn)
objectVersion = (([cn unsignedLongLongValue] >> 16)
& 0x0000ffffffffffffLL);
else
objectVersion = ULLONG_MAX;
}
objectVersion = ULLONG_MAX;
return objectVersion;
}
- (void) _updatePredecessorChangeList
{
BOOL updated;
enum mapistore_error rc;
NSData *currentChangeList, *changeKey;
NSMutableArray *changeKeys;
NSMutableData *newChangeList;
NSUInteger count, len;
struct SizedXid *changes;
struct SPropValue property;
struct SRow aRow;
struct XID *currentChangeKey;
TALLOC_CTX *localMemCtx;
uint32_t nChanges;
localMemCtx = talloc_new (NULL);
if (!localMemCtx)
{
[self errorWithFormat: @"No more memory"];
return;
}
changeKey = [self getReplicaKeyFromGlobCnt: [self objectVersion]];
currentChangeList = [properties objectForKey: MAPIPropertyKey (PidTagPredecessorChangeList)];
if (!currentChangeList)
{
/* Create a new PredecessorChangeList */
len = [changeKey length];
newChangeList = [NSMutableData dataWithCapacity: len + 1];
[newChangeList appendUInt8: len];
[newChangeList appendData: changeKey];
}
else
{
/* Update current predecessor change list with new change key */
changes = [currentChangeList asSizedXidArrayInMemCtx: localMemCtx
with: &nChanges];
updated = NO;
currentChangeKey = [changeKey asXIDInMemCtx: localMemCtx];
for (count = 0; count < nChanges && !updated; count++)
{
if (GUID_equal(&changes[count].XID.NameSpaceGuid, &currentChangeKey->NameSpaceGuid))
{
NSData *globCnt, *oldGlobCnt;
oldGlobCnt = [NSData dataWithBytes: changes[count].XID.LocalId.data length: changes[count].XID.LocalId.length];
globCnt = [NSData dataWithBytes: currentChangeKey->LocalId.data length: currentChangeKey->LocalId.length];
if ([globCnt compare: oldGlobCnt] == NSOrderedDescending)
{
if ([globCnt length] != [oldGlobCnt length])
{
[self errorWithFormat: @"Cannot compare globcnt with different length: %@ and %@", globCnt, oldGlobCnt];
abort();
}
memcpy (changes[count].XID.LocalId.data, currentChangeKey->LocalId.data, currentChangeKey->LocalId.length);
updated = YES;
}
}
}
/* Serialise it */
changeKeys = [NSMutableArray array];
if (!updated)
[changeKeys addObject: changeKey];
for (count = 0; count < nChanges; count++)
{
changeKey = [NSData dataWithXID: &changes[count].XID];
[changeKeys addObject: changeKey];
}
[changeKeys sortUsingFunction: MAPIChangeKeyGUIDCompare context: localMemCtx];
newChangeList = [NSMutableData data];
len = [changeKeys count];
for (count = 0; count < len; count++)
{
changeKey = [changeKeys objectAtIndex: count];
[newChangeList appendUInt8: [changeKey length]];
[newChangeList appendData: changeKey];
}
}
if ([newChangeList length] > 0)
{
property.ulPropTag = PidTagPredecessorChangeList;
property.value.bin = *[newChangeList asBinaryInMemCtx: localMemCtx];
aRow.cValues = 1;
aRow.lpProps = &property;
rc = [self addPropertiesFromRow: &aRow];
if (rc != MAPISTORE_SUCCESS)
[self errorWithFormat: @"Impossible to add a new predecessor change list: %d", rc];
}
talloc_free (localMemCtx);
}
//
// FIXME: how this can happen?
//
@@ -335,19 +160,10 @@
[properties setObject: attachmentParts forKey: @"attachments"];
newVersion = [[self context] getNewChangeNumber];
newVersion = exchange_globcnt ((newVersion >> 16) & 0x0000ffffffffffffLL);
[properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion]
forKey: @"version_number"];
forKey: @"version"];
/* Remove old version */
[properties removeObjectForKey: @"version"];
/* Update PredecessorChangeList accordingly */
[self _updatePredecessorChangeList];
// [self logWithFormat: @"Saving %@", [self description]];
// [self logWithFormat: @"%d props in dict", [properties count]];
[self logWithFormat: @"%d props in dict", [properties count]];
[sogoObject save];
}
@@ -390,36 +206,4 @@
return [sogoObject lastModified];
}
- (enum mapistore_error) setReadFlag: (uint8_t) flag
{
/* Modify PidTagMessageFlags from SetMessageReadFlag and
SyncImportReadStateChanges ROPs */
NSNumber *flags;
uint32_t newFlag;
flags = [properties objectForKey: MAPIPropertyKey (PR_MESSAGE_FLAGS)];
if (flags)
{
newFlag = [flags unsignedLongValue];
if (flag & SUPPRESS_RECEIPT)
newFlag |= MSGFLAG_READ;
if (flag & CLEAR_RN_PENDING)
newFlag &= ~MSGFLAG_RN_PENDING;
if (flag & CLEAR_READ_FLAG)
newFlag &= ~MSGFLAG_READ;
if (flag & CLEAR_NRN_PENDING)
newFlag &= ~MSGFLAG_NRN_PENDING;
}
else
{
newFlag = MSGFLAG_READ;
if (flag & CLEAR_READ_FLAG)
newFlag = 0x0;
}
[properties setObject: [NSNumber numberWithUnsignedLong: newFlag]
forKey: MAPIPropertyKey (PR_MESSAGE_FLAGS)];
return MAPISTORE_SUCCESS;
}
@end
+4 -5
View File
@@ -61,15 +61,14 @@ static Class MAPIStoreDBMessageK = Nil;
if ((uint32_t) res->ulPropTag == PidTagChangeNumber)
{
SEL operator;
value = NSObjectFromMAPISPropValue (&res->lpProp);
cVersion = exchange_globcnt (([value unsignedLongLongValue] >> 16)
& 0x0000ffffffffffffLL);
version = [NSNumber numberWithUnsignedLongLong: cVersion];
operator = [self operatorFromRestrictionOperator: res->relop];
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"version_number"
operatorSelector: operator
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
[self logWithFormat: @" version: %.16lx", cVersion];
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"version"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: version];
[*qualifier autorelease];
rc = MAPIRestrictionStateNeedsEval;
+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 -2
View File
@@ -121,7 +121,6 @@
fromFolder: (MAPIStoreFolder *) sourceFolder
withMIDs: (uint64_t *) targetMids
andChangeKeys: (struct Binary_r **) targetChangeKeys
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
wantCopy: (uint8_t) want_copy
inMemCtx: (TALLOC_CTX *) memCtx;
@@ -151,7 +150,6 @@
/* helpers */
- (uint64_t) idForObjectWithKey: (NSString *) childKey;
- (MAPIStoreFolder *) rootContainer;
/* subclasses */
- (MAPIStoreMessage *) createMessage;
@@ -186,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
+218 -124
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;
}
@@ -642,7 +668,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
fromFolder: (MAPIStoreFolder *) sourceFolder
withMID: (uint64_t) targetMid
andChangeKey: (struct Binary_r *) targetChangeKey
andPredecessorChangeList: (struct Binary_r *) targetPredecessorChangeList
wantCopy: (uint8_t) wantCopy
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -651,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];
@@ -670,24 +694,19 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
[sourceMsg copyToMessage: destMsg inMemCtx: memCtx];
if (targetPredecessorChangeList)
if (targetChangeKey)
{
property.ulPropTag = PidTagPredecessorChangeList;
property.value.bin = *targetPredecessorChangeList;
property.ulPropTag = PidTagChangeKey;
property.value.bin = *targetChangeKey;
aRow.cValues = 1;
aRow.lpProps = &property;
rc = [destMsg addPropertiesFromRow: &aRow];
if (rc != MAPISTORE_SUCCESS)
{
[self errorWithFormat: @"Cannot add PredecessorChangeList on move"];
goto end;
}
goto end;
}
[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);
@@ -700,7 +719,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
fromFolder: (MAPIStoreFolder *) sourceFolder
withMIDs: (uint64_t *) targetMids
andChangeKeys: (struct Binary_r **) targetChangeKeys
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
wantCopy: (uint8_t) wantCopy
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -710,7 +728,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSString *oldMessageURL;
MAPIStoreMapping *mapping;
SOGoUser *ownerUser;
struct Binary_r *targetChangeKey, *targetPredecessorChangeList;
struct Binary_r *targetChangeKey;
//TALLOC_CTX *memCtx;
//memCtx = talloc_zero (NULL, TALLOC_CTX);
@@ -731,21 +749,14 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (oldMessageURL)
{
[oldMessageURLs addObject: oldMessageURL];
if (targetChangeKeys && targetPredecessorChangeList)
{
targetChangeKey = targetChangeKeys[count];
targetPredecessorChangeList = targetPredecessorChangeLists[count];
}
if (targetChangeKeys)
targetChangeKey = targetChangeKeys[count];
else
{
targetChangeKey = NULL;
targetPredecessorChangeList = NULL;
}
targetChangeKey = NULL;
rc = [self _moveCopyMessageWithMID: srcMids[count]
fromFolder: sourceFolder
withMID: targetMids[count]
andChangeKey: targetChangeKey
andPredecessorChangeList: targetPredecessorChangeList
wantCopy: wantCopy
inMemCtx: memCtx];
}
@@ -756,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];
@@ -763,9 +781,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
}
else
rc = MAPISTORE_ERR_DENIED;
//talloc_free (memCtx);
return rc;
}
@@ -827,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];
}
@@ -848,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];
}
@@ -875,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;
@@ -935,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];
@@ -946,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];
}
@@ -957,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
@@ -971,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];
@@ -998,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++;
@@ -1065,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 */
@@ -1086,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];
}
@@ -1117,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
@@ -1226,7 +1334,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
/*
Possible values are:
0x00000001 Modify
0x00000002 Read
0x00000004 Delete
@@ -1257,7 +1365,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
access |= 0x10;
if (userIsOwner)
access |= 0x20;
*data = MAPILongValue (memCtx, access);
return MAPISTORE_SUCCESS;
@@ -1286,7 +1394,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
rights |= RightsCreateSubfolders;
if (userIsOwner)
rights |= RightsFolderOwner | RightsFolderContact;
*data = MAPILongValue (memCtx, rights);
return MAPISTORE_SUCCESS;
@@ -1322,7 +1430,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPIBoolValue (memCtx, [self supportsSubFolders] && [[self folderKeys] count] > 0);
return MAPISTORE_SUCCESS;
}
@@ -1330,7 +1438,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = MAPILongValue (memCtx, [[self folderKeys] count]);
return MAPISTORE_SUCCESS;
}
@@ -1432,7 +1540,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
[dbObject setIsNew: YES];
newMessage = [MAPIStoreFAIMessageK mapiStoreObjectWithSOGoObject: dbObject
inContainer: self];
return newMessage;
}
@@ -1441,8 +1549,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
MAPIStoreMessage *newMessage;
WOContext *woContext;
[[self userContext] activate];
if (isAssociated)
newMessage = [self _createAssociatedMessage];
else
@@ -1549,6 +1655,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
struct Binary_r bin32;
struct AddressBookEntryId *entryId;
NSString *username;
struct ldb_context *samCtx;
if (bin && bin->cb)
{
@@ -1558,8 +1665,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
entryId = get_AddressBookEntryId (NULL, &bin32);
if (entryId)
{
username = MAPIStoreSamDBUserAttribute ([[self context] connectionInfo],
@"legacyExchangeDN",
samCtx = [[self context] connectionInfo]->sam_ctx;
username = MAPIStoreSamDBUserAttribute (samCtx, @"legacyExchangeDN",
[NSString stringWithUTF8String: entryId->X500DN],
@"sAMAccountName");
}
@@ -1606,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
@@ -1641,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)
@@ -1759,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];
@@ -1792,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;
}
+1 -3
View File
@@ -41,10 +41,8 @@
/* synchronisation */
- (BOOL) synchroniseCache;
- (BOOL) synchroniseCacheFor: (NSString *) nameInContainer;
- (void) updateVersionsForMessageWithKey: (NSString *) messageKey
withChangeKey: (NSData *) oldChangeKey
andPredecessorChangeList: (NSData *) pcl;
withChangeKey: (NSData *) newChangeKey;
- (NSNumber *) lastModifiedFromMessageChangeNumber: (NSString *) changeNumber;
- (NSString *) changeNumberForMessageWithKey: (NSString *) messageKey;
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey;
+21 -197
View File
@@ -75,7 +75,6 @@ static Class NSNumberK;
[SOGoMAPIDBMessage objectWithName: @"versions.plist"
inContainer: dbFolder]);
[versionsMessage setObjectType: MAPIInternalCacheObject];
[versionsMessage reloadIfNeeded];
}
- (void) dealloc
@@ -262,6 +261,7 @@ static Class NSNumberK;
*/
- (void) _setChangeKey: (NSData *) changeKey
forMessageEntry: (NSMutableDictionary *) messageEntry
inChangeListOnly: (BOOL) inChangeListOnly
{
struct XID *xid;
NSString *guid;
@@ -270,15 +270,19 @@ static Class NSNumberK;
NSMutableDictionary *changeList;
xid = [changeKey asXIDInMemCtx: NULL];
guid = [NSString stringWithGUID: &xid->NameSpaceGuid];
globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length];
guid = [NSString stringWithGUID: &xid->GUID];
globCnt = [NSData dataWithBytes: xid->Data length: xid->Size];
talloc_free (xid);
/* 1. set change key association */
changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys: guid, @"GUID",
globCnt, @"LocalId",
nil];
[messageEntry setObject: changeKeyDict forKey: @"ChangeKey"];
if (!inChangeListOnly)
{
/* 1. set change key association */
changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys:
guid, @"GUID",
globCnt, @"LocalId",
nil];
[messageEntry setObject: changeKeyDict forKey: @"ChangeKey"];
}
/* 2. append/update predecessor change list */
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
@@ -292,77 +296,6 @@ static Class NSNumberK;
[changeList setObject: globCnt forKey: guid];
}
- (void) _updatePredecessorChangeList: (NSData *) predecessorChangeList
forMessageEntry: (NSMutableDictionary *) messageEntry
withOldChangeKey: (NSData *) oldChangeKey
{
NSData *globCnt, *oldGlobCnt;
NSDictionary *changeKeyDict;
NSString *guid;
NSMutableDictionary *changeList;
struct SizedXid *sizedXIDList;
struct XID xid, *givenChangeKey;
TALLOC_CTX *localMemCtx;
uint32_t i, length;
localMemCtx = talloc_new (NULL);
if (!localMemCtx)
{
[self errorWithFormat: @"No more memory"];
return;
}
if (predecessorChangeList)
{
sizedXIDList = [predecessorChangeList asSizedXidArrayInMemCtx: localMemCtx with: &length];
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
if (!changeList)
{
changeList = [NSMutableDictionary new];
[messageEntry setObject: changeList
forKey: @"PredecessorChangeList"];
[changeList release];
}
if (sizedXIDList) {
for (i = 0; i < length; i++)
{
xid = sizedXIDList[i].XID;
guid = [NSString stringWithGUID: &xid.NameSpaceGuid];
globCnt = [NSData dataWithBytes: xid.LocalId.data length: xid.LocalId.length];
oldGlobCnt = [changeList objectForKey: guid];
if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending))
[changeList setObject: globCnt forKey: guid];
}
}
}
if (oldChangeKey)
{
givenChangeKey = [oldChangeKey asXIDInMemCtx: localMemCtx];
if (givenChangeKey) {
guid = [NSString stringWithGUID: &givenChangeKey->NameSpaceGuid];
globCnt = [NSData dataWithBytes: givenChangeKey->LocalId.data length: givenChangeKey->LocalId.length];
changeKeyDict = [messageEntry objectForKey: @"ChangeKey"];
if (!changeKeyDict ||
([guid isEqualToString: [changeKeyDict objectForKey: @"GUID"]]
&& ([globCnt compare: [changeKeyDict objectForKey: @"LocalId"]] == NSOrderedDescending)))
{
/* The given change key is greater than current one stored in
metadata or it does not exist */
[messageEntry setObject: [NSDictionary dictionaryWithObjectsAndKeys: guid, @"GUID",
globCnt, @"LocalId",
nil]
forKey: @"ChangeKey"];
}
}
}
talloc_free (localMemCtx);
}
- (EOQualifier *) componentQualifier
{
if (!componentQualifier)
@@ -532,7 +465,8 @@ static Class NSNumberK;
// A GLOBCNT structure is a 6-byte global namespace counter,
// we strip the first 2 bytes. The first two bytes is the ReplicaId
changeKey = [self getReplicaKeyFromGlobCnt: newChangeNum >> 16];
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
[self _setChangeKey: changeKey forMessageEntry: messageEntry
inChangeListOnly: NO];
}
now = [NSCalendarDate date];
@@ -548,123 +482,13 @@ static Class NSNumberK;
return rc;
}
- (BOOL) synchroniseCacheFor: (NSString *) nameInContainer
{
/* Try to synchronise old messages in versions.plist cache using an
specific c_name. It returns a boolean indicating if the
synchronisation was carried out succesfully.
It should be used as last resort, keeping synchroniseCache as the
main sync entry point. */
uint64_t changeNumber;
NSString *changeNumberStr;
NSData *changeKey;
NSNumber *cLastModified, *cDeleted, *cVersion;
EOFetchSpecification *fs;
EOQualifier *searchQualifier, *fetchQualifier;
NSArray *fetchResults;
NSDictionary *result;
NSMutableDictionary *currentProperties, *messages, *mapping, *messageEntry;
GCSFolder *ocsFolder;
static NSArray *fields;
[versionsMessage reloadIfNeeded];
currentProperties = [versionsMessage properties];
messages = [currentProperties objectForKey: @"Messages"];
if (!messages)
{
messages = [NSMutableDictionary new];
[currentProperties setObject: messages forKey: @"Messages"];
[messages release];
}
messageEntry = [messages objectForKey: nameInContainer];
if (!messageEntry)
{
/* Fetch the message by its name */
if (!fields)
fields = [[NSArray alloc]
initWithObjects: @"c_name", @"c_version", @"c_lastmodified",
@"c_deleted", nil];
searchQualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_name"
operatorSelector: EOQualifierOperatorEqual
value: nameInContainer];
fetchQualifier = [[EOAndQualifier alloc]
initWithQualifiers: searchQualifier,
[self contentComponentQualifier],
nil];
[fetchQualifier autorelease];
[searchQualifier release];
ocsFolder = [sogoObject ocsFolder];
fs = [EOFetchSpecification
fetchSpecificationWithEntityName: [ocsFolder folderName]
qualifier: fetchQualifier
sortOrderings: nil];
fetchResults = [ocsFolder fetchFields: fields
fetchSpecification: fs
ignoreDeleted: NO];
if ([fetchResults count] == 1)
{
result = [fetchResults objectAtIndex: 0];
cLastModified = [result objectForKey: @"c_lastmodified"];
cDeleted = [result objectForKey: @"c_deleted"];
if ([cDeleted isKindOfClass: NSNumberK] && [cDeleted intValue])
cVersion = [NSNumber numberWithInt: -1];
else
cVersion = [result objectForKey: @"c_version"];
changeNumber = [[self context] getNewChangeNumber];
changeNumberStr = [NSString stringWithUnsignedLongLong: changeNumber];
/* Create new message entry in Messages dict */
messageEntry = [NSMutableDictionary new];
[messages setObject: messageEntry forKey: nameInContainer];
[messageEntry release];
/* Store cLastModified, cVersion and the change number */
[messageEntry setObject: cLastModified forKey: @"c_lastmodified"];
[messageEntry setObject: cVersion forKey: @"c_version"];
[messageEntry setObject: changeNumberStr forKey: @"version"];
/* Store the change key */
changeKey = [self getReplicaKeyFromGlobCnt: changeNumber >> 16];
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
/* Store the changeNumber -> cLastModified mapping */
mapping = [currentProperties objectForKey: @"VersionMapping"];
if (!mapping)
{
mapping = [NSMutableDictionary new];
[currentProperties setObject: mapping forKey: @"VersionMapping"];
[mapping release];
}
[mapping setObject: cLastModified forKey: changeNumberStr];
/* Save the message */
[versionsMessage save];
return YES;
}
else
return NO;
}
/* If message entry exists, then synchroniseCache did its job */
return YES;
}
- (void) updateVersionsForMessageWithKey: (NSString *) messageKey
withChangeKey: (NSData *) oldChangeKey
andPredecessorChangeList: (NSData *) pcl
withChangeKey: (NSData *) newChangeKey
{
NSMutableDictionary *messages, *messageEntry;
[self synchroniseCache];
if (oldChangeKey || pcl)
if (newChangeKey)
{
messages = [[versionsMessage properties] objectForKey: @"Messages"];
messageEntry = [messages objectForKey: messageKey];
@@ -672,8 +496,8 @@ static Class NSNumberK;
[NSException raise: @"MAPIStoreIOException"
format: @"no version record found for message '%@'",
messageKey];
[self _updatePredecessorChangeList: pcl forMessageEntry: messageEntry
withOldChangeKey: oldChangeKey];
[self _setChangeKey: newChangeKey forMessageEntry: messageEntry
inChangeListOnly: YES];
[versionsMessage save];
}
}
@@ -681,12 +505,12 @@ static Class NSNumberK;
- (NSNumber *) lastModifiedFromMessageChangeNumber: (NSString *) changeNumber
{
NSDictionary *mapping;
NSNumber *lastModified;
NSNumber *modseq;
mapping = [[versionsMessage properties] objectForKey: @"VersionMapping"];
lastModified = [mapping objectForKey: changeNumber];
modseq = [mapping objectForKey: changeNumber];
return lastModified;
return modseq;
}
- (NSString *) changeNumberForMessageWithKey: (NSString *) messageKey
+16 -39
View File
@@ -140,16 +140,9 @@
[parentFolder synchroniseCache];
changeKey = [parentFolder changeKeyForMessageWithKey: nameInContainer];
}
if (changeKey)
*data = [changeKey asBinaryInMemCtx: memCtx];
else
{
[self warnWithFormat: @"No change key for %@ in folder %@",
nameInContainer,
[parentFolder url]
];
rc = MAPISTORE_ERR_NOT_FOUND;
}
if (!changeKey)
abort ();
*data = [changeKey asBinaryInMemCtx: memCtx];
}
return rc;
@@ -187,8 +180,7 @@
{
uint64_t version = ULLONG_MAX;
NSString *changeNumber;
BOOL synced;
if (!isNew)
{
changeNumber = [(MAPIStoreGCSFolder *) container
@@ -197,28 +189,16 @@
{
[self warnWithFormat: @"attempting to get change number"
@" by synchronising folder..."];
synced = [(MAPIStoreGCSFolder *) container synchroniseCache];
if (synced)
[(MAPIStoreGCSFolder *) container synchroniseCache];
changeNumber = [(MAPIStoreGCSFolder *) container
changeNumberForMessageWithKey: [self nameInContainer]];
if (changeNumber)
[self logWithFormat: @"got one"];
else
{
changeNumber = [(MAPIStoreGCSFolder *) container
changeNumberForMessageWithKey: [self nameInContainer]];
}
if (!changeNumber)
{
[self warnWithFormat: @"attempting to get change number"
@" by synchronising this specific message..."];
synced = [(MAPIStoreGCSFolder *) container
synchroniseCacheFor: [self nameInContainer]];
if (synced)
{
changeNumber = [(MAPIStoreGCSFolder *) container
changeNumberForMessageWithKey: [self nameInContainer]];
}
if (!changeNumber)
{
[self errorWithFormat: @"still nothing. We crash!"];
abort();
}
[self errorWithFormat: @"still nothing. We crash!"];
abort();
}
}
version = [changeNumber unsignedLongLongValue] >> 16;
@@ -229,16 +209,13 @@
- (void) updateVersions
{
/* Update ChangeKey and PredecessorChangeList on message's save */
NSData *newChangeKey, *predecessorChangeList;
NSData *newChangeKey;
newChangeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)];
predecessorChangeList = [properties objectForKey: MAPIPropertyKey (PR_PREDECESSOR_CHANGE_LIST)];
[(MAPIStoreGCSFolder *) container
updateVersionsForMessageWithKey: [self nameInContainer]
withChangeKey: newChangeKey
andPredecessorChangeList: predecessorChangeList];
updateVersionsForMessageWithKey: [self nameInContainer]
withChangeKey: newChangeKey];
}
@end
+4 -14
View File
@@ -27,7 +27,6 @@
#import <Foundation/NSString.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSObject+Values.h>
#import <EOControl/EOFetchSpecification.h>
#import <EOControl/EOQualifier.h>
@@ -39,6 +38,7 @@
#import "MAPIStoreTypes.h"
#import "MAPIStoreGCSFolder.h"
#import "MAPIStoreGCSMessageTable.h"
#undef DEBUG
@@ -89,31 +89,21 @@
if (res->ulPropTag == PidTagChangeNumber)
{
NSString *changeNumber;
value = NSObjectFromMAPISPropValue (&res->lpProp);
changeNumber = [NSString stringWithUnsignedLongLong: [(NSNumber *)value unsignedLongLongValue]];
lastModified = [(MAPIStoreGCSFolder *)
container lastModifiedFromMessageChangeNumber: changeNumber];
container lastModifiedFromMessageChangeNumber: value];
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
//[self logWithFormat: @" c_lastmodified: %@", lastModified];
if (lastModified)
{
SEL operator;
operator = [self operatorFromRestrictionOperator: res->relop];
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_lastmodified"
operatorSelector: operator
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: lastModified];
[*qualifier autorelease];
rc = MAPIRestrictionStateNeedsEval;
}
else
{
[self logWithFormat: @"No last modified found for: 0x%.16"PRIx64". Then no restriction applied",
[value unsignedLongLongValue]];
rc = MAPIRestrictionStateAlwaysTrue;
}
rc = MAPIRestrictionStateAlwaysTrue;
}
else
{
+21 -23
View File
@@ -30,7 +30,6 @@
#import <SOGo/NSArray+Utilities.h>
#import <Mailer/SOGoMailBodyPart.h>
#import <Mailer/SOGoMailObject.h>
#import <Mailer/NSDictionary+Mail.h>
#import "MAPIStoreTypes.h"
#import "MAPIStoreMailMessage.h"
@@ -109,7 +108,7 @@
static char recordBytes[] = {0xd9, 0xd8, 0x11, 0xa3, 0xe2, 0x90, 0x18, 0x41,
0x9e, 0x04, 0x58, 0x46, 0x9d, 0x6d, 0x1b,
0x68};
*data = [[NSData dataWithBytes: recordBytes length: 16]
asBinaryInMemCtx: memCtx];
@@ -118,7 +117,19 @@
- (NSString *) _fileName
{
return [bodyInfo filename];
NSString *fileName;
NSDictionary *parameters;
fileName = [[bodyInfo objectForKey: @"parameterList"]
objectForKey: @"name"];
if (!fileName)
{
parameters = [[bodyInfo objectForKey: @"disposition"]
objectForKey: @"parameterList"];
fileName = [parameters objectForKey: @"filename"];
}
return fileName;
}
- (int) getPidTagAttachLongFilename: (void **) data
@@ -152,22 +163,15 @@
- (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;
}
- (int) getPidTagAttachContentId: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
{
*data = [[bodyInfo objectForKey: @"bodyId"]
asUnicodeInMemCtx: memCtx];
@@ -177,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;
+15 -40
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,25 +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 ,(2) asCSSIdentifier and (3) "folder"-prefixed
// e.g.: folderProbl&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 substringFromIndex: 6]
fromCSSIdentifier]
stringByDecodingImap4FolderName];
// And finally to represent that as URI we have to (1) asCSSIdentifier,
// (2) Imap4Encode (3) AddPercentEscapes and (4) add the "folder" prefix
// e.g.: folderProbl&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];
stringData = [NSString stringWithFormat: @"folder%@", stringData];
context->url = [[NSString stringWithFormat: @"%@%@", urlBase, stringData] asUnicodeInMemCtx: context];
context->name = [realName 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";
@@ -200,20 +180,19 @@ MakeDisplayFolderName (NSString *folderName)
userContext = [MAPIStoreUserContext userContextWithUsername: userName
andTDBIndexing: NULL];
[MAPIApp setUserContext: userContext];
accountFolder = [[userContext rootFolders] objectForKey: @"mail"];
folderName = [NSString stringWithFormat: @"folder%@",
[[newFolderName stringByEncodingImap4FolderName] asCSSIdentifier]];
[newFolderName asCSSIdentifier]];
newFolder = [SOGoMailFolder objectWithName: folderName
inContainer: accountFolder];
if ([newFolder create])
mapistoreURI = [NSString stringWithFormat: @"sogo://%@:%@@mail/%@/",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
[folderName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
userName, userName,
[[folderName stringByEncodingImap4FolderName] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
else
mapistoreURI = nil;
[MAPIApp setUserContext: nil];
return mapistoreURI;
}
@@ -285,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];
-10
View File
@@ -44,24 +44,14 @@
/* 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;
- (void) setChangeKey: (NSData *) changeKey
forMessageWithKey: (NSString *) messageKey;
- (BOOL) updatePredecessorChangeListWith: (NSData *) changeKey
forMessageWithKey: (NSString *) messageKey;
- (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
File diff suppressed because it is too large. Load diff
-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;
+80 -247
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>
@@ -40,9 +39,7 @@
#import <Mailer/NSData+Mail.h>
#import <Mailer/SOGoMailBodyPart.h>
#import <Mailer/SOGoMailObject.h>
#import <Mailer/NSDictionary+Mail.h>
#import "Codepages.h"
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
@@ -53,7 +50,6 @@
#import "MAPIStoreMailFolder.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreSamDBUtils.h"
#import "MAPIStoreSharingMessage.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
@@ -67,7 +63,7 @@
@class iCalCalendar, iCalEvent;
static Class NSExceptionK, MAPIStoreSharingMessageK;
static Class NSExceptionK;
@interface NSString (MAPIStoreMIME)
@@ -110,7 +106,6 @@ static Class NSExceptionK, MAPIStoreSharingMessageK;
+ (void) initialize
{
NSExceptionK = [NSException class];
MAPIStoreSharingMessageK = [MAPIStoreSharingMessage class];
}
- (id) init
@@ -119,8 +114,6 @@ static Class NSExceptionK, MAPIStoreSharingMessageK;
{
mimeKey = nil;
mailIsEvent = NO;
mailIsMeetingRequest = NO;
mailIsSharingObject = NO;
headerCharset = nil;
headerEncoding = nil;
headerMimeType = nil;
@@ -139,7 +132,6 @@ static Class NSExceptionK, MAPIStoreSharingMessageK;
[bodyContent release];
[headerMimeType release];
[headerCharset release];
[headerEncoding release];
[appointmentWrapper release];
[super dealloc];
}
@@ -159,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)
{
@@ -197,7 +165,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
count1 = [keys indexOfObject: data1];
data2 = [entry2 objectForKey: @"mimeType"];
count2 = [keys indexOfObject: data2];
if (count1 == count2)
{
data1 = [entry1 objectForKey: @"key"];
@@ -232,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",
@@ -260,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;
@@ -340,6 +286,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
wrapperWithICalEvent: event
andUser: [context activeUser]
andSenderEmail: senderEmail
inTimeZone: [[self userContext] timeZone]
withConnectionInfo: [context connectionInfo]];
[appointmentWrapper retain];
}
@@ -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;
@@ -521,9 +456,6 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
NSUInteger colIdx;
NSString *stringValue;
/* As specified in [MS-OXCMAIL] 2.2.3.2.6.1, if there are three
or less characters followed by a colon at the beginning of
the subject, we can assume that's the subject prefix */
subject = [self subject];
colIdx = [subject rangeOfString: @":"].location;
if (colIdx != NSNotFound && colIdx < 4)
@@ -532,52 +464,24 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
else
stringValue = @"";
*data = [stringValue asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidTagNormalizedSubject: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *stringValue, *subject;
NSUInteger quoteStartIdx, quoteEndIdx, colIdx;
NSRange quoteRange;
if (!headerSetup)
[self _fetchHeaderData];
NSString *subject;
NSUInteger colIdx;
NSString *stringValue;
subject = [self subject];
if (mailIsMeetingRequest)
{
/* SOGo "spices up" the invitation/update mail's subject, but
the client uses it to name the attendee's event, so we keep
only what's inside the quotes */
quoteStartIdx = [subject rangeOfString: @"\""].location;
quoteEndIdx = [subject rangeOfString: @"\""
options: NSBackwardsSearch].location;
if (quoteStartIdx != NSNotFound
&& quoteEndIdx != NSNotFound
&& quoteStartIdx != quoteEndIdx)
{
quoteRange = NSMakeRange(quoteStartIdx + 1, quoteEndIdx - quoteStartIdx - 1);
stringValue = [subject substringWithRange: quoteRange];
}
else stringValue = subject;
}
colIdx = [subject rangeOfString: @":"].location;
if (colIdx != NSNotFound && colIdx < 4)
stringValue = [[subject substringFromIndex: colIdx + 1]
stringByTrimmingLeadSpaces];
else
{
/* As specified in [MS-OXCMAIL] 2.2.3.2.6.1, if there are three
or less characters followed by a colon at the beginning of
the subject, we can assume that's the subject prefix */
colIdx = [subject rangeOfString: @":"].location;
if (colIdx != NSNotFound && colIdx < 4)
stringValue = [[subject substringFromIndex: colIdx + 1]
stringByTrimmingLeadSpaces];
else
stringValue = subject;
}
stringValue = subject;
if (!stringValue)
stringValue = @"";
*data = [stringValue asUnicodeInMemCtx: memCtx];
@@ -600,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
{
@@ -655,7 +564,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
NSDictionary *coreInfos;
NSArray *flags;
unsigned int v = 0;
coreInfos = [sogoObject fetchCoreInfos];
flags = [coreInfos objectForKey: @"flags"];
@@ -667,7 +576,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if ([[self attachmentKeys]
count] > 0)
v |= MSGFLAG_HASATTACH;
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
@@ -687,7 +596,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
v = 2;
else
v = 0;
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
@@ -699,15 +608,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
NSDictionary *coreInfos;
NSArray *flags;
unsigned int v;
coreInfos = [sogoObject fetchCoreInfos];
flags = [coreInfos objectForKey: @"flags"];
if ([flags containsObject: @"flagged"])
v = 6;
else
v = 0;
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
@@ -786,7 +695,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if ([ngAddress isKindOfClass: [NGMailAddress class]])
{
cn = [ngAddress displayName];
// If we don't have a displayName, we use the email address instead. This
// avoid bug #2119 - where Outlook won't display anything in the "From" field,
// nor in the recipient field if we reply to the email.
@@ -810,6 +719,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
NSDictionary *contactInfos;
NGMailAddress *ngAddress;
NSData *entryId;
struct ldb_context *samCtx;
int rc;
if (fullMail)
@@ -831,14 +741,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
contactInfos = [mgr contactInfosForUserWithUIDorEmail: email];
if (contactInfos)
{
username = [contactInfos objectForKey: @"sAMAccountName"];
entryId = MAPIStoreInternalEntryId([[self context] connectionInfo], username);
username = [contactInfos objectForKey: @"c_uid"];
samCtx = [[self context] connectionInfo]->sam_ctx;
entryId = MAPIStoreInternalEntryId (samCtx, username);
}
else
entryId = MAPIStoreExternalEntryId (cn, email);
*data = [entryId asBinaryInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
else
@@ -995,15 +906,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
{
uint32_t v;
NSString *s;
s = [[sogoObject mailHeaders] objectForKey: @"x-priority"];
v = 0x1;
if ([s hasPrefix: @"1"]) v = 0x2;
else if ([s hasPrefix: @"2"]) v = 0x2;
else if ([s hasPrefix: @"4"]) v = 0x0;
else if ([s hasPrefix: @"5"]) v = 0x0;
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
@@ -1012,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;
}
@@ -1192,14 +1101,14 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if (!headerSetup)
[self _fetchHeaderData];
if ([headerMimeType isEqualToString: @"text/plain"])
format = EDITOR_FORMAT_PLAINTEXT;
else if ([headerMimeType isEqualToString: @"text/html"])
format = EDITOR_FORMAT_HTML;
else
format = 0; /* EDITOR_FORMAT_DONTKNOW */
*data = MAPILongValue (memCtx, format);
return MAPISTORE_SUCCESS;
@@ -1424,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
{
@@ -1475,9 +1349,11 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
NSData *entryId;
NSDictionary *contactInfos;
SOGoUserManager *mgr;
struct ldb_context *samCtx;
struct mapistore_message *msgData;
struct mapistore_message_recipient *recipient;
samCtx = [[self context] connectionInfo]->sam_ctx;
[super getMessageData: &msgData inMemCtx: memCtx];
if (!headerSetup)
@@ -1526,12 +1402,12 @@ _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 ([[self context] connectionInfo], username);
entryId = MAPIStoreInternalEntryId (samCtx, username);
}
else
{
@@ -1544,7 +1420,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
p = 0;
recipient->data = talloc_array (msgData, void *, msgData->columns->cValues);
memset (recipient->data, 0, msgData->columns->cValues * sizeof (void *));
// PR_OBJECT_TYPE = MAPI_MAILUSER (see MAPI_OBJTYPE)
recipient->data[p] = MAPILongValue (msgData, MAPI_MAILUSER);
p++;
@@ -1552,7 +1428,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
// PR_DISPLAY_TYPE = DT_MAILUSER (see MS-NSPI)
recipient->data[p] = MAPILongValue (msgData, 0);
p++;
// PR_7BIT_DISPLAY_NAME_UNICODE
recipient->data[p] = [cn asUnicodeInMemCtx: msgData];
p++;
@@ -1560,7 +1436,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
// PR_SMTP_ADDRESS_UNICODE
recipient->data[p] = [email asUnicodeInMemCtx: msgData];
p++;
// PR_SEND_INTERNET_ENCODING = 0x00060000 (plain text, see OXCMAIL)
recipient->data[p] = MAPILongValue (msgData, 0x00060000);
p++;
@@ -1593,9 +1469,12 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
withPrefix: (NSString *) keyPrefix
{
NSArray *parts;
NSDictionary *parameters;
NSUInteger count, max;
if ([[bodyInfo filename] length] > 0)
parameters = [[bodyInfo objectForKey: @"disposition"]
objectForKey: @"parameterList"];
if ([[parameters objectForKey: @"filename"] length] > 0)
{
if ([keyPrefix length] == 0)
keyPrefix = @"0";
@@ -1638,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];
@@ -1669,13 +1546,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
return attachment;
}
- (enum mapistore_error) setReadFlag: (uint8_t) flag
- (int) setReadFlag: (uint8_t) flag
{
NSString *imapFlag = @"\\Seen";
/* TODO: notifications should probably be emitted from here */
if (flag & CLEAR_READ_FLAG)
[properties setObject: [NSNumber numberWithBool: NO] forKey: @"read_flag_set"];
[sogoObject removeFlags: imapFlag];
else
[properties setObject: [NSNumber numberWithBool: YES] forKey: @"read_flag_set"];
[sogoObject addFlags: imapFlag];
return MAPISTORE_SUCCESS;
}
@@ -1687,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;
}
@@ -1701,27 +1584,9 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
bodySetup = YES;
}
- (MAPIStoreSharingMessage *) _sharingObject
- (void) save: (TALLOC_CTX *) memCtx
{
/* 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
{
BOOL modified = NO;
BOOL seen, storedSeenFlag;
NSNumber *value;
NSString *imapFlag = @"\\Seen";
value = [properties objectForKey: MAPIPropertyKey (PR_FLAG_STATUS)];
if (value)
@@ -1731,39 +1596,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
[sogoObject addFlags: @"\\Flagged"];
else /* 0: unflagged, 1: follow up complete */
[sogoObject removeFlags: @"\\Flagged"];
modified = YES;
}
/* Manage seen flag on save */
value = [properties objectForKey: @"read_flag_set"];
if (value)
{
seen = [value boolValue];
storedSeenFlag = [[[sogoObject fetchCoreInfos] objectForKey: @"flags"] containsObject: @"seen"];
/* We modify the flags anyway to generate a new change number */
if (seen)
{
if (storedSeenFlag)
[sogoObject removeFlags: imapFlag];
[sogoObject addFlags: imapFlag];
}
else
{
if (!storedSeenFlag)
[sogoObject addFlags: imapFlag];
[sogoObject removeFlags: imapFlag];
}
modified = YES;
}
if (modified)
[(MAPIStoreMailFolder *)[self container] synchroniseCache];
if (mailIsSharingObject)
[[self _sharingObject] saveWithMessage: self
andSOGoObject: sogoObject];
}
@end
+7 -22
View File
@@ -161,30 +161,15 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK;
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
//[self logWithFormat: @" modseq: %.16lx", [modseq unsignedLongLongValue]];
if (modseq)
{
if (res->relop == RELOP_GT)
modseq = [NSNumber numberWithUnsignedLongLong:
[modseq unsignedLongLongValue] + 1];
}
modseq = [NSNumber numberWithUnsignedLongLong:
[modseq unsignedLongLongValue] + 1];
else
modseq = [NSNumber numberWithUnsignedLongLong: 0];
if (res->relop == RELOP_GT || res->relop == RELOP_GE)
{
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"MODSEQ"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: modseq];
[*qualifier autorelease];
rc = MAPIRestrictionStateNeedsEval;
}
else
{
/* Ignore other operations as IMAP only support MODSEQ >= X */
[self warnWithFormat: @"Ignoring '%@' as only supported operators are > and >=",
NSStringFromSelector ([self operatorFromRestrictionOperator: res->relop])];
rc = MAPIRestrictionStateAlwaysTrue;
}
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"MODSEQ"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: modseq];
[*qualifier autorelease];
rc = MAPIRestrictionStateNeedsEval;
}
break;
+49 -260
View File
@@ -28,13 +28,11 @@
#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/NSObject+Values.h>
#import <NGExtensions/NSString+Encoding.h>
#import <NGMime/NGMimeBodyPart.h>
#import <NGMime/NGMimeMultipartBody.h>
@@ -45,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>
@@ -53,7 +50,6 @@
#import <Mailer/SOGoMailFolder.h>
#import <Mailer/NSString+Mail.h>
#import "Codepages.h"
#import "MAPIStoreAttachment.h"
#import "MAPIStoreAttachmentTable.h"
#import "MAPIStoreContext.h"
@@ -66,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;
@@ -167,9 +163,9 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
- (BOOL) hasContentId
{
NSString *contentId = [properties
objectForKey: MAPIPropertyKey (PR_ATTACH_CONTENT_ID_UNICODE)];
return contentId && [contentId length] > 0;
return ([properties
objectForKey: MAPIPropertyKey (PR_ATTACH_CONTENT_ID_UNICODE)]
!= nil);
}
- (NGMimeBodyPart *) asMIMEBodyPart
@@ -233,7 +229,7 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
[map addObject: contentDisposition forKey: @"content-disposition"];
contentId = [properties
objectForKey: MAPIPropertyKey (PR_ATTACH_CONTENT_ID_UNICODE)];
if (contentId && [contentId length] > 0)
if (contentId)
[map setObject: [NSString stringWithFormat: @"<%@>", contentId]
forKey: @"content-id"];
bodyPart = [NGMimeBodyPart bodyPartWithHeader: map];
@@ -286,7 +282,7 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
version = [properties objectForKey: @"version"];
return (version
? [version unsignedLongLongValue]
? exchange_globcnt ([version unsignedLongLongValue])
: ULLONG_MAX);
}
@@ -338,10 +334,13 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
NSData *entryId;
NSDictionary *allRecipients, *dict, *contactInfos;
SOGoUserManager *mgr;
struct ldb_context *samCtx;
struct mapistore_message *msgData;
struct mapistore_message_recipient *recipient;
enum ulRecipClass type;
samCtx = [[self context] connectionInfo]->sam_ctx;
// [super getMessageData: &msgData inMemCtx: memCtx];
msgData = talloc_zero (memCtx, struct mapistore_message);
@@ -384,9 +383,9 @@ 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 ([[self context] connectionInfo], username);
entryId = MAPIStoreInternalEntryId (samCtx, username);
}
else
{
@@ -532,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;
@@ -671,104 +571,10 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
list = MakeRecipientsList ([recipients objectForKey: @"orig"]);
if ([list count])
{
[headers setObjects: list forKey: @"from"];
fromResolved = YES;
}
}
if (!fromResolved)
{
TALLOC_CTX *local_mem_ctx;
local_mem_ctx = talloc_new(NULL);
if (!local_mem_ctx)
{
NSLog (@"%s: Out of memory", __PRETTY_FUNCTION__);
return;
}
NSLog (@"Message without an orig from, try to guess it from PidTagSenderEntryId");
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 (local_mem_ctx, &bin32);
if (addrBookEntryId && [[NSString stringWithGUID: &addrBookEntryId->ProviderUID]
hasSuffix: @"08002b2fe182"])
{
/* TODO: better way to distinguish local and other ones */
username = MAPIStoreSamDBUserAttribute (connInfo, @"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 (local_mem_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"];
}
}
if ([[fromRecipient allKeys] count] > 0)
{
list = MakeRecipientsList ([NSArray arrayWithObjects: fromRecipient, nil]);
if ([list count])
[headers setObjects: list forKey: @"from"];
}
}
/* Free entryId */
talloc_free(local_mem_ctx);
}
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)];
@@ -777,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)];
@@ -792,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"];
@@ -810,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 *
@@ -877,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];
@@ -1013,7 +820,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
- (NGMimeMessage *) _generateMessageWithBcc: (BOOL) withBcc
{
NSString *contentType;
NGMimeMessage *message;
NGMimeMessage *message;
NGMutableHashMap *headers;
id messageBody;
@@ -1027,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];
}
@@ -1053,7 +860,6 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
- (int) submitWithFlags: (enum SubmitFlags) flags
{
enum mapistore_error rc = MAPISTORE_SUCCESS;
NSDictionary *recipients;
NSData *messageData;
NSMutableArray *recipientEmails;
@@ -1067,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++)
@@ -1090,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]
@@ -1100,10 +905,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
withAuthenticator: authenticator
inContext: woContext];
if (error)
{
[self errorWithFormat: @"an error occurred: '%@'", error];
rc = MAPISTORE_ERR_MSG_SEND;
}
[self logWithFormat: @"an error occurred: '%@'", error];
// mapping = [self mapping];
// [mapping unregisterURLWithID: [self objectId]];
@@ -1115,13 +917,12 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
[self logWithFormat: @"skipping submit of message with class '%@'",
msgClass];
return rc;
return MAPISTORE_SUCCESS;
}
- (void) save: (TALLOC_CTX *) memCtx
{
BOOL updatedMetadata;
NSString *folderName, *flag, *newIdString, *messageKey, *changeNumber;
NSString *folderName, *flag, *newIdString, *messageKey;
NSData *changeKey, *messageData;
NGImap4Connection *connection;
NGImap4Client *client;
@@ -1157,33 +958,21 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
[sogoObject setNameInContainer: messageKey];
[mapping registerURL: [self url] withID: mid];
/* synchronise the cache and update the predecessor change list
with the change key provided by the client. Before doing
this, lets issue a unselect/select combo because of timing
issues with Dovecot in obtaining the latest modseq.
Sometimes, Dovecot doesn't return the newly appended UID if
we do a "UID SORT (DATE) UTF-8 (MODSEQ XYZ) (NOT DELETED)"
command (where XYZ is the HIGHESTMODSEQ+1) immediately after
IMAP APPEND */
/* synchronise the cache and update the change key with the one provided
by the client. Before doing this, lets issue a unselect/select combo
because of timing issues with Dovecot in obtaining the latest modseq.
Sometimes, Dovecot doesn't return the newly appended UID if we do
a "UID SORT (DATE) UTF-8 (MODSEQ XYZ) (NOT DELETED)" command (where
XYZ is the HIGHESTMODSEQ+1) immediately after IMAP APPEND */
[client unselect];
[client select: folderName];
[(MAPIStoreMailFolder *) container synchroniseCache];
changeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)];
if (changeKey)
{
updatedMetadata = [(MAPIStoreMailFolder *) container updatePredecessorChangeListWith: changeKey
forMessageWithKey: messageKey];
if (!updatedMetadata)
[self warnWithFormat: @"Predecessor change list not updated with client data"];
}
/* Update version property (PR_CHANGE_KEY indeed) as it is
requested once it is saved */
changeNumber = [(MAPIStoreMailFolder *) container changeNumberForMessageUID: newIdString];
if (changeNumber)
[properties setObject: [NSNumber numberWithUnsignedLongLong: [changeNumber unsignedLongLongValue] >> 16]
forKey: @"version"];
[(MAPIStoreMailFolder *) container
setChangeKey: changeKey
forMessageWithKey: messageKey];
}
}
-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
+1 -1
View File
@@ -63,7 +63,7 @@
withAID: (uint32_t) aid;
- (int) getAttachmentTable: (MAPIStoreAttachmentTable **) tablePtr
andRowCount: (uint32_t *) countPtr;
- (enum mapistore_error) setReadFlag: (uint8_t) flag;
- (int) setReadFlag: (uint8_t) flag;
- (enum mapistore_error) saveMessage: (TALLOC_CTX *) memCtx;
- (NSArray *) activeContainerMessageTables;
+74 -80
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];
@@ -549,12 +546,11 @@ rtf2html (NSData *compressedRTF)
}
[self save: memCtx];
/* We make sure that any change-related properties are removed from the
/* We make sure that any change-related properties are removes from the
properties dictionary, to make sure that related methods will be
invoked the next time they are requested. */
[properties removeObjectForKey: MAPIPropertyKey (PidTagChangeKey)];
[properties removeObjectForKey: MAPIPropertyKey (PidTagChangeNumber)];
[properties removeObjectForKey: MAPIPropertyKey (PidTagPredecessorChangeList)];
if ([container isKindOfClass: MAPIStoreFolderK])
{
@@ -786,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];
@@ -799,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]
@@ -811,8 +807,6 @@ rtf2html (NSData *compressedRTF)
if (rc == MAPISTORE_SUCCESS)
*data = talloc_asprintf (memCtx, "%s%s", prefix, normalizedSubject);
talloc_free(localMemCtx);
return rc;
}
@@ -919,7 +913,7 @@ rtf2html (NSData *compressedRTF)
return [self getNo: data inMemCtx: memCtx];;
}
- (enum mapistore_error) setReadFlag: (uint8_t) flag
- (int) setReadFlag: (uint8_t) flag
{
// [self subclassResponsibility: _cmd];
+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 -1
View File
@@ -103,7 +103,7 @@
else
{
connInfo = [(MAPIStoreContext *) [container context] connectionInfo];
entryId = MAPIStoreInternalEntryId (connInfo, userId);
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, userId);
}
*data = [entryId asBinaryInMemCtx: memCtx];
+4 -5
View File
@@ -27,7 +27,8 @@
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalRecurrenceRule.h>
#import <NGCards/iCalTimeZone.h>
@class NSTimeZone;
@class iCalEvent;
@class iCalRepeatableEntityObject;
@@ -40,10 +41,7 @@
@interface iCalCalendar (MAPIStoreRecurrence)
- (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity
fromRecurrencePattern: (struct RecurrencePattern *) rp
withExceptions: (struct ExceptionInfo *) exInfos
andExceptionCount: (uint16_t) exInfoCount
inTimeZone: (iCalTimeZone *) tz;
fromRecurrencePattern: (struct RecurrencePattern *) rp;
@end
@@ -51,6 +49,7 @@
- (void) fillRecurrencePattern: (struct RecurrencePattern *) rp
withEvent: (iCalEvent *) event
inTimeZone: (NSTimeZone *) timeZone
inMemCtx: (TALLOC_CTX *) memCtx;
@end
+34 -55
View File
@@ -34,7 +34,6 @@
#import <NGCards/iCalRepeatableEntityObject.h>
#import <NGCards/iCalRecurrenceRule.h>
#import <NGCards/iCalTimeZone.h>
#import <NGCards/iCalTimeZonePeriod.h>
#import "NSDate+MAPIStore.h"
#import "MAPIStoreRecurrenceUtils.h"
@@ -49,10 +48,6 @@
- (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity
fromRecurrencePattern: (struct RecurrencePattern *) rp
withExceptions: (struct ExceptionInfo *) exInfos
andExceptionCount: (uint16_t) exInfoCount
inTimeZone: (iCalTimeZone *) tz
{
NSCalendarDate *startDate, *olEndDate, *untilDate, *exDate;
NSString *monthDay, *month;
@@ -63,7 +58,7 @@
iCalWeekOccurrence weekOccurrence;
iCalWeekOccurrences dayMaskDays;
NSUInteger count, max;
NSInteger bySetPos, tzOffset;
NSInteger bySetPos;
unsigned char maskValue;
[entity removeAllRecurrenceRules];
@@ -219,43 +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];
tzOffset = -[[tz periodForDate: exDate] secondsOffsetFromGMT];
exDate = [exDate dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[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
@@ -264,6 +250,7 @@
- (void) fillRecurrencePattern: (struct RecurrencePattern *) rp
withEvent: (iCalEvent *) event
inTimeZone: (NSTimeZone *) timeZone
inMemCtx: (TALLOC_CTX *) memCtx
{
iCalRecurrenceFrequency freq;
@@ -279,8 +266,10 @@
NSMutableArray *deletedDates, *modifiedDates;
startDate = [event firstRecurrenceStartDate];
[startDate setTimeZone: timeZone];
endDate = [event lastPossibleRecurrenceStartDate];
[endDate setTimeZone: timeZone];
rp->ReaderVersion = 0x3004;
rp->WriterVersion = 0x3004;
@@ -323,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
+149 -89
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] --->");
#define NS_CURRENT_THREAD_TRY_UNREGISTER(rc) \
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] <--- [%s]", mapistore_errstr (rc));
}
#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(ret); \
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];
@@ -253,7 +233,7 @@ sogo_backend_create_context(TALLOC_CTX *mem_ctx,
rc = MAPISTORE_ERROR;
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
return rc;
}
@@ -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];
@@ -291,7 +273,7 @@ sogo_backend_create_root_folder (const char *username,
rc = MAPISTORE_ERROR;
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
return rc;
}
@@ -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];
@@ -322,7 +306,7 @@ sogo_backend_list_contexts(const char *username, struct indexing_context *indexi
rc = MAPISTORE_ERROR;
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
return rc;
}
@@ -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;
@@ -363,7 +349,7 @@ sogo_context_get_path(void *backend_object, TALLOC_CTX *mem_ctx,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -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;
@@ -397,7 +385,7 @@ sogo_context_get_root_folder(void *backend_object, TALLOC_CTX *mem_ctx,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -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;
@@ -439,7 +429,7 @@ sogo_folder_open_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -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;
@@ -480,7 +472,7 @@ sogo_folder_create_folder(void *folder_object, TALLOC_CTX *mem_ctx,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -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;
@@ -519,7 +513,7 @@ sogo_folder_delete(void *folder_object)
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -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;
@@ -549,7 +545,7 @@ sogo_folder_get_child_count(void *folder_object, enum mapistore_table_type table
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -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;
@@ -588,7 +586,7 @@ sogo_folder_open_message(void *folder_object,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -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,13 +621,13 @@ 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)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -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;
@@ -657,7 +659,7 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags)
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -674,7 +676,6 @@ sogo_folder_move_copy_messages(void *folder_object,
uint32_t mid_count,
uint64_t *src_mids, uint64_t *t_mids,
struct Binary_r **target_change_keys,
struct Binary_r **target_predecessor_change_lists,
uint8_t want_copy)
{
MAPIStoreFolder *sourceFolder, *targetFolder;
@@ -682,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;
@@ -699,13 +702,12 @@ sogo_folder_move_copy_messages(void *folder_object,
fromFolder: sourceFolder
withMIDs: t_mids
andChangeKeys: target_change_keys
andPredecessorChangeLists: target_predecessor_change_lists
wantCopy: want_copy
inMemCtx: mem_ctx];
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -725,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;
@@ -753,7 +757,7 @@ sogo_folder_move_folder(void *folder_object, void *target_folder_object,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -773,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;
@@ -795,7 +801,7 @@ sogo_folder_copy_folder(void *folder_object, void *target_folder_object, TALLOC_
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -815,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;
@@ -831,7 +839,7 @@ sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -852,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;
@@ -869,7 +879,7 @@ sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -889,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;
@@ -903,7 +915,7 @@ sogo_folder_modify_permissions(void *folder_object, uint8_t flags,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -921,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;
@@ -934,7 +948,7 @@ sogo_folder_preload_message_bodies(void *folder_object, enum mapistore_table_typ
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -954,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;
@@ -967,8 +983,8 @@ sogo_message_get_message_data(void *message_object,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER();
rc = MAPISTORE_SUCCESS;
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
}
else
{
@@ -987,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;
@@ -998,10 +1016,11 @@ 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];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1021,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;
@@ -1032,10 +1053,11 @@ 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];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1054,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;
@@ -1066,10 +1090,11 @@ 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];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1090,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;
@@ -1101,10 +1128,11 @@ sogo_message_modify_recipients (void *message_object,
rc = [message modifyRecipientsWithRecipients: recipients
andCount: count
andColumns: columns];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1120,7 +1148,9 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
struct MAPIStoreTallocWrapper *wrapper;
NSAutoreleasePool *pool;
MAPIStoreMessage *message;
enum mapistore_error rc;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
if (message_object)
{
@@ -1131,10 +1161,11 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
TRYCATCH_START
rc = [message setReadFlag: flag];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1152,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;
@@ -1161,10 +1194,11 @@ sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx)
TRYCATCH_START
rc = [message saveMessage: mem_ctx];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1182,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;
@@ -1191,10 +1227,11 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags)
TRYCATCH_START
rc = [message submitWithFlags: flags];
// [context tearDownRequest];
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1217,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;
@@ -1234,7 +1273,7 @@ sogo_message_attachment_open_embedded_message (void *attachment_object,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1256,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;
@@ -1272,7 +1313,7 @@ sogo_message_attachment_create_embedded_message (void *attachment_object,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1290,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;
@@ -1302,7 +1345,7 @@ static enum mapistore_error sogo_table_get_available_properties(void *table_obje
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1320,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;
@@ -1333,7 +1378,7 @@ sogo_table_set_columns (void *table_object, uint16_t count, enum MAPITAGS *prope
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1351,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;
@@ -1366,7 +1413,7 @@ sogo_table_set_restrictions (void *table_object, struct mapi_SRestriction *restr
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1384,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;
@@ -1399,7 +1448,7 @@ sogo_table_set_sort_order (void *table_object, struct SSortOrderSet *sort_order,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1419,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;
@@ -1432,7 +1483,7 @@ sogo_table_get_row (void *table_object, TALLOC_CTX *mem_ctx,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1452,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;
@@ -1465,7 +1518,7 @@ sogo_table_get_row_count (void *table_object,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1483,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;
@@ -1495,8 +1550,8 @@ sogo_table_handle_destructor (void *table_object, uint32_t handle_id)
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER();
rc = MAPISTORE_SUCCESS;
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
}
else
{
@@ -1515,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;
@@ -1527,7 +1584,7 @@ static enum mapistore_error sogo_properties_get_available_properties(void *objec
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1548,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;
@@ -1562,7 +1621,7 @@ sogo_properties_get_properties (void *object,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1580,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;
@@ -1592,7 +1653,7 @@ sogo_properties_set_properties (void *object, struct SRow *aRow)
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
NS_CURRENT_THREAD_TRY_UNREGISTER();
}
else
{
@@ -1603,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
@@ -1630,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: @"/"];
@@ -1646,7 +1706,7 @@ sogo_manager_generate_uri (TALLOC_CTX *mem_ctx,
TRYCATCH_END(pool)
[pool release];
NS_CURRENT_THREAD_TRY_UNREGISTER(MAPISTORE_SUCCESS);
NS_CURRENT_THREAD_TRY_UNREGISTER();
return MAPISTORE_SUCCESS;
}
@@ -1658,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;
@@ -1716,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;
+1 -3
View File
@@ -197,7 +197,6 @@ static Class MAPIStoreFolderK;
inMemCtx: (TALLOC_CTX *) memCtx
{
int rc;
struct mapistore_connection_info *connInfo;
uint64_t obVersion;
obVersion = [self objectVersion];
@@ -205,9 +204,8 @@ static Class MAPIStoreFolderK;
rc = MAPISTORE_ERR_NOT_FOUND;
else
{
connInfo = [[self context] connectionInfo];
*data = MAPILongLongValue (memCtx, ((obVersion << 16)
| connInfo->repl_id));
| 0x0001));
rc = MAPISTORE_SUCCESS;
}
+3 -3
View File
@@ -25,13 +25,13 @@
@class NSString;
#include <mapistore/mapistore.h>
struct ldb_context;
NSString *MAPIStoreSamDBUserAttribute (struct mapistore_connection_info *connInfo,
NSString *MAPIStoreSamDBUserAttribute (struct ldb_context *samCtx,
NSString *userKey,
NSString *value,
NSString *attributeName);
NSData *MAPIStoreInternalEntryId (struct mapistore_connection_info *connInfo, NSString *username);
NSData *MAPIStoreInternalEntryId (struct ldb_context *, NSString *username);
NSData *MAPIStoreExternalEntryId (NSString *cn, NSString *email);
#endif /* MAPISTORESAMDBUTILS_H */
+6 -24
View File
@@ -24,18 +24,13 @@
#import <Foundation/NSString.h>
#include <talloc.h>
#include <ldb.h>
#include <libmapiproxy.h>
#include <samba/version.h>
#import "NSData+MAPIStore.h"
#import "MAPIStoreSamDBUtils.h"
NSString *
MAPIStoreSamDBUserAttribute (struct mapistore_connection_info *connInfo,
MAPIStoreSamDBUserAttribute (struct ldb_context *samCtx,
NSString *userKey,
NSString *value,
NSString *attributeName)
@@ -53,20 +48,10 @@ MAPIStoreSamDBUserAttribute (struct mapistore_connection_info *connInfo,
attrs[0] = [attributeName UTF8String];
searchFormat
= [NSString stringWithFormat: @"(&(objectClass=user)(%@=%%s))", userKey];
#if SAMBA_VERSION_MAJOR <= 4 && SAMBA_VERSION_MINOR < 3
ret = ldb_search (connInfo->sam_ctx, memCtx, &res,
ldb_get_default_basedn(connInfo->sam_ctx),
ret = ldb_search (samCtx, memCtx, &res, ldb_get_default_basedn(samCtx),
LDB_SCOPE_SUBTREE, attrs,
[searchFormat UTF8String],
[value UTF8String]);
#else
ret = safe_ldb_search (&connInfo->sam_ctx, memCtx, &res,
ldb_get_default_basedn(connInfo->sam_ctx),
LDB_SCOPE_SUBTREE, attrs,
[searchFormat UTF8String],
[value UTF8String]);
#endif
if (ret == LDB_SUCCESS && res->count == 1)
{
result = ldb_msg_find_attr_as_string (res->msgs[0], attrs[0], NULL);
@@ -80,7 +65,7 @@ MAPIStoreSamDBUserAttribute (struct mapistore_connection_info *connInfo,
}
NSData *
MAPIStoreInternalEntryId (struct mapistore_connection_info *connInfo, NSString *username)
MAPIStoreInternalEntryId (struct ldb_context *samCtx, NSString *username)
{
static const uint8_t const providerUid[] = { 0xdc, 0xa7, 0x40, 0xc8,
0xc0, 0x42, 0x10, 0x1a,
@@ -97,7 +82,7 @@ MAPIStoreInternalEntryId (struct mapistore_connection_info *connInfo, NSString *
type: 32
X500DN: variable */
legacyDN = MAPIStoreSamDBUserAttribute (connInfo, @"sAMAccountName", username,
legacyDN = MAPIStoreSamDBUserAttribute (samCtx, @"sAMAccountName", username,
@"legacyExchangeDN");
if (legacyDN)
{
@@ -111,11 +96,8 @@ MAPIStoreInternalEntryId (struct mapistore_connection_info *connInfo, NSString *
[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
+4 -6
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;
}
@@ -107,18 +105,18 @@
if ([roles containsObject: SOGoRole_ObjectCreator])
rights |= RightsCreateItems;
if ([roles containsObject: SOGoRole_ObjectEraser])
rights |= RightsDeleteAll | RightsDeleteOwn;
rights |= RightsDeleteAll;
if ([roles containsObject: SOGoCalendarRole_PublicModifier]
&& [roles containsObject: SOGoCalendarRole_PrivateModifier]
&& [roles containsObject: SOGoCalendarRole_ConfidentialModifier])
rights |= RightsReadItems | RightsEditAll | RightsEditOwn;
rights |= RightsReadItems | RightsEditAll;
else if ([roles containsObject: SOGoCalendarRole_PublicViewer]
&& [roles containsObject: SOGoCalendarRole_PrivateViewer]
&& [roles containsObject: SOGoCalendarRole_ConfidentialViewer])
rights |= RightsReadItems;
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
return rights;
}
+3 -21
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];
@@ -531,7 +513,7 @@
}
[vToDo setTimeStampAsDate: now];
[sogoObject saveCalendar: vCalendar];
[sogoObject saveComponent: vCalendar];
[self updateVersions];
}
-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)];
+5 -4
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);
}
@@ -198,7 +198,7 @@ NSObjectFromSPropValue (const struct SPropValue *value)
break;
case PT_STRING8:
result = (value->value.lpszA
? [NSString stringWithUTF8String: (const char *) value->value.lpszA]
? [NSString stringWithUTF8String: value->value.lpszA]
: (id) @"");
break;
case PT_SYSTIME:
@@ -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 -40
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>
@@ -73,8 +72,6 @@ static NSMapTable *contextsTable = nil;
[userContext autorelease];
[contextsTable setObject: userContext forKey: username];
}
else
[userContext activate];
return userContext;
}
@@ -161,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;
@@ -219,7 +214,7 @@ static NSMapTable *contextsTable = nil;
if (!userFolder)
{
userFolder = [SOGoUserFolder objectWithName: username
inContainer: nil];
inContainer: MAPIApp];
[userFolder retain];
}
@@ -237,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 */
@@ -263,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];
@@ -274,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"];
}
@@ -316,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: @"/"]];
@@ -343,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:
@@ -360,7 +355,7 @@ static NSMapTable *contextsTable = nil;
[channel cancelFetch];
[cm releaseChannel: channel];
[cm releaseChannel: channel];
}
/* SOGo context objects */
@@ -374,11 +369,6 @@ static NSMapTable *contextsTable = nil;
return authenticator;
}
- (void) activate
{
[self activateWithUser: [self sogoUser]];
}
- (void) activateWithUser: (SOGoUser *) activeUser;
{
NSMutableDictionary *info;
@@ -389,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
+1 -1
View File
@@ -228,7 +228,7 @@
mvResult = [NSMutableArray arrayWithCapacity: mvString->cValues];
for (count = 0; count < mvString->cValues; count++)
{
subObject = [NSString stringWithUTF8String: (const char *) mvString->lppszA[count]];
subObject = [NSString stringWithUTF8String: mvString->lppszA[count]];
[mvResult addObject: subObject];
}
-2
View File
@@ -41,8 +41,6 @@
+ (id) dataWithXID: (const struct XID *) xid;
- (struct XID *) asXIDInMemCtx: (void *) memCtx;
- (struct SizedXid *) asSizedXidArrayInMemCtx: (void *) memCtx
with: (uint32_t *) length;
+ (id) dataWithChangeKeyGUID: (NSString *) guidString
andCnt: (NSData *) globCnt;
Loaded 100 of 1771 files, more files were not shown because too many files have changed in this diff. Show more