Compare commits
37
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93d190060e | ||
|
|
1f299c7a1a | ||
|
|
74cfb901fd | ||
|
|
065fd5d9b5 | ||
|
|
bf547dd3fe | ||
|
|
81e47c59cd | ||
|
|
7862cda661 | ||
|
|
329552030b | ||
|
|
04904d8c61 | ||
|
|
f0b4a05c70 | ||
|
|
95d6911f1a | ||
|
|
48f98ef34e | ||
|
|
ae0c5eae77 | ||
|
|
0c2d727057 | ||
|
|
072f5f5a15 | ||
|
|
1db85743a0 | ||
|
|
2cf66e037d | ||
|
|
449d838dc2 | ||
|
|
c4bc215a47 | ||
|
|
c9936d7ecf | ||
|
|
885e59a2af | ||
|
|
bf398889bf | ||
|
|
e26e3d7307 | ||
|
|
045b275b27 | ||
|
|
7ec1973e0f | ||
|
|
a79a9c4eff | ||
|
|
f049e2430a | ||
|
|
59b3219f2d | ||
|
|
e9eb8bdc86 | ||
|
|
5e0c7ae4f2 | ||
|
|
c1c0c1ab44 | ||
|
|
a59fff785b | ||
|
|
6a70db80e6 | ||
|
|
d610630c8d | ||
|
|
4dc7790015 | ||
|
|
9dd000a2ca | ||
|
|
ce4084e528 |
No files matched your search
+13
-27
@@ -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
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "UI/WebServerResources/angular-material"]
|
||||
path = UI/WebServerResources/angular-material
|
||||
url = https://github.com/angular/material
|
||||
-66
@@ -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 +1 @@
|
||||
ifeq ($(HAS_LIBRARY_ssl),yes)
|
||||
ADDITIONAL_CPPFLAGS += -DHAVE_OPENSSL=1
|
||||
BUNDLE_LIBS += -lcrypto
|
||||
endif
|
||||
# compilation settings
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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
@@ -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"]))
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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 -> 😃 wrong: unichar -> � �
|
||||
//
|
||||
// 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
@@ -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,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;
|
||||
|
||||
|
||||
+271
-1048
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
@@ -37,7 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@interface SOGoSyncCacheObject : NSObject
|
||||
{
|
||||
@public
|
||||
id _uid;
|
||||
id _sequence;
|
||||
}
|
||||
|
||||
@@ -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"];
|
||||
}
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
+5655
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
-------------------
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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) \
|
||||
|
||||
@@ -33,9 +33,8 @@
|
||||
}
|
||||
|
||||
- (id) authenticatorInContext: (id) context;
|
||||
- (MAPIStoreUserContext *) userContext;
|
||||
|
||||
- (void) setUserContext: (MAPIStoreUserContext *) newContext;
|
||||
- (void) cleanup;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -46,9 +46,6 @@
|
||||
forURL: (NSURL *) server
|
||||
forceRenew: (BOOL) renew;
|
||||
|
||||
- (NSString *) passwordInContext: (WOContext *) context;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
#endif /* MAPISTOREAUTHENTICATOR_H */
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)];
|
||||
|
||||
@@ -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)];
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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, ¤tChangeKey->NameSpaceGuid))
|
||||
{
|
||||
NSData *globCnt, *oldGlobCnt;
|
||||
oldGlobCnt = [NSData dataWithBytes: changes[count].XID.LocalId.data length: changes[count].XID.LocalId.length];
|
||||
globCnt = [NSData dataWithBytes: currentChangeKey->LocalId.data length: currentChangeKey->LocalId.length];
|
||||
if ([globCnt compare: oldGlobCnt] == NSOrderedDescending)
|
||||
{
|
||||
if ([globCnt length] != [oldGlobCnt length])
|
||||
{
|
||||
[self errorWithFormat: @"Cannot compare globcnt with different length: %@ and %@", globCnt, oldGlobCnt];
|
||||
abort();
|
||||
}
|
||||
memcpy (changes[count].XID.LocalId.data, currentChangeKey->LocalId.data, currentChangeKey->LocalId.length);
|
||||
updated = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Serialise it */
|
||||
changeKeys = [NSMutableArray array];
|
||||
|
||||
if (!updated)
|
||||
[changeKeys addObject: changeKey];
|
||||
|
||||
for (count = 0; count < nChanges; count++)
|
||||
{
|
||||
changeKey = [NSData dataWithXID: &changes[count].XID];
|
||||
[changeKeys addObject: changeKey];
|
||||
}
|
||||
|
||||
[changeKeys sortUsingFunction: MAPIChangeKeyGUIDCompare context: localMemCtx];
|
||||
|
||||
newChangeList = [NSMutableData data];
|
||||
len = [changeKeys count];
|
||||
for (count = 0; count < len; count++)
|
||||
{
|
||||
changeKey = [changeKeys objectAtIndex: count];
|
||||
[newChangeList appendUInt8: [changeKey length]];
|
||||
[newChangeList appendData: changeKey];
|
||||
}
|
||||
}
|
||||
|
||||
if ([newChangeList length] > 0)
|
||||
{
|
||||
property.ulPropTag = PidTagPredecessorChangeList;
|
||||
property.value.bin = *[newChangeList asBinaryInMemCtx: localMemCtx];
|
||||
aRow.cValues = 1;
|
||||
aRow.lpProps = &property;
|
||||
rc = [self addPropertiesFromRow: &aRow];
|
||||
if (rc != MAPISTORE_SUCCESS)
|
||||
[self errorWithFormat: @"Impossible to add a new predecessor change list: %d", rc];
|
||||
}
|
||||
|
||||
talloc_free (localMemCtx);
|
||||
}
|
||||
|
||||
//
|
||||
// FIXME: how this can happen?
|
||||
//
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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
|
||||
|
||||
@@ -35,8 +35,6 @@
|
||||
{
|
||||
BOOL headerSetup;
|
||||
BOOL mailIsEvent;
|
||||
BOOL mailIsMeetingRequest;
|
||||
BOOL mailIsSharingObject;
|
||||
NSString *mimeKey;
|
||||
NSString *headerCharset;
|
||||
NSString *headerEncoding;
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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,
|
||||
¬if_parameters);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newChildRow == NSNotFound)
|
||||
mapistore_push_notification (mstoreCtx,
|
||||
MAPISTORE_TABLE,
|
||||
MAPISTORE_OBJECT_DELETED,
|
||||
¬if_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,
|
||||
¬if_parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -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;
|
||||
|
||||
@@ -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)];
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
else
|
||||
{
|
||||
connInfo = [(MAPIStoreContext *) [container context] connectionInfo];
|
||||
entryId = MAPIStoreInternalEntryId (connInfo, userId);
|
||||
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, userId);
|
||||
}
|
||||
*data = [entryId asBinaryInMemCtx: memCtx];
|
||||
|
||||
|
||||
@@ -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,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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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)];
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -86,8 +86,6 @@
|
||||
|
||||
/* SOGo hacky magic */
|
||||
- (void) activateWithUser: (SOGoUser *) activeUser;
|
||||
- (void) activate;
|
||||
- (void) deactivate;
|
||||
- (MAPIStoreAuthenticator *) authenticator;
|
||||
- (WOContext *) woContext;
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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
Reference in new issue
Block a user