Compare commits

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

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

No files matched your search

-140
View File
@@ -1,140 +0,0 @@
# Contributing to SOGo
## Reporting Bugs and Suggesting Enhancements
If you encounter a possible bug with SOGo, you can access our
[bug tracking system](https://bugs.sogo.nu/).
Please make sure to respect the following guidelines when reporting a bug:
* verify that the bug you found is not already known or even fixed in the `master` version
* make the actual facts very clear; be precise, we need to be able to reproduce the problem
* explain your speculations, if any
* add a screenshot to the ticket if appropriate
## Submitting a Pull Request
Begin by reading [SOGo Developer's Guide](../Documentation/SOGoDevelopersGuide.asciidoc).
### Translations
Three type of files must be translated. The first type are **Localizable.strings**; they can be
translated online using **[Transifex](https://www.transifex.com/alinto/sogo/)**. To use Transifex,
you must first sign up for a [free account](https://www.transifex.com/signup/). Once registered,
[request a new team](https://www.transifex.com/alinto/teams/) for your language. Once authorized,
you'll be able to start/continue translating SOGo in your language.
The second type are **wox and html templates**. Only words outside the tags (<>) must be
translated. Start by duplicating the English templates:
* [UI/Templates/SOGoACLEnglishAdditionAdvisory.wox](https://raw.githubusercontent.com/alinto/sogo/master/UI/Templates/SOGoACLEnglishAdditionAdvisory.wox)
* [UI/Templates/SOGoACLEnglishRemovalAdvisory.wox](https://raw.githubusercontent.com/alinto/sogo/master/UI/Templates/SOGoACLEnglishRemovalAdvisory.wox)
* [UI/Templates/SOGoACLEnglishModificationAdvisory.wox](https://raw.githubusercontent.com/alinto/sogo/master/UI/Templates/SOGoACLEnglishModificationAdvisory.wox)
* [UI/Templates/SOGoFolderEnglishAdditionAdvisory.wox](https://raw.githubusercontent.com/alinto/sogo/master/UI/Templates/SOGoFolderEnglishAdditionAdvisory.wox)
* [UI/Templates/SOGoFolderEnglishRemovalAdvisory.wox](https://raw.githubusercontent.com/alinto/sogo/master/UI/Templates/SOGoFolderEnglishRemovalAdvisory.wox)
* [SoObjects/Mailer/SOGoMailEnglishForward.wo/SOGoMailEnglishForward.html](https://raw.githubusercontent.com/alinto/sogo/master/SoObjects/Mailer/SOGoMailEnglishForward.wo/SOGoMailEnglishForward.html)
* [SoObjects/Mailer/SOGoMailEnglishReply.wo/SOGoMailEnglishReply.html](https://raw.githubusercontent.com/alinto/sogo/master/SoObjects/Mailer/SOGoMailEnglishReply.wo/SOGoMailEnglishReply.html)
The third type is the locale file formatted as a **plist**. Duplicate the English locale. Beware that words with other characters than [a-zA-Z] (accents, non-latin...) must be between double quotes ("). You can look at other files as arabic or french to have an example:
* [UI/MainUI/English.lproj/Locale](https://raw.githubusercontent.com/alinto/sogo/master/UI/MainUI/English.lproj/Locale)
Once translated, create an archive with all the files and [contact
us](https://sogo.nu/support.html#/commercial). We'll integrate it in the next version of SOGo.
### Git Commit Guidelines
We have very precise rules over how our git commit messages can be formatted. This leads to **more
readable messages** that are easy to follow when looking through the **project history**.
It is important to note that we use the git commit messages to **generate** the
[CHANGELOG](../CHANGELOG.md) document. Improperly formatted commit messages may result in your
change not appearing in the CHANGELOG of the next release.
### Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
```html
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
> Any line of the commit message cannot be longer than 100 characters.
> This allows the message to be easier to read on GitHub as well as in various Git tools.
#### Type
Must be one of the following:
* **feat**: A new feature
* **fix**: A bug fix
* **docs**: Documentation only changes
* **i18n**: Change in localizable strings
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
semi-colons, etc)
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **perf**: A code change that improves performance
* **test**: Adding missing tests
* **chore**: Changes to the build and packaging process or auxiliary tools (sogo-tool,
sogo-ealarms-notify) and libraries such as documentation generation
#### Scope
The scope could be anything that helps specifying the scope (or feature) that is changing.
Examples
* mail
* mail(js)
* calendar(css)
* addressbook
* preferences(js)
* core
* eas
#### Subject
The subject contains a succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize first letter
* no dot (.) at the end
#### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes"
The body should include the motivation for the change and contrast this with previous behavior.
#### Footer
The footer should contain any information about **Breaking Changes** and is also the
place to reference [Mantis](https://bugs.sogo.nu) issues that this commit **Fixes** or **Resolves**.
> Breaking Changes are intended to be highlighted in the CHANGELOG as changes that will require
> community users to modify their code after updating to a version that contains this commit.
#### Sample Commit messages
```text
fix(calendar): don't raise exception when renaming with same name
this would break Apple Calendar.app when creating a new calendar
Fixes #4813
```
```text
feat(calendar(js)): optionally expand LDAP groups in attendees editor
* add `/members` action for LDIF groups
* add button to expand invited LDAP groups
Fixes #2506
```
```text
fix(core): set default Sieve port to 4190
BREAKING CHANGE: the default port for the SOGoSieveServer configuration default is now 4190 (was
2000).
You need to explicitly set the port if you use a different port.
Closes #4826
```
+13 -53
View File
@@ -1,58 +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
Documentation/*.html
*._*
*/*/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/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
.DS_Store
Tests/package-lock.json
.vscode
.configure-test*
UI/WebServerResources/package-lock.json
# CKEditor
UI/WebServerResources/js/vendor/ckeditor/samples/
UI/WebServerResources/js/vendor/ckeditor/skins/n1theme/readme.md
UI/WebServerResources/js/vendor/ckeditor/*.md
UI/WebServerResources/js/vendor/ckeditor/adapters/jquery.js
UI/WebServerResources/js/vendor/ckeditor/bender-runner.config.json
UI/WebServerResources/js/vendor/ckeditor/plugins/onchange/docs
UI/WebServerResources/js/vendor/ckeditor/plugins/scayt/*.md
UI/WebServerResources/js/vendor/ckeditor/skins/n1theme/*.md
# Transifex
.tx/config_20230213185112.bak
# Tests
Tests/node_modules
Tests/lib/config.js
Tests/results.xml
Tests/results
# SAML2 autogenerated files
SoObjects/SOGo/SOGoSAML2Exceptions.*
*.pyc
._*
Documentation/*.docbook
Documentation/*.pdf
-3
View File
@@ -1,3 +0,0 @@
[submodule "UI/WebServerResources/angular-material"]
path = UI/WebServerResources/angular-material
url = https://github.com/angular/material
+275 -47
View File
@@ -1,60 +1,288 @@
[main]
host = https://www.transifex.com
lang_map = fr: French, pt_BR: BrazilianPortuguese, ru: Russian, sk: Slovak, es_AR: SpanishArgentina, fi: Finnish, id_ID: Indonesian, lt: Lithuanian, tr_TR: TurkishTurkey, zh_TW: ChineseTaiwan, ar: Arabic, cs: Czech, nn_NO: NorwegianNynorsk, sl_SI: Slovenian, uk: Ukrainian, zh_CN: ChineseChina, sv: Swedish, bg_BG: Bulgarian, cy: Welsh, is: Icelandic, sr: Serbian, lv: Latvian, pl: Polish, ro_RO: Romanian, bs_BA: Bosnian,ca: Catalan, he: Hebrew, kk: Kazakh, pt: Portuguese, es_ES: SpanishSpain, eu: Basque, hu: Hungarian, ja: Japanese, mk_MK: Macedonian, nb_NO: NorwegianBokmal, nl: Dutch, sr@latin: SerbianLatin, da_DK: Danish, de: German, hr_HR: Croatian, it: Italian, sr_ME@latin: Montenegrin, gl_ES: Galician
[o:alinto:p:sogo:r:soobjects-appointments]
source_file = SoObjects/Appointments/English.lproj/Localizable.strings
source_lang = en
file_filter = SoObjects/Appointments/<lang>.lproj/Localizable.strings
[sogo.ui-mailerui]
source_file = UI/MailerUI/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/MailerUI/Arabic.lproj/Localizable.strings
trans.ca = UI/MailerUI/Catalan.lproj/Localizable.strings
trans.cs = UI/MailerUI/Czech.lproj/Localizable.strings
trans.cy = UI/MailerUI/Welsh.lproj/Localizable.strings
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.fi = UI/MailerUI/Finnish.lproj/Localizable.strings
trans.fr = UI/MailerUI/French.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.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_BR = UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings
trans.ru = UI/MailerUI/Russian.lproj/Localizable.strings
trans.sk = UI/MailerUI/Slovak.lproj/Localizable.strings
trans.sv = UI/MailerUI/Swedish.lproj/Localizable.strings
trans.uk = UI/MailerUI/Ukrainian.lproj/Localizable.strings
[sogo.ui-preferencesui]
source_file = UI/PreferencesUI/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/PreferencesUI/Arabic.lproj/Localizable.strings
trans.ca = UI/PreferencesUI/Catalan.lproj/Localizable.strings
trans.cs = UI/PreferencesUI/Czech.lproj/Localizable.strings
trans.cy = UI/PreferencesUI/Welsh.lproj/Localizable.strings
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.fi = UI/PreferencesUI/Finnish.lproj/Localizable.strings
trans.fr = UI/PreferencesUI/French.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.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_BR = UI/PreferencesUI/BrazilianPortuguese.lproj/Localizable.strings
trans.ru = UI/PreferencesUI/Russian.lproj/Localizable.strings
trans.sk = UI/PreferencesUI/Slovak.lproj/Localizable.strings
trans.sv = UI/PreferencesUI/Swedish.lproj/Localizable.strings
trans.uk = UI/PreferencesUI/Ukrainian.lproj/Localizable.strings
[o:alinto:p:sogo:r:soobjects-contacts]
source_file = SoObjects/Contacts/English.lproj/Localizable.strings
source_lang = en
file_filter = SoObjects/Contacts/<lang>.lproj/Localizable.strings
[sogo.ui-scheduler]
source_file = UI/Scheduler/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/Scheduler/Arabic.lproj/Localizable.strings
trans.ca = UI/Scheduler/Catalan.lproj/Localizable.strings
trans.cs = UI/Scheduler/Czech.lproj/Localizable.strings
trans.cy = UI/Scheduler/Welsh.lproj/Localizable.strings
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.fi = UI/Scheduler/Finnish.lproj/Localizable.strings
trans.fr = UI/Scheduler/French.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.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_BR = UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings
trans.ru = UI/Scheduler/Russian.lproj/Localizable.strings
trans.sk = UI/Scheduler/Slovak.lproj/Localizable.strings
trans.sv = UI/Scheduler/Swedish.lproj/Localizable.strings
trans.uk = UI/Scheduler/Ukrainian.lproj/Localizable.strings
[o:alinto:p:sogo:r:soobjects-mailer]
source_file = SoObjects/Mailer/English.lproj/Localizable.strings
source_lang = en
file_filter = SoObjects/Mailer/<lang>.lproj/Localizable.strings
[sogo.ui-contacts]
source_file = UI/Contacts/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/Contacts/Arabic.lproj/Localizable.strings
trans.ca = UI/Contacts/Catalan.lproj/Localizable.strings
trans.cs = UI/Contacts/Czech.lproj/Localizable.strings
trans.cy = UI/Contacts/Welsh.lproj/Localizable.strings
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.fi = UI/Contacts/Finnish.lproj/Localizable.strings
trans.fr = UI/Contacts/French.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.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_BR = UI/Contacts/BrazilianPortuguese.lproj/Localizable.strings
trans.ru = UI/Contacts/Russian.lproj/Localizable.strings
trans.sk = UI/Contacts/Slovak.lproj/Localizable.strings
trans.sv = UI/Contacts/Swedish.lproj/Localizable.strings
trans.uk = UI/Contacts/Ukrainian.lproj/Localizable.strings
[o:alinto:p:sogo:r:ui-administrationui]
source_file = UI/AdministrationUI/English.lproj/Localizable.strings
source_lang = en
file_filter = UI/AdministrationUI/<lang>.lproj/Localizable.strings
[sogo.ui-mainui]
source_file = UI/MainUI/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/MainUI/Arabic.lproj/Localizable.strings
trans.ca = UI/MainUI/Catalan.lproj/Localizable.strings
trans.cs = UI/MainUI/Czech.lproj/Localizable.strings
trans.cy = UI/MainUI/Welsh.lproj/Localizable.strings
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.fi = UI/MainUI/Finnish.lproj/Localizable.strings
trans.fr = UI/MainUI/French.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.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_BR = UI/MainUI/BrazilianPortuguese.lproj/Localizable.strings
trans.ru = UI/MainUI/Russian.lproj/Localizable.strings
trans.sk = UI/MainUI/Slovak.lproj/Localizable.strings
trans.sv = UI/MainUI/Swedish.lproj/Localizable.strings
trans.uk = UI/MainUI/Ukrainian.lproj/Localizable.strings
[o:alinto:p:sogo:r:ui-common]
source_file = UI/Common/English.lproj/Localizable.strings
source_lang = en
file_filter = UI/Common/<lang>.lproj/Localizable.strings
[sogo.ui-common]
source_file = UI/Common/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/Common/Arabic.lproj/Localizable.strings
trans.ca = UI/Common/Catalan.lproj/Localizable.strings
trans.cs = UI/Common/Czech.lproj/Localizable.strings
trans.cy = UI/Common/Welsh.lproj/Localizable.strings
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.fi = UI/Common/Finnish.lproj/Localizable.strings
trans.fr = UI/Common/French.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.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_BR = UI/Common/BrazilianPortuguese.lproj/Localizable.strings
trans.ru = UI/Common/Russian.lproj/Localizable.strings
trans.sk = UI/Common/Slovak.lproj/Localizable.strings
trans.sv = UI/Common/Swedish.lproj/Localizable.strings
trans.uk = UI/Common/Ukrainian.lproj/Localizable.strings
[o:alinto:p:sogo:r:ui-contacts]
source_file = UI/Contacts/English.lproj/Localizable.strings
source_lang = en
file_filter = UI/Contacts/<lang>.lproj/Localizable.strings
[sogo.ui-administrationui]
source_file = UI/AdministrationUI/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/AdministrationUI/Arabic.lproj/Localizable.strings
trans.ca = UI/AdministrationUI/Catalan.lproj/Localizable.strings
trans.cs = UI/AdministrationUI/Czech.lproj/Localizable.strings
trans.cy = UI/AdministrationUI/Welsh.lproj/Localizable.strings
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.fi = UI/AdministrationUI/Finnish.lproj/Localizable.strings
trans.fr = UI/AdministrationUI/French.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.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_BR = UI/AdministrationUI/BrazilianPortuguese.lproj/Localizable.strings
trans.ru = UI/AdministrationUI/Russian.lproj/Localizable.strings
trans.sk = UI/AdministrationUI/Slovak.lproj/Localizable.strings
trans.sv = UI/AdministrationUI/Swedish.lproj/Localizable.strings
trans.uk = UI/AdministrationUI/Ukrainian.lproj/Localizable.strings
[o:alinto:p:sogo:r:ui-mailerui]
source_file = UI/MailerUI/English.lproj/Localizable.strings
source_lang = en
file_filter = UI/MailerUI/<lang>.lproj/Localizable.strings
[sogo.soobjects-appointments]
source_file = SoObjects/Appointments/English.lproj/Localizable.strings
source_lang = en
trans.ar = SoObjects/Appointments/Arabic.lproj/Localizable.strings
trans.ca = SoObjects/Appointments/Catalan.lproj/Localizable.strings
trans.cs = SoObjects/Appointments/Czech.lproj/Localizable.strings
trans.cy = SoObjects/Appointments/Welsh.lproj/Localizable.strings
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.fi = SoObjects/Appointments/Finnish.lproj/Localizable.strings
trans.fr = SoObjects/Appointments/French.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.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_BR = SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings
trans.ru = SoObjects/Appointments/Russian.lproj/Localizable.strings
trans.sk = SoObjects/Appointments/Slovak.lproj/Localizable.strings
trans.sv = SoObjects/Appointments/Swedish.lproj/Localizable.strings
trans.uk = SoObjects/Appointments/Ukrainian.lproj/Localizable.strings
[o:alinto:p:sogo:r:ui-mailpartviewers]
source_file = UI/MailPartViewers/English.lproj/Localizable.strings
source_lang = en
file_filter = UI/MailPartViewers/<lang>.lproj/Localizable.strings
[sogo.soobjects-contacts]
source_file = SoObjects/Contacts/English.lproj/Localizable.strings
source_lang = en
trans.ar = SoObjects/Contacts/Arabic.lproj/Localizable.strings
trans.ca = SoObjects/Contacts/Catalan.lproj/Localizable.strings
trans.cs = SoObjects/Contacts/Czech.lproj/Localizable.strings
trans.cy = SoObjects/Contacts/Welsh.lproj/Localizable.strings
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.fi = SoObjects/Contacts/Finnish.lproj/Localizable.strings
trans.fr = SoObjects/Contacts/French.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.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_BR = SoObjects/Contacts/BrazilianPortuguese.lproj/Localizable.strings
trans.ru = SoObjects/Contacts/Russian.lproj/Localizable.strings
trans.sk = SoObjects/Contacts/Slovak.lproj/Localizable.strings
trans.sv = SoObjects/Contacts/Swedish.lproj/Localizable.strings
trans.uk = SoObjects/Contacts/Ukrainian.lproj/Localizable.strings
[o:alinto:p:sogo:r:ui-mainui]
source_file = UI/MainUI/English.lproj/Localizable.strings
source_lang = en
file_filter = UI/MainUI/<lang>.lproj/Localizable.strings
[o:alinto:p:sogo:r:ui-preferencesui]
source_file = UI/PreferencesUI/English.lproj/Localizable.strings
source_lang = en
file_filter = UI/PreferencesUI/<lang>.lproj/Localizable.strings
[o:alinto:p:sogo:r:ui-scheduler]
source_file = UI/Scheduler/English.lproj/Localizable.strings
source_lang = en
file_filter = UI/Scheduler/<lang>.lproj/Localizable.strings
[sogo.soobjects-mailer]
source_file = SoObjects/Mailer/English.lproj/Localizable.strings
source_lang = en
trans.ar = SoObjects/Mailer/Arabic.lproj/Localizable.strings
trans.ca = SoObjects/Mailer/Catalan.lproj/Localizable.strings
trans.cs = SoObjects/Mailer/Czech.lproj/Localizable.strings
trans.cy = SoObjects/Mailer/Welsh.lproj/Localizable.strings
trans.da_DK = SoObjects/Mailer/Danish.lproj/Localizable.strings
trans.de = SoObjects/Mailer/German.lproj/Localizable.strings
trans.es_AR = SoObjects/Mailer/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = SoObjects/Mailer/SpanishSpain.lproj/Localizable.strings
trans.fi = SoObjects/Mailer/Finnish.lproj/Localizable.strings
trans.fr = SoObjects/Mailer/French.lproj/Localizable.strings
trans.hu = SoObjects/Mailer/Hungarian.lproj/Localizable.strings
trans.is = SoObjects/Mailer/Icelandic.lproj/Localizable.strings
trans.it = SoObjects/Mailer/Italian.lproj/Localizable.strings
trans.nb_NO = SoObjects/Mailer/NorwegianBokmal.lproj/Localizable.strings
trans.nl = SoObjects/Mailer/Dutch.lproj/Localizable.strings
trans.nn_NO = SoObjects/Mailer/NorwegianNynorsk.lproj/Localizable.strings
trans.pl = SoObjects/Mailer/Polish.lproj/Localizable.strings
trans.pt_BR = SoObjects/Mailer/BrazilianPortuguese.lproj/Localizable.strings
trans.ru = SoObjects/Mailer/Russian.lproj/Localizable.strings
trans.sk = SoObjects/Mailer/Slovak.lproj/Localizable.strings
trans.sv = SoObjects/Mailer/Swedish.lproj/Localizable.strings
trans.uk = SoObjects/Mailer/Ukrainian.lproj/Localizable.strings
[sogo.ui-mailpartviewers]
source_file = UI/MailPartViewers/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/MailPartViewers/Arabic.lproj/Localizable.strings
trans.ca = UI/MailPartViewers/Catalan.lproj/Localizable.strings
trans.cs = UI/MailPartViewers/Czech.lproj/Localizable.strings
trans.cy = UI/MailPartViewers/Welsh.lproj/Localizable.strings
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.fi = UI/MailPartViewers/Finnish.lproj/Localizable.strings
trans.fr = UI/MailPartViewers/French.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.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_BR = UI/MailPartViewers/BrazilianPortuguese.lproj/Localizable.strings
trans.ru = UI/MailPartViewers/Russian.lproj/Localizable.strings
trans.sk = UI/MailPartViewers/Slovak.lproj/Localizable.strings
trans.sv = UI/MailPartViewers/Swedish.lproj/Localizable.strings
trans.uk = UI/MailPartViewers/Ukrainian.lproj/Localizable.strings
-27
View File
@@ -1,27 +0,0 @@
const tracker = {
filename: "Version",
updater: require("./Scripts/standard-version-updater.js")
}
module.exports = {
tagPrefix: "SOGo-",
issueUrlFormat: "https://bugs.sogo.nu/view.php?id={{id}}",
compareUrlFormat: "{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}",
types: [
{type: "feat", section: "Features"},
{type: "refactor", section: "Enhancements"},
{type: "perf", section: "Enhancements"},
{type: "i18n", section: "Localization"},
{type: "fix", section: "Bug Fixes"},
{type: "chore", hidden: true},
{type: "docs", hidden: true},
{type: "style", hidden: true},
{type: "test", hidden: true}
],
skip: {
commit: true,
tag: true
},
packageFiles: [tracker],
bumpFiles: [tracker]
}
+1 -4
View File
@@ -1,4 +1 @@
ifeq ($(HAS_LIBRARY_ssl),yes)
ADDITIONAL_CPPFLAGS += -DHAVE_OPENSSL=1
BUNDLE_LIBS += -lcrypto
endif
# compilation settings
+1
View File
@@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define __NGDOMELEMENTACTIVESYNC_H__
#import <DOM/DOMElement.h>
#import <DOM/DOMProtocols.h>
@class NSDictionary;
+2 -40
View File
@@ -34,7 +34,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSString.h>
static NSArray *asElementArray = nil;
static NSArray *considerAsSameArray = nil;
@implementation NGDOMElement (ActiveSync)
@@ -102,44 +101,7 @@ static NSArray *considerAsSameArray = nil;
int i, count;
if (!asElementArray)
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", @"Category", @"Exception", @"Add", @"Delete", nil];
// FIXME
/* if the client sends
<attachments>
<add>
...
</add>
<add>
...
</add>
</attachments>
the result is a NSarray i.e. {add1; add2; ...}
if the client sends
<attachments>
<add>
...
</add>
<add>
...
</add>
<delete>
...
</delete>
<delete>
...
</delete>
</attachments>
the result is a NSDictionary ie. Add = { }; Delete = { }; the dictionary would contain only one entry for add
*/
if (!considerAsSameArray)
considerAsSameArray = [[NSArray alloc] initWithObjects: @"Add", @"Delete", nil];
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", @"Category", nil];
data = [NSMutableDictionary dictionary];
@@ -189,7 +151,7 @@ the result is a NSDictionary ie. Add = { }; Delete = { }; the dictionary would c
if (!innerTag)
innerTag = [innerElement tagName];
if ([innerTag isEqualToString: [innerElement tagName]] || [considerAsSameArray containsObject: innerTag])
if ([innerTag isEqualToString: [innerElement tagName]])
{
if ([(id)innerElement isTextNode])
[innerElements addObject: [(NGDOMElement *)innerElement textValue]];
+1 -1
View File
@@ -36,7 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@interface NGMimeMessage (ActiveSync)
- (NSArray *) allBareRecipients;
- (NSArray *) allRecipients;
@end
+24 -33
View File
@@ -1,6 +1,6 @@
/*
Copyright (c) 2015, Inverse inc.
Copyright (c) 2014, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import "NGMimeMessage+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSString.h>
#import <NGMail/NGMailAddress.h>
#import <NGMail/NGMailAddressParser.h>
@@ -40,45 +42,34 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSArray *) allRecipients
{
NSEnumerator *enumerator, *addressList;
NSMutableArray *recipients;
NGMailAddressParser *parser;
NSEnumerator *addressList;
NSMutableArray *allRecipients;
NGMailAddress *address;
NSEnumerator *recipients;
NSString *s;
NSString *fieldNames[] = {@"to", @"cc", @"bcc"};
unsigned int count;
allRecipients = [NSMutableArray arrayWithCapacity: 16];
recipients = [NSMutableArray array];
for (count = 0; count < 3; count++)
enumerator = [[self headersForKey: @"to"] objectEnumerator];
while ((s = [enumerator nextObject]))
{
recipients = [[self headersForKey: fieldNames[count]] objectEnumerator];
while ((s = [recipients nextObject]))
{
parser = [NGMailAddressParser mailAddressParserWithString: s];
addressList = [[parser parseAddressList] objectEnumerator];
while ((address = [addressList nextObject]))
[allRecipients addObject: [address address]];
}
parser = [NGMailAddressParser mailAddressParserWithString: s];
addressList = [[parser parseAddressList] objectEnumerator];
while ((address = [addressList nextObject]))
[recipients addObject: [address address]];
}
return allRecipients;
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;
}
- (NSArray *) allBareRecipients
{
NSMutableArray *bareRecipients;
NSEnumerator *allRecipients;
NSString *recipient;
bareRecipients = [NSMutableArray array];
allRecipients = [[self allRecipients] objectEnumerator];
while ((recipient = [allRecipients nextObject]))
[bareRecipients addObject: [recipient pureEMailAddress]];
return bareRecipients;
}
@end
+64 -321
View File
@@ -29,12 +29,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "NGVCard+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSString+misc.h>
#import <NGCards/CardElement.h>
#import <Contacts/NGVCard+SOGo.h>
#import <SOGo/NSString+Utilities.h>
@@ -42,50 +46,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "NSDate+ActiveSync.h"
#include "NSString+ActiveSync.h"
#import <NGObjWeb/WOContext+SoObjects.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
@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;
NSMutableArray *other_addresses;
CardElement *n, *homeAdr, *workAdr, *otherAdr;
NSMutableString *s, *a;
CardElement *n, *homeAdr, *workAdr;
NSMutableString *s;
NSString *url;
id o;
@@ -96,22 +63,10 @@ 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]];
if ((o = [n flattenedValueAtIndex: 2 forKey: @""]))
[s appendFormat: @"<MiddleName xmlns=\"Contacts:\">%@</MiddleName>", [o activeSyncRepresentationInContext: context]];
if ((o = [n flattenedValueAtIndex: 3 forKey: @""]))
[s appendFormat: @"<Title xmlns=\"Contacts:\">%@</Title>", [o activeSyncRepresentationInContext: context]];
if ((o = [n flattenedValueAtIndex: 4 forKey: @""]))
[s appendFormat: @"<Suffix xmlns=\"Contacts:\">%@</Suffix>", [o activeSyncRepresentationInContext: context]];
if ((o = [self fn]))
[s appendFormat: @"<FileAs xmlns=\"Contacts:\">%@</FileAs>", [o activeSyncRepresentationInContext: context]];
if ((o = [self workCompany]))
[s appendFormat: @"<CompanyName xmlns=\"Contacts:\">%@</CompanyName>", [o activeSyncRepresentationInContext: context]];
@@ -151,7 +106,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendFormat: @"<JobTitle xmlns=\"Contacts:\">%@</JobTitle>", [o activeSyncRepresentationInContext: context]];
if ((o = [self preferredEMail]))
[s appendFormat: @"<Email1Address xmlns=\"Contacts:\">%@</Email1Address>", [o activeSyncRepresentationInContext: context]];
[s appendFormat: @"<Email1Address xmlns=\"Contacts:\">%@</Email1Address>", o];
// Secondary email addresses (2 and 3)
@@ -161,7 +116,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
o = [[emails objectAtIndex: i] flattenedValuesForKey: @""];
[s appendFormat: @"<Email%dAddress xmlns=\"Contacts:\">%@</Email%dAddress>", i+2, [o activeSyncRepresentationInContext: context], i+2];
[s appendFormat: @"<Email%dAddress xmlns=\"Contacts:\">%@</Email%dAddress>", i+2, o, i+2];
if (i == 1)
break;
@@ -191,22 +146,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 activeSyncRepresentationInContext: context]];
if ((o = [homeAdr flattenedValueAtIndex: 1 forKey: @""]) && [o length])
[a appendFormat: @"\n%@", [o activeSyncRepresentationInContext: context]];
[s appendFormat: @"<HomeStreet xmlns=\"Contacts:\">%@</HomeStreet>", [o activeSyncRepresentationInContext: context]];
[s appendFormat: @"<HomeStreet xmlns=\"Contacts:\">%@</HomeStreet>", a];
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]];
@@ -222,15 +171,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 activeSyncRepresentationInContext: context]];
if ((o = [workAdr flattenedValueAtIndex: 1 forKey: @""]) && [o length])
[a appendFormat: @"\n%@", [o activeSyncRepresentationInContext: context]];
[s appendFormat: @"<BusinessStreet xmlns=\"Contacts:\">%@</BusinessStreet>", a];
[s appendFormat: @"<BusinessStreet xmlns=\"Contacts:\">%@</BusinessStreet>", [o activeSyncRepresentationInContext: context]];
if ((o = [workAdr flattenedValueAtIndex: 3 forKey: @""]))
[s appendFormat: @"<BusinessCity xmlns=\"Contacts:\">%@</BusinessCity>", [o activeSyncRepresentationInContext: context]];
@@ -245,48 +188,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendFormat: @"<BusinessCountry xmlns=\"Contacts:\">%@</BusinessCountry>", [o activeSyncRepresentationInContext: context]];
}
// Other Address
other_addresses = [[self childrenWithTag: @"adr"] mutableCopy];
[other_addresses removeObjectsInArray: [self childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"work"]];
[other_addresses removeObjectsInArray: [self childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"home"]];
if ([other_addresses count])
{
otherAdr = [other_addresses objectAtIndex: 0];
a = [NSMutableString string];
if ((o = [otherAdr flattenedValueAtIndex: 2 forKey: @""]))
[a appendString: [o activeSyncRepresentationInContext: context]];
if ((o = [otherAdr flattenedValueAtIndex: 1 forKey: @""]) && [o length])
[a appendFormat: @"\n%@", [o activeSyncRepresentationInContext: context]];
[s appendFormat: @"<OtherStreet xmlns=\"Contacts:\">%@</OtherStreet>", a];
if ((o = [otherAdr flattenedValueAtIndex: 3 forKey: @""]))
[s appendFormat: @"<OtherCity xmlns=\"Contacts:\">%@</OtherCity>", [o activeSyncRepresentationInContext: context]];
if ((o = [otherAdr flattenedValueAtIndex: 4 forKey: @""]))
[s appendFormat: @"<OtherState xmlns=\"Contacts:\">%@</OtherState>", [o activeSyncRepresentationInContext: context]];
if ((o = [otherAdr flattenedValueAtIndex: 5 forKey: @""]))
[s appendFormat: @"<OtherPostalCode xmlns=\"Contacts:\">%@</OtherPostalCode>", [o activeSyncRepresentationInContext: context]];
if ((o = [otherAdr flattenedValueAtIndex: 6 forKey: @""]))
[s appendFormat: @"<OtherCountry xmlns=\"Contacts:\">%@</OtherCountry>", [o activeSyncRepresentationInContext: context]];
}
// Other, less important fields
if ((o = [self birthday]))
{
[s appendFormat: @"<Birthday xmlns=\"Contacts:\">%@</Birthday>",
[[o dateByAddingYears: 0 months: 0 days: 0
hours: -12 minutes: 0
seconds: 0]
activeSyncRepresentationInContext: context]];
}
[s appendFormat: @"<Birthday xmlns=\"Contacts:\">%@</Birthday>", [o activeSyncRepresentationInContext: context]];
if ((o = [self note]))
{
@@ -313,11 +217,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inContext: (WOContext *) context
{
CardElement *element;
NSMutableArray *addressLines, *other_addresses;
id o, l, m, f, p, s;
l = m = f = p = s = nil;
id o;
// Contact's note
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setNote: o];
@@ -325,8 +226,6 @@ 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"]))
@@ -334,11 +233,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
o = [o calendarDate];
[self setBday: [o descriptionWithCalendarFormat: @"%Y-%m-%d" timeZone: nil locale: nil]];
}
else if (![self _isGhosted: @"Birthday" inContext: context])
{
[self setBday: @""];
}
//
// Business address information
@@ -350,48 +244,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
@@ -403,126 +267,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: @""];
}
// OtherCountry
//
other_addresses = [[self childrenWithTag: @"adr"] mutableCopy];
[other_addresses removeObjectsInArray: [self childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"work"]];
[other_addresses removeObjectsInArray: [self childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"home"]];
if ([other_addresses count])
element = [other_addresses objectAtIndex: 0];
else
{
element = [CardElement elementWithTag: @"adr"];
[self addChild: element];
}
if ((o = [theValues objectForKey: @"OtherStreet"]) || ![self _isGhosted: @"OtherStreet" 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: @"OtherCity"]) || ![self _isGhosted: @"OtherCity" inContext: context])
{
[element setSingleValue: [theValues objectForKey: @"OtherCity"]
atIndex: 3 forKey: @""];
}
if ((o = [theValues objectForKey: @"OtherState"]) || ![self _isGhosted: @"OtherState" inContext: context])
{
[element setSingleValue: [theValues objectForKey: @"OtherState"]
atIndex: 4 forKey: @""];
}
if ((o = [theValues objectForKey: @"OtherPostalCode"]) || ![self _isGhosted: @"OtherPostalCode" inContext: context])
{
[element setSingleValue: [theValues objectForKey: @"OtherPostalCode"]
atIndex: 5 forKey: @""];
}
if ((o = [theValues objectForKey: @"OtherCountry"]) || ![self _isGhosted: @"OtherCountry" inContext: context])
{
[element setSingleValue: [theValues objectForKey: @"OtherCountry"]
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: @""];
@@ -530,7 +303,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: @""];
@@ -540,75 +313,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"]];
if ((o = [theValues objectForKey: @"LastName"]) || ![self _isGhosted: @"LastName" inContext: context])
l = o ? o : @"";
if ((o = [theValues objectForKey: @"FirstName"]) || ![self _isGhosted: @"FirstName" inContext: context])
f = o ? o : @"";
if ((o = [theValues objectForKey: @"MiddleName"]) || ![self _isGhosted: @"MiddleName" inContext: context])
m = o ? o : @"";
if ((o = [theValues objectForKey: @"Title"]) || ![self _isGhosted: @"Title" inContext: context])
p = o ? o : @"";
if ((o = [theValues objectForKey: @"Suffix"]) || ![self _isGhosted: @"Suffix" inContext: context])
s = o ? o : @"";
[self setNWithFamily: l given: f additional: m prefixes: p suffixes: s];
[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"]))
+1
View File
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import "NSCalendarDate+ActiveSync.h"
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#define ONE_DAY 86400
+11 -43
View File
@@ -30,13 +30,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import "NSData+ActiveSync.h"
#import <Foundation/NSProcessInfo.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <Foundation/NSString.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NSObject+Logs.h>
#include <wbxml/wbxml.h>
#include <wbxml/wbxml_conv.h>
#include <wbxml/wbxml_errors.h>
#define WBXMLDEBUG 0
@@ -44,18 +45,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];
[self errorWithFormat: @"Original data written to: %@", path];
}
//
@@ -63,33 +57,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
@@ -114,7 +82,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
[self errorWithFormat: @"wbxml2xml failed: %s\n", wbxml_errors_string(ret)];
[self errorWithFormat: @"wbxml2xmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
return nil;
}
@@ -147,7 +115,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
[self logWithFormat: @"xml2wbxml failed: %s\n", wbxml_errors_string(ret)];
[self logWithFormat: @"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
return nil;
}
@@ -162,7 +130,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
[self errorWithFormat: @"xml2wbxml failed: %s\n", wbxml_errors_string(ret)];
[self errorWithFormat: @"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
free(wbxml);
wbxml_conv_xml2wbxml_destroy(conv);
+2 -5
View File
@@ -1,6 +1,6 @@
/*
Copyright (c) 2014-2015, Inverse inc.
Copyright (c) 2014, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define __NSSTRINGACTIVESYNC_H__
#import <Foundation/NSString.h>
#include "SOGoActiveSyncConstants.h"
@class NSCalendarDate;
@@ -48,11 +49,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSString *) deviceType;
- (NSString *) attachmentName;
- (NSString *) command;
- (NSString *) collectionid;
- (NSString *) itemid;
- (BOOL) acceptsMultiPart;
- (NSData *) convertHexStringToBytes;
- (NSString *) protocolVersion;
@end
+9 -69
View File
@@ -31,6 +31,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <Foundation/NSArray.h>
#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>
@@ -62,7 +65,11 @@ static NSArray *easCommandParameters = nil;
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
return [self safeStringByEscapingXMLString: YES];
NSString *s;
s = [self safeString];
return [s stringByEscapingHTMLString];
}
- (int) activeSyncFolderType
@@ -135,31 +142,6 @@ static NSArray *easCommandParameters = nil;
return o;
}
- (NSString *) protocolVersion
{
NSMutableArray *components;
components = [NSMutableArray arrayWithArray: [[[self componentsSeparatedByString: @"?"] lastObject] componentsSeparatedByString: @"&"]];
// We handle BASE64 encoded queryStrings. See http://msdn.microsoft.com/en-us/library/ee160227%28v=exchg.80%29.aspx for details.
if ([components count] == 1)
{
NSData *queryString;
const char* qs_bytes;
queryString = [[components objectAtIndex: 0] dataByDecodingBase64];
if (![queryString length])
return nil;
qs_bytes = (const char*)[queryString bytes];
return [NSString stringWithFormat:@"%.1f", (float)((uint8_t)qs_bytes[0]/10)];
}
return nil;
}
- (NSString *) _valueForParameter: (NSString *) theParameter
{
NSMutableArray *components;
@@ -200,11 +182,6 @@ static NSArray *easCommandParameters = nil;
// Command code, 1 byte, ie.: cmd=
cmd_code = qs_bytes[1];
// Check whether the command code is within the known range.
if (cmd_code < 0 || cmd_code > 22)
return nil;
[components addObject: [NSString stringWithFormat: @"cmd=%@", [easCommandCodes objectAtIndex: cmd_code]]];
// Device ID length and Device ID (variable)
@@ -234,7 +211,7 @@ static NSArray *easCommandParameters = nil;
// parameter_code 7 == Options
// http://msdn.microsoft.com/en-us/library/ee237789(v=exchg.80).aspx
if (parameter_code == 7 && ! [parameterValue isEqualToString: @"\000"] )
if (parameter_code == 7)
[components addObject: [NSString stringWithFormat: @"%@=%@", [easCommandParameters objectAtIndex: parameter_code],
([parameterValue isEqualToString: @"\001"]) ? @"SaveInSent" : @"AcceptMultiPart"]];
else
@@ -321,43 +298,6 @@ static NSArray *easCommandParameters = nil;
return s;
}
- (NSString *) itemid
{
NSString *s;
s = [self _valueForParameter: @"ITEMID="];
if (!s)
s = @"Unknown";
return s;
}
- (NSString *) collectionid
{
NSString *s;
s = [self _valueForParameter: @"COLLECTIONID="];
if (!s)
s = @"Unknown";
return s;
}
- (BOOL) acceptsMultiPart
{
NSString *s;
s = [self _valueForParameter: @"OPTIONS="];
if (s && [s rangeOfString: @"AcceptMultiPart" options: NSCaseInsensitiveSearch].location != NSNotFound)
return YES;
return NO;
}
//
// FIXME: combine with our OpenChange code.
//
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import "SOGoActiveSyncDispatcher.h"
#import <DOM/DOMElement.h>
#import <DOM/DOMProtocols.h>
@class WOResponse;
File diff suppressed because it is too large. Load diff
+1 -14
View File
@@ -1,6 +1,6 @@
/*
Copyright (c) 2014-2015, Inverse inc.
Copyright (c) 2014, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -27,31 +27,19 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <Foundation/NSObject.h>
#include "SOGoActiveSyncConstants.h"
@class NSCalendarDate;
@class NSException;
@class NSMutableDictionary;
@class NSURL;
@class NSNumber;
static volatile BOOL easShouldTerminate = NO;
@interface SOGoActiveSyncDispatcher : NSObject
{
NSURL *folderTableURL;
NSDictionary *imapFolderGUIDS;
id context;
NSNumber *syncRequest;
BOOL debugOn;
}
- (NSMutableDictionary *) globalMetadataForDevice;
- (id) collectionFromId: (NSString *) theCollectionId
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType;
@@ -64,6 +52,5 @@ static volatile BOOL easShouldTerminate = NO;
- (NSURL *) folderTableURL;
- (void) ensureFolderTableExists;
- (BOOL) easShouldTerminate;
@end
File diff suppressed because it is too large. Load diff
-3
View File
@@ -42,9 +42,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
- (NSString *) storeMail: (NSDictionary *) theValues
inBuffer: (NSMutableString *) theBuffer
inContext: (WOContext *) _context;
@end
File diff suppressed because it is too large. Load diff
-1
View File
@@ -37,7 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@interface SOGoSyncCacheObject : NSObject
{
@public
id _uid;
id _sequence;
}
+13 -22
View File
@@ -32,17 +32,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSNull.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
static Class NSNullK;
@implementation SOGoSyncCacheObject
+ (void) initialize
{
NSNullK = [NSNull class];
}
- (id) init
{
if ((self = [super init]))
@@ -54,14 +46,14 @@ 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];
}
@@ -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
@@ -27,11 +27,9 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <NGObjWeb/SoObjectWebDAVDispatcher.h>
#include <NGObjWeb/SoObject+SoDAV.h>
#include <NGObjWeb/WEClientCapabilities.h>
#include <NGObjWeb/WOContext.h>
#include <NGObjWeb/WORequest.h>
@@ -39,7 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSArray.h>
@interface SoObjectWebDAVDispatcher (ActiveSync)
- (id)_callObjectMethod:(NSString *)_method inContext:(WOContext *)_ctx;
+37 -59
View File
@@ -30,38 +30,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import "iCalAlarm+ActiveSync.h"
#import <Foundation/NSDictionary.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <Foundation/NSString.h>
#import <NGExtensions/NSString+misc.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGCards/iCalAlarm.h>
#import <NGCards/iCalEvent.h>
#import <NGCards/iCalTrigger.h>
#import <NGCards/NSCalendarDate+NGCards.h>
#include "NSDate+ActiveSync.h"
@implementation iCalAlarm (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSMutableString *s;
NSCalendarDate *nextAlarmDate;
NSInteger delta;
s = [NSMutableString string];
nextAlarmDate = [self nextAlarmDate];
delta = (int)(([[(iCalEvent *)parent startDate] timeIntervalSince1970] - [nextAlarmDate timeIntervalSince1970])/60);
if ([parent isKindOfClass: [iCalEvent class]])
if ([[self action] caseInsensitiveCompare: @"DISPLAY"] == NSOrderedSame)
{
NSCalendarDate *nextAlarmDate;
NSInteger delta;
nextAlarmDate = [self nextAlarmDate];
delta = (int)(([[(iCalEvent *)parent startDate] timeIntervalSince1970] - [nextAlarmDate timeIntervalSince1970])/60);
// don't send negative reminder - not supported
if (delta > 0)
[s appendFormat: @"<Reminder xmlns=\"Calendar:\">%d</Reminder>", (int)delta];
}
else
{
[s appendFormat: @"<ReminderTime xmlns=\"Task:\">%@</ReminderTime>", [nextAlarmDate activeSyncRepresentationInContext: context]];
[s appendFormat: @"<Reminder xmlns=\"Calendar:\">%d</Reminder>", delta];
}
return s;
@@ -73,56 +70,37 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
iCalTrigger *trigger;
id o;
if ((o = [theValues objectForKey: @"Reminder"]))
o = [theValues objectForKey: @"Reminder"];
// Outlook: if reminder is set to 0 minutes before start save it as 1 minute since -> 0 minutes in not accepted by SOGo
if ([o isEqualToString: @"0"])
o = @"1";
trigger = [iCalTrigger elementWithTag: @"TRIGGER"];
[trigger setValueType: @"DURATION"];
[self setTrigger: trigger];
[self setAction: @"DISPLAY"];
// SOGo web ui only supports 1w but not 2w (custom reminder only supports min/hours/days)
// 1week = -P1W
// 2weeks > -PxD
// xdays > -PxD
// xhours -> -PTxH
// xmin -> -PTxM
if ([o intValue] == 10080)
[trigger setSingleValue: [NSString stringWithFormat: @"-P1W" ] forKey: @""];
else
{
// Outlook: if reminder is set to 0 minutes before starttime, save it as 1 minute since -> 0 minutes in not accepted by SOGo
if ([o isEqualToString: @"0"])
o = @"1";
trigger = [iCalTrigger elementWithTag: @"TRIGGER"];
[trigger setValueType: @"DURATION"];
[self setTrigger: trigger];
if (![[self action] length])
[self setAction: @"DISPLAY"];
// SOGo web ui only supports 1w but not 2w (custom reminder only supports min/hours/days)
// 1week = -P1W
// 2weeks > -PxD
// xdays > -PxD
// xhours -> -PTxH
// xmin -> -PTxM
if ([o intValue] == 10080)
[trigger setSingleValue: [NSString stringWithFormat: @"-P1W" ] forKey: @""];
if (([o intValue] % 1440) == 0)
[trigger setSingleValue: [NSString stringWithFormat: @"-P%dD", ([o intValue] / 1440)] forKey: @""];
else
{
if (([o intValue] % 1440) == 0)
[trigger setSingleValue: [NSString stringWithFormat: @"-P%dD", ([o intValue] / 1440)] forKey: @""];
if (([o intValue] % 60) == 0)
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%dH", ([o intValue] / 60)] forKey: @""];
else
{
if (([o intValue] % 60) == 0)
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%dH", ([o intValue] / 60)] forKey: @""];
else
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%@M", o] forKey: @""];
}
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%@M", o] forKey: @""];
}
}
else if ((o = [theValues objectForKey: @"ReminderTime"]))
{
o = [o calendarDate];
trigger = [iCalTrigger elementWithTag: @"TRIGGER"];
[trigger setValueType: @"DATE-TIME"];
[trigger setSingleValue: [NSString stringWithFormat: @"%@Z", [o iCalFormattedDateTimeString]] forKey: @""];
if ((o = [theValues objectForKey: @"ReminderSet"]))
{
if ([o intValue] == 0)
[trigger setValue: 0 ofAttribute: @"x-webstatus" to: @"triggered"];
}
[self setTrigger: trigger];
if (![[self action] length])
[self setAction: @"DISPLAY"];
}
}
@end
+1 -3
View File
@@ -41,9 +41,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
- (void) changeParticipationStatus: (NSDictionary *) theValues
inContext: (WOContext *) context
component: (id) component;
@end
#endif
+72 -465
View File
@@ -30,27 +30,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import "iCalEvent+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#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 <NGCards/iCalCalendar.h>
#import <NGCards/iCalDateTime.h>
#import <NGCards/iCalPerson.h>
#import <NGCards/NSCalendarDate+NGCards.h>
#import <NGCards/NSString+NGCards.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"
@@ -63,7 +61,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (int) _attendeeStatus: (iCalPerson *) attendee
{
int attendee_status;
attendee_status = 5;
if ([[attendee partStat] caseInsensitiveCompare: @"ACCEPTED"] == NSOrderedSame)
attendee_status = 3;
@@ -75,29 +73,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
return attendee_status;
}
//
// Possible values are:
// 0 Free
// 1 Tentative
// 2 Busy
// 3 Out of Office
// 4 Working elsewhere
//
- (int) _busyStatus: (iCalPerson *) attendee
{
int attendee_status;
attendee_status = 2;
if ([[attendee partStat] caseInsensitiveCompare: @"DECLINED"] == NSOrderedSame)
attendee_status = 0;
else if ([[attendee partStat] caseInsensitiveCompare: @"TENTATIVE"] == NSOrderedSame)
attendee_status = 1;
return attendee_status;
}
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSMutableString *s;
@@ -122,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 && [[context objectForKey: @"ASProtocolVersion"] floatValue] < 16.0)
if ([self isAllDay])
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>",
[[[self startDate] dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
@@ -141,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 && [[context objectForKey: @"ASProtocolVersion"] floatValue] < 16.0)
if ([self isAllDay])
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>",
[[[self endDate] dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
@@ -151,24 +123,26 @@ 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];
o = [organizer cn];
if ([o length])
[s appendFormat: @"<Organizer_Name xmlns=\"Calendar:\">%@</Organizer_Name>", [o activeSyncRepresentationInContext: context]];
[s appendFormat: @"<Organizer_Name xmlns=\"Calendar:\">%@</Organizer_Name>", o];
}
}
@@ -187,10 +161,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
attendee = [attendees objectAtIndex: i];
[s appendFormat: @"<Attendee_Email xmlns=\"Calendar:\">%@</Attendee_Email>", [[attendee rfc822Email] activeSyncRepresentationInContext: context]];
if ([[attendee cn] length])
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee cn] activeSyncRepresentationInContext: context]];
else
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee rfc822Email] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee cn] activeSyncRepresentationInContext: context]];
attendee_status = [self _attendeeStatus: attendee];
@@ -209,7 +180,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
else
{
meetingStatus = 0; // The event is an appointment, which has no attendees.
meetingStatus = 0; // appointment
}
// This depends on the 'NEEDS-ACTION' parameter.
@@ -230,13 +201,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[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>", [self _busyStatus: attendee]];
}
else
{
// If it's a normal event (i.e. with no organizer/attendee) or we are the organizer of an event
// invitation, we set the busy status depending on TRANSP.
[s appendFormat: @"<BusyStatus xmlns=\"Calendar:\">%d</BusyStatus>", (([self isOpaque]) ? 2 : 0)];
[s appendFormat: @"<BusyStatus xmlns=\"Calendar:\">%d</BusyStatus>", 2];
}
[s appendFormat: @"<MeetingStatus xmlns=\"Calendar:\">%d</MeetingStatus>", meetingStatus];
@@ -247,12 +212,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Location
if ([[self location] length])
{
if ([[context objectForKey: @"ASProtocolVersion"] floatValue] >= 16.0)
[s appendFormat: @"<Location xmlns=\"AirSyncBase:\"><DisplayName>%@</DisplayName></Location>", [[self location] activeSyncRepresentationInContext: context]];
else
[s appendFormat: @"<Location xmlns=\"Calendar:\">%@</Location>", [[self location] activeSyncRepresentationInContext: context]];
}
[s appendFormat: @"<Location xmlns=\"Calendar:\">%@</Location>", [[self location] activeSyncRepresentationInContext: context]];
// Importance - NOT SUPPORTED - DO NOT ENABLE
//o = [self priority];
@@ -265,37 +225,9 @@ 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 objectForKey: @"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;
@@ -318,89 +250,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[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])
{
iCalAlarm *alarm;
alarm = [self firstSupportedAlarm];
alarm = [self firstDisplayOrAudioAlarm];
[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])
{
// 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: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
return s;
}
@@ -446,21 +327,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;
iCalAlarm *alarm;
id o;
int deltasecs;
BOOL isAllDay;
NSMutableArray *occurences;
occurences = [NSMutableArray arrayWithArray: [[self parent] events]];
if ((o = [theValues objectForKey: ([[context objectForKey: @"ASProtocolVersion"] floatValue] >= 16.0) ? @"ClientUid" : @"UID"]))
if ((o = [theValues objectForKey: @"UID"]))
[self setUid: o];
// FIXME: merge with iCalToDo
@@ -472,21 +346,13 @@ 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
//
if ((o = [theValues objectForKey: @"BusyStatus"]))
{
if ([o boolValue])
[self setTransparency: @"OPAQUE"];
else
[self setTransparency: @"TRANSPARENT"];
[o intValue];
}
//
@@ -528,34 +394,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
// FIXME: merge with iCalToDo
if ([[context objectForKey: @"ASProtocolVersion"] isEqualToString: @"2.5"])
{
if ((o = [theValues objectForKey: @"Body"]))
[self setComment: o];
}
else
{
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setComment: o];
}
if ([[context objectForKey: @"ASProtocolVersion"] floatValue] < 16.0 && (o = [theValues objectForKey: @"Location"]))
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setComment: o];
if ((o = [theValues objectForKey: @"Location"]))
[self setLocation: o];
else if ([[context objectForKey: @"ASProtocolVersion"] floatValue] >= 16.0 && (o = [theValues objectForKey: @"Location"]) && [o isKindOfClass: [NSDictionary class]])
[self setLocation: [o objectForKey: @"DisplayName"]];
deltasecs = 0;
start = nil;
if ((o = [theValues objectForKey: @"StartTime"]))
{
o = [o calendarDate];
start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
oldstart = [start dateTime];
[start setTimeZone: tz];
if (isAllDay)
{
if (isAllDay)
{
[start setDate: o];
[start setTimeZone: nil];
}
@@ -563,10 +415,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
[start setDateTime: o];
}
// Calculate delta if start date has been changed.
if (oldstart)
deltasecs = [[start dateTime ] timeIntervalSinceDate: oldstart] * -1;
}
if ((o = [theValues objectForKey: @"EndTime"]))
@@ -586,19 +434,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
}
if ((o = [theValues objectForKey: @"Reminder"]) && [o length])
//
// If an alarm is deinfed with an action != DISPLAY, we ignore the alarm - don't want to overwrite.
//
if ([self hasAlarms] && [[[[self alarms] objectAtIndex: 0] action] caseInsensitiveCompare: @"DISPLAY"] != NSOrderedSame)
{
// Ignore the alarm for now
}
else if ((o = [theValues objectForKey: @"Reminder"]))
{
if ([self hasAlarms])
alarm = [[self firstSupportedAlarm] mutableCopy];
else
alarm = [[iCalAlarm alloc] init];
// NOTE: Outlook sends a 15 min reminder (18 hour for allday) if no reminder is specified
// although no default reminder is defined (File -> Options -> Clendar -> Calendar Options - > Default Reminders)
//
// http://answers.microsoft.com/en-us/office/forum/office_2013_release-outlook/desktop-outlook-calendar-creates-entries-with/9aef72d8-81bb-4a32-a6ab-bf7d216fb811?page=5&tm=1395690285088
//
iCalAlarm *alarm;
alarm = [[iCalAlarm alloc] init];
[alarm takeActiveSyncValues: theValues inContext: context];
[self removeAllAlarms];
@@ -612,7 +464,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
// Recurrence
if ((o = [theValues objectForKey: @"Recurrence"]) && [o isKindOfClass: [NSDictionary class]])
if ((o = [theValues objectForKey: @"Recurrence"]))
{
iCalRecurrenceRule *rule;
@@ -621,177 +473,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
@@ -799,7 +480,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"]];
@@ -807,14 +488,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[self setOrganizer: person];
}
//
// iOS is plain stupid here. It seends event invitations with no Organizer.
// We check this corner-case and if MeetingStatus == 1 (see http://msdn.microsoft.com/en-us/library/ee219342(v=exchg.80).aspx or details)
// and there's no organizer, we fake one.
//
if ((o = [theValues objectForKey: @"MeetingStatus"]))
{
//
// iOS is plain stupid here. It seends event invitations with no Organizer.
// We check this corner-case and if MeetingStatus == 1 (see http://msdn.microsoft.com/en-us/library/ee219342(v=exchg.80).aspx or details)
// and there's no organizer, we fake one.
//
if ([o intValue] == 1 && ![theValues objectForKey: @"Organizer_Email"] && ![[[self organizer] rfc822Email] length])
if ([o intValue] == 1 && ![theValues objectForKey: @"Organizer_Email"])
{
iCalPerson *person;
@@ -824,29 +505,16 @@ 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];
}
}
// Attendees - we don't touch the values if we're an attendee. This is gonna
// be done automatically by the ActiveSync client when invoking MeetingResponse.
if (![self userIsAttendee: [context activeUser]])
{
// 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;
@@ -861,13 +529,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// { "Attendee_Email" = "sogo3@example.com"; "Attendee_Name" = "Wolfgang Fritz"; "Attendee_Status" = 5; "Attendee_Type" = 1; }
attendee = [o objectAtIndex: i];
if ([self isOrganizer: [attendee objectForKey: @"Attendee_Email"]])
continue;
person = [iCalPerson elementWithTag: @"attendee"];
[person setCn: [attendee objectForKey: @"Attendee_Name"]];
[person setEmail: [attendee objectForKey: @"Attendee_Email"]];
status = [[attendee objectForKey: @"Attendee_Status"] intValue];
switch (status)
@@ -884,10 +549,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
case 0:
case 5:
default:
{
[person setPartStat: @"NEEDS-ACTION"];
[person setRsvp: @"TRUE"];
}
[person setPartStat: @"NEEDS-ACTION"];
break;
}
@@ -899,61 +561,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[self setAttendees: attendees];
}
}
[self setLastModified: [NSCalendarDate calendarDate]];
}
- (void) changeParticipationStatus: (NSDictionary *) theValues
inContext: (WOContext *) context
component: (id) component
{
NSString *status;
iCalAlarm *alarm;
iCalPerson *attendee;
id o;
attendee = [self userAsAttendee: [context activeUser]];
status = [attendee partStat];
alarm = nil;
// 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";
}
if ((o = [theValues objectForKey: @"Reminder"]) && [o length])
{
if ([self hasAlarms])
alarm = [[self firstSupportedAlarm] mutableCopy];
else
alarm = [[iCalAlarm alloc] init];
[alarm takeActiveSyncValues: theValues inContext: context];
}
// There's no delegate in EAS
[(SOGoAppointmentObject *) component changeParticipationStatus: status
withDelegate: nil
alarm: alarm];
RELEASE(alarm);
}
@end
+24 -51
View File
@@ -35,42 +35,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSString.h>
#import <NGCards/iCalEvent.h>
#import <NGCards/iCalToDo.h>
#import <NGCards/iCalByDayMask.h>
#import <NGCards/iCalDateTime.h>
#import <NGCards/iCalTimeZone.h>
#import "NSCalendarDate+ActiveSync.h"
#import "NSDate+ActiveSync.h"
@implementation iCalRecurrenceRule (ActiveSync)
- (NSCalendarDate *) _adjustedStartDate
{
iCalTimeZone *timeZone;
timeZone = [(iCalDateTime *)[[self parent] firstChildWithTag: @"dtstart"] timeZone];
if (timeZone)
return [timeZone computedDateForDate: [[self parent] startDate]];
else
return [[self parent] startDate];
}
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSMutableString *s;
NSString *t;
int type;
s = [NSMutableString string];
if ([[self parent] isKindOfClass: [iCalToDo class]])
t = @"Tasks";
else
t = @"Calendar";
[s appendFormat: @"<Recurrence xmlns=\"%@:\">", t];
[s appendString: @"<Recurrence xmlns=\"Calendar:\">"];
// 0 -> daily, 1 -> weekly, 2 -> montly, 5 -> yearly
type = 0;
@@ -82,11 +61,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 1 -> sunday, 2 -> monday, 4 -> tuesday, 8 -> wednesday, 16 -> thursday, 32 -> friday, 64 -> saturday, 127 -> last day of month (montly or yearl recurrences only)
if ([[self byDayMask] isWeekDays])
{
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"%@:\">%d</Recurrence_DayOfWeek>", t, (2|4|8|16|32)];
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (2|4|8|16|32)];
}
else
{
[s appendFormat: @"<Recurrence_Interval xmlns=\"%@:\">%d</Recurrence_Interval>", t, [self repeatInterval]];
[s appendFormat: @"<Recurrence_Interval xmlns=\"Calendar:\">%d</Recurrence_Interval>", [self repeatInterval]];
}
}
else if ([self frequency] == iCalRecurrenceFrequenceWeekly)
@@ -111,11 +90,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
// No byDayMask, we take the event's start date to compute the DayOfWeek
// 0 == Sunday, 6 == Saturday
v = (1 << [[self _adjustedStartDate] dayOfWeek]);
v = (1 << [[[self parent] startDate] dayOfWeek]);
}
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"%@:\">%d</Recurrence_DayOfWeek>", t, v];
[s appendFormat: @"<Recurrence_Interval xmlns=\"%@:\">%d</Recurrence_Interval>", t, [self repeatInterval]];
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", v];
[s appendFormat: @"<Recurrence_Interval xmlns=\"Calendar:\">%d</Recurrence_Interval>", [self repeatInterval]];
}
else if ([self frequency] == iCalRecurrenceFrequenceMonthly)
{
@@ -132,9 +111,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (firstOccurrence < 0)
firstOccurrence = 5;
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"%@:\">%d</Recurrence_DayOfWeek>", t, (1 << [dm firstDay])];
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"%@:\">%d</Recurrence_WeekOfMonth>", t, firstOccurrence];
[s appendFormat: @"<Recurrence_Interval xmlns=\"%@:\">%d</Recurrence_Interval>", t, [self repeatInterval]];
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (1 << [dm firstDay])];
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"Calendar:\">%d</Recurrence_WeekOfMonth>", firstOccurrence];
}
else if ([[self byMonthDay] count])
{
@@ -148,9 +126,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
iCalByDayMask *dm;
dm = [self byDayMask];
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"%@:\">%d</Recurrence_DayOfWeek>", t, (1 << [dm firstDay])];
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"%@:\">%d</Recurrence_WeekOfMonth>", t, 5];
[s appendFormat: @"<Recurrence_Interval xmlns=\"%@:\">%d</Recurrence_Interval>", t, [self repeatInterval]];
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (1 << [dm firstDay])];
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"Calendar:\">%d</Recurrence_WeekOfMonth>", 5];
}
else
{
@@ -162,7 +139,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
// Simple reccurrence rule of type "Monthly"
type = 2;
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"%@:\">%d</Recurrence_DayOfMonth>", t, [[self _adjustedStartDate] dayOfMonth]];
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"Calendar:\">%d</Recurrence_DayOfMonth>",
[[[self parent] startDate] dayOfMonth]];
}
}
else if ([self frequency] == iCalRecurrenceFrequenceYearly)
@@ -181,39 +159,33 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (firstOccurrence < 0)
firstOccurrence = 5;
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"%@:\">%d</Recurrence_DayOfWeek>", t, (1 << [dm firstDay])];
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"%@:\">%d</Recurrence_WeekOfMonth>", t, firstOccurrence];
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"%@:\">%@</Recurrence_MonthOfYear>", t,
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (1 << [dm firstDay])];
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"Calendar:\">%d</Recurrence_WeekOfMonth>", firstOccurrence];
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"Calendar:\">%@</Recurrence_MonthOfYear>",
[self flattenedValuesForKey: @"bymonth"]];
}
else
{
type = 5; // Yearly
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"%@:\">%@</Recurrence_DayOfMonth>", t,
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"Calendar:\">%@</Recurrence_DayOfMonth>",
[self flattenedValuesForKey: @"bymonthday"]];
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"%@:\">%@</Recurrence_MonthOfYear>", t,
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"Calendar:\">%@</Recurrence_MonthOfYear>",
[self flattenedValuesForKey: @"bymonth"]];
}
}
else
{
type = 5;
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"%@:\">%d</Recurrence_DayOfMonth>", t, [[self _adjustedStartDate] dayOfMonth]];
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"%@:\">%d</Recurrence_MonthOfYear>", t, [[self _adjustedStartDate] monthOfYear]];
}
type = 5;
}
[s appendFormat: @"<Recurrence_Type xmlns=\"%@:\">%d</Recurrence_Type>", t, type];
if ([[self parent] isKindOfClass: [iCalToDo class]])
[s appendFormat: @"<Recurrence_Start xmlns=\"%@:\">%@</Recurrence_Start>", t, [[[self parent] startDate] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<Recurrence_Type xmlns=\"Calendar:\">%d</Recurrence_Type>", type];
// Occurrences / Until
//[s appendFormat: @"<Recurrence_Occurrences xmlns=\"Calendar:\">%d</Recurrence_Occurrences>", 5];
if ([self repeatCount])
{
[s appendFormat: @"<Recurrence_Occurrences xmlns=\"%@:\">%@</Recurrence_Occurrences>", t,
[s appendFormat: @"<Recurrence_Occurrences xmlns=\"Calendar:\">%@</Recurrence_Occurrences>",
[self flattenedValuesForKey: @"count"]];
}
else if ([self untilDate])
@@ -224,10 +196,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//ud = [[context activeUser] userDefaults];
//[date setTimeZone: [ud timeZone]];
[s appendFormat: @"<Recurrence_Until xmlns=\"%@:\">%@</Recurrence_Until>", t,
[s appendFormat: @"<Recurrence_Until xmlns=\"Calendar:\">%@</Recurrence_Until>",
[date activeSyncRepresentationWithoutSeparatorsInContext: context]];
}
[s appendString: @"</Recurrence>"];
return s;
+17 -34
View File
@@ -31,10 +31,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <Foundation/NSArray.h>
#include <Foundation/NSCalendarDate.h>
#include <Foundation/NSData.h>
#include <Foundation/NSDate.h>
#include <Foundation/NSString.h>
#import <NGCards/iCalByDayMask.h>
#import <NGCards/iCalTimeZonePeriod.h>
#import <NGCards/iCalRecurrenceRule.h>
#import <NGExtensions/NGBase64Coding.h>
#include "NSData+ActiveSync.h"
@@ -78,28 +83,10 @@ struct SYSTEMTIME {
tzData->wDay = ([mask firstOccurrence] == -1) ? 5 : [mask firstOccurrence];
dateValue = [self startDate];
if (![dateValue hourOfDay])
{
if ([mask firstDay]-1 < 0)
tzData->wDayOfWeek = 6;
else
tzData->wDayOfWeek = [mask firstDay]-1;
tzData->wHour = 23;
tzData->wMinute = 59;
tzData->wSecond = 59;
tzData->wMilliseconds = 999;
}
else
{
tzData->wDayOfWeek = [mask firstDay];
tzData->wHour = [dateValue hourOfDay];
tzData->wMinute = [dateValue minuteOfHour];
tzData->wSecond = [dateValue secondOfMinute];
tzData->wMilliseconds = 0;
}
tzData->wHour = [dateValue hourOfDay];
tzData->wMinute = [dateValue minuteOfHour];
tzData->wSecond = [dateValue secondOfMinute];
tzData->wMilliseconds = 0;
}
}
@@ -141,7 +128,7 @@ struct SYSTEMTIME {
//uint16_t wStandardYear;
struct SYSTEMTIME stStandardDate;
//uint16_t wDaylightYear;
struct SYSTEMTIME stDaylightDate = {0,0,0,0,0,0,0,0};
struct SYSTEMTIME stDaylightDate;
char standardName[64], daylightName[64];
@@ -157,17 +144,13 @@ struct SYSTEMTIME {
period = [self _mostRecentPeriodWithName: @"DAYLIGHT"];
if (!period)
{
stStandardDate.wMonth = 0;
lDaylightBias = 0;
}
else
{
lDaylightBias = (uint32_t) -([period secondsOffsetFromGMT] / 60) - lBias;
[period _fillTZDate: &stDaylightDate];
//wStandardYear = stStandardDate.wYear;
//wDaylightYear = stDaylightDate.wYear;
}
stStandardDate.wMonth = 0;
lDaylightBias = (uint32_t) -([period secondsOffsetFromGMT] / 60) - lBias;
[period _fillTZDate: &stDaylightDate];
//wStandardYear = stStandardDate.wYear;
//wDaylightYear = stDaylightDate.wYear;
// We build the timezone
[bytes appendBytes: &lBias length: 4];
+18 -111
View File
@@ -29,12 +29,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "iCalToDo+ActiveSync.h"
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#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>
@@ -42,14 +45,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalDateTime.h>
#import <NGCards/iCalTimeZone.h>
#import <NGCards/iCalTrigger.h>
#import <Appointments/iCalEntityObject+SOGo.h>
#include "NSDate+ActiveSync.h"
#include "NSString+ActiveSync.h"
#include "iCalRecurrenceRule+ActiveSync.h"
#include "iCalAlarm+ActiveSync.h"
@implementation iCalToDo (ActiveSync)
@@ -64,10 +62,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
s = [NSMutableString string];
// Complete
[s appendFormat: @"<Complete xmlns=\"Tasks:\">%d</Complete>", [[self status] isEqualToString: @"COMPLETED"] ? 1 : 0];
o = [self completed];
[s appendFormat: @"<Complete xmlns=\"Tasks:\">%d</Complete>", (o ? 1 : 0)];
// DateCompleted
if ((o = [self completed]))
if (o)
[s appendFormat: @"<DateCompleted xmlns=\"Tasks:\">%@</DateCompleted>", [o activeSyncRepresentationInContext: context]];
// Start date
@@ -84,10 +83,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendFormat: @"<DueDate xmlns=\"Tasks:\">%@</DueDate>", [o activeSyncRepresentationInContext: context]];
[s appendFormat: @"<UTCDueDate xmlns=\"Tasks:\">%@</UTCDueDate>", [o activeSyncRepresentationInContext: context]];
}
// Recurrence rules
if ([self isRecurrent])
[s appendString: [[[self recurrenceRules] lastObject] activeSyncRepresentationInContext: context]];
// Importance
o = [self priority];
@@ -99,33 +94,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
v = 1;
[s appendFormat: @"<Importance xmlns=\"Tasks:\">%d</Importance>", v];
// Reminder
if ([self hasAlarms])
{
iCalAlarm *alarm;
NSString *webstatus;
if ((alarm = [self firstSupportedAlarm]))
{
webstatus = [[alarm trigger] value: 0 ofAttribute: @"x-webstatus"];
if (!webstatus || ([webstatus caseInsensitiveCompare: @"TRIGGERED"] != NSOrderedSame))
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 1];
else
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
[s appendString: [alarm activeSyncRepresentationInContext: context]];
}
else
{
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
}
}
else
{
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
}
// Reminder - FIXME
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
// Sensitivity
if ([[self accessClass] isEqualToString: @"PRIVATE"])
v = 2;
else if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
@@ -133,8 +104,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
v = 0;
[s appendFormat: @"<Sensitivity xmlns=\"Tasks:\">%d</Sensitivity>", v];
categories = [self categories];
if ([categories count])
@@ -157,22 +126,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
o = [o activeSyncRepresentationInContext: context];
if ([[context objectForKey: @"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: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
return s;
}
@@ -192,16 +152,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[self setSummary: o];
// FIXME: merge with iCalEvent
if ([[context objectForKey: @"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"])) )
@@ -213,11 +166,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[completed setDate: o];
[self setStatus: @"COMPLETED"];
}
else
{
[self setStatus: @"IN-PROCESS"];
[self setCompleted: nil];
}
if ((o = [theValues objectForKey: @"DueDate"]))
{
@@ -229,16 +177,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[due setDateTime: o];
}
if ((o = [theValues objectForKey: @"StartDate"]))
{
iCalDateTime *due;
o = [o calendarDate];
due = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
[due setTimeZone: tz];
[due setDateTime: o];
}
// 2 == high, 1 == normal, 0 == low
if ((o = [theValues objectForKey: @"Importance"]))
{
@@ -276,39 +214,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ((o = [theValues objectForKey: @"ReminderTime"]))
{
iCalAlarm *alarm;
alarm = [[iCalAlarm alloc] init];
[alarm takeActiveSyncValues: theValues inContext: context];
[self removeAllAlarms];
[self addToAlarms: alarm];
RELEASE(alarm);
}
// Recurrence
if ((o = [theValues objectForKey: @"Recurrence"]) && !([[o objectForKey: @"Recurrence_DeadOccur"] intValue]))
{
iCalRecurrenceRule *rule;
rule = [[iCalRecurrenceRule alloc] init];
[self setRecurrenceRules: [NSArray arrayWithObject: rule]];
RELEASE(rule);
[rule takeActiveSyncValues: o inContext: context];
if (!([theValues objectForKey: @"StartDate"]))
{
iCalDateTime *start;
start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
[start setTimeZone: tz];
[start setDate: [[o objectForKey: @"Recurrence_Start"] calendarDate]];
}
}
}
@end
+2 -2
View File
@@ -28,7 +28,7 @@
ProxyPass /SOGo http://127.0.0.1:20000/SOGo interpolate
ProxyPass / http://127.0.0.1:20000/SOGo/dav/ interpolate
<Location />
<IfVersion < 2.4>
<IfVersion < 2.4>
Order deny,allow
Allow from all
</IfVersion>
@@ -40,7 +40,7 @@
<Proxy http://127.0.0.1:20000>
RequestHeader set "x-webobjects-server-port" "8843"
RequestHeader set "x-webobjects-server-name" "CHANGETHIS:8843"
RequestHeader set "x-webobjects-server-url" "https://CHANGETHIS:8843"
RequestHeader set "x-webobjects-server-url" "http://CHANGETHIS:8843"
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
AddDefaultCharset UTF-8
</Proxy>
+11 -30
View File
@@ -6,7 +6,7 @@ Alias /SOGo/WebServerResources/ \
<Directory /usr/lib/GNUstep/SOGo/>
AllowOverride None
<IfVersion < 2.4>
<IfVersion < 2.4>
Order deny,allow
Allow from all
</IfVersion>
@@ -22,14 +22,6 @@ Alias /SOGo/WebServerResources/ \
</IfModule>
</Directory>
# Don't send the Referer header for cross-origin requests
Header always set Referrer-Policy "same-origin"
<Location /SOGo>
# Don't cache dynamic content
Header set Cache-Control "max-age=0, no-cache, no-store"
</Location>
## Uncomment the following to enable proxy-side authentication, you will then
## need to set the "SOGoTrustProxyAuthentication" SOGo user default to YES and
## adjust the "x-webobjects-remote-user" proxy header in the "Proxy" section
@@ -53,12 +45,8 @@ Header always set Referrer-Policy "same-origin"
#</Location>
ProxyRequests Off
ProxyPreserveHost On
SetEnv proxy-nokeepalive 1
# Uncomment the following lines if you experience "Bad gateway" errors with mod_proxy
#SetEnv proxy-initial-not-pooled 1
#SetEnv force-proxy-request-1.0 1
ProxyPreserveHost On
# When using CAS, you should uncomment this and install cas-proxy-validate.py
# in /usr/lib/cgi-bin to reduce server overloading
@@ -69,8 +57,7 @@ SetEnv proxy-nokeepalive 1
# Allow from your-cas-host-addr
# </Proxy>
# Redirect / to /SOGo
#RedirectMatch ^/$ https://mail.yourdomain.com/SOGo
ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
# Enable to use Microsoft ActiveSync support
# Note that you MUST have many sogod workers to use ActiveSync.
@@ -80,24 +67,18 @@ SetEnv proxy-nokeepalive 1
# http://127.0.0.1:20000/SOGo/Microsoft-Server-ActiveSync \
# retry=60 connectiontimeout=5 timeout=360
ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0 nocanon
<Proxy http://127.0.0.1:20000/SOGo>
## Adjust the following to your configuration
## and make sure to enable the headers module
<IfModule headers_module>
RequestHeader set "x-webobjects-server-port" "443"
SetEnvIf Host (.*) HTTP_HOST=$1
RequestHeader set "x-webobjects-server-name" "%{HTTP_HOST}e" env=HTTP_HOST
RequestHeader set "x-webobjects-server-url" "https://%{HTTP_HOST}e" env=HTTP_HOST
## 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"
## When using proxy-side autentication, you need to uncomment and
## adjust the following line:
RequestHeader unset "x-webobjects-remote-user"
# RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e" env=REMOTE_USER
RequestHeader unset "x-webobjects-remote-user"
# RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e" env=REMOTE_USER
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
</IfModule>
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
AddDefaultCharset UTF-8
@@ -109,5 +90,5 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0 nocanon
<IfModule rewrite_module>
RewriteEngine On
RewriteRule ^/.well-known/caldav/?$ /SOGo/dav [R=301]
RewriteRule ^/.well-known/carddav/?$ /SOGo/dav [R=301]
</IfModule>
-4353
View File
File diff suppressed because it is too large. Load diff
+21010 -92899
View File
File diff suppressed because it is too large. Load diff
+5655
View File
File diff suppressed because it is too large. Load diff
+5 -26
View File
@@ -1,29 +1,8 @@
all: pdf html
all: $(patsubst %.asciidoc,%.pdf,$(wildcard *.asciidoc))
ASCIIDOCS = $(wildcard SOGo*.asciidoc)
PDFS = $(patsubst %.asciidoc,%.pdf, $(ASCIIDOCS))
HTML = $(patsubst %.asciidoc,%.html, $(ASCIIDOCS))
%.pdf: %.asciidoc asciidoctor-pdf-theme.yml $(wildcard includes/*.asciidoc)
asciidoctor-pdf \
-a pdf-fontsdir=fonts \
-a release_version=`git describe --abbrev=0 --tags | cut -d'-' -f 2` \
-a release_month=`LANG=en_US.UTF-8 date +%B` \
-a pdf-theme=asciidoctor-pdf-theme.yml \
--trace \
$<
%.html: %.asciidoc $(wildcard includes/*.asciidoc)
asciidoctor \
-D . \
-a release_version=`git describe --abbrev=0 --tags | cut -d'-' -f 2` \
-a release_month=`LANG=en_US.UTF-8 date +%B` \
-n \
$<
pdf: $(PDFS)
html: $(HTML)
%.pdf : %.asciidoc
asciidoc -a docinfo1 -b docbook -d book -o $<.docbook $<
fop -c fonts/fop-config.xml -xsl docbook/xsl/sogo-fo.xsl -xml $<.docbook -pdf $@
clean:
rm -f *.pdf *.html
rm *.asciidoc.docbook *.pdf
-194
View File
@@ -1,194 +0,0 @@
Developer's Guide
=================
////
This file is part of the SOGo project.
See includes/global-attributes.asciidoc
for authors, copyright and license information.
////
include::includes/global-attributes.asciidoc[]
UI and UX
---------
* https://material.io/design/
Frameworks & Tools
------------------
GNUstep
~~~~~~~
SOPE
~~~~
JavaScript libraries
~~~~~~~~~~~~~~~~~~~~
* https://angularjs.org/
* https://material.angularjs.org/
* http://angular-ui.github.io/ui-router/
* http://lodash.com/
* https://github.com/nervgh/angular-file-upload
* https://github.com/a5hik/ng-sortable
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/
* http://standardjs.com
* 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.
Controllers
^^^^^^^^^^^
* Functions not exposed in the controller must be prefixed with an underscore.
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/
* http://stylelint.io/
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.
* FlexBox compatibility http://caniuse.com/#feat=flexbox
Fonts
^^^^^
* http://mozilla.github.io/Fira/[Mozilla Fira]
* https://material.io/tools/icons/[Material icons]
Building frontend
-----------------
* Install the latest stable release of https://nodejs.org[Node.js]
* Install grunt
npm install -g grunt-cli
npm install -g bower
* 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
* Generate the JavaScript and CSS files
cd UI/WebServerResources
npm install
bower install
grunt build
Defining an alternate color theme
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SOGo relies on the https://material.angularjs.org/latest/Theming/01_introduction[theming system of Angular Material] to define the colors of the Web interface.
To overwrite the default theme in SOGo, set the following parameter in `/etc/sogo/sogo.conf`:
SOGoUIAdditionalJSFiles = (js/theme.js);
Edit `theme.js` under `/usr/lib64/GNUstep/SOGo/WebServerResources/js` or `/usr/lib/GNUstep/SOGo/WebServerResources/js` depending on your platform and restart sogod.
If the configuration parameter `SOGoUIxDebugEnabled` is unset or set to `NO` in `/etc/sogo/sogo.conf`, you'll need to generate a new `theme-default.css` stylesheet for the new theme.
. Temporarily set `SOGoUIxDebugEnabled` to `YES`;
. Restart sogod;
. From your favorite browser, open the JavaScript console and type the following:
copy([].slice.call(document.styleSheets)
.map(e => e.ownerNode)
.filter(e => e.hasAttribute('md-theme-style'))
.map(e => e.textContent)
.join('\n')
)
. Overwrite the content of `WebServerResources/css/theme-default.css` with the content of the clipboard;
. Restore the value of `SOGoUIxDebugEnabled` (`NO` or unset);
. Restart sogod.
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 http://stedolan.github.io/jq/[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
File diff suppressed because it is too large. Load diff
@@ -1,13 +1,15 @@
Mobile Devices Configuration Guide
==================================
////
This file is part of the SOGo project.
See includes/global-attributes.asciidoc
for authors, copyright and license information.
See SOGo Mobile Devices Configuration-docinfo.xml for authors,
copyright and license information.
////
include::includes/global-attributes.asciidoc[]
About this Guide
@@ -22,7 +24,7 @@ devices (iPhone, iPod touch, and iPad).
The instructions are based on version {release_version} of SOGo.
The latest version of this guide is available at
https://www.sogo.nu/support.html#/documentation.
http://www.sogo.nu/downloads/documentation.html.
Introduction
------------
@@ -1,13 +1,15 @@
Mozilla Thunderbird Configuration Guide
=======================================
////
This file is part of the SOGo project.
See includes/global-attributes.asciidoc
for authors, copyright and license information.
See SOGo Mozilla Thunderbird Configuration Guide-docinfo.xml for
authors, copyright and license information.
////
include::includes/global-attributes.asciidoc[]
About this Guide
@@ -46,7 +48,7 @@ device, or Outlook 2013
SOGo is developed by a community of developers located mainly in North
America and Europe. More information can be found on
https://www.sogo.nu/.
http://www.sogo.nu/.
Installation
------------
@@ -59,8 +61,9 @@ Mozilla Thunderbird
Mozilla Thunderbird is the official front end client of SOGo.
Mozilla Thunderbird versions 31, 38, 45 and above are supported
and it is recommended to use the latest version of Thunderbird.
Mozilla Thunderbird version 2, 3.1, 10 ESR (Extended Support Release),
17 ESR, 24 and 31 are supported and it is recommended to use version 31 of
Thunderbird.
In order to download and install Mozilla Thunderbird, please visit:
@@ -69,16 +72,33 @@ https://www.mozilla.org/en-US/thunderbird/organizations/all-esr.html
Mozilla Lightning
~~~~~~~~~~~~~~~~~
When using Thunderbird, you can use the latest version of Mozilla
Lightning. Use the Add-ons manager of Thunderbird or visit:
When using version 24 or 31 of Thunderbird, you can use the latest version of
Mozilla Lightning. Use the Add-ons manager of Thunderbird or visit:
https://addons.mozilla.org/en-US/thunderbird/addon/lightning/
When using version 17 ESR of Thunderbird, you can use Mozilla Lightning
version 1.9.1. In order to download the extension, please visit:
https://addons.mozilla.org/en-US/thunderbird/addon/lightning/versions/1.9.1
For Thunderbird 2 and 3.1, you need the _Inverse Edition_of Mozilla
Lightning. It provides back ported features, bug fixes and security
fixes from the current development version of Mozilla Lightning. For
Thunderbird 2, it is based on release version 0.9 of Lightning. For
Thunderbird 3.1, it is based on 1.0b2.
In order to download and install Mozilla Lightning – Inverse Edition for
Thunderbird 2 or 3.1, please visit:
http://www.sogo.nu/downloads/frontends.html
SOGo Connector and SOGo Integrator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The SOGo Connector and Integrator extensions are provided to perfect the
integration of Mozilla Thunderbird with the SOGo groupware solution.
integration of Mozilla Thunderbird 2, 3.1, 10 ESR, 17 ESR, 24 and 31 with
the SOGo groupware solution.
First of all, the SOGo Connector extension transforms Thunderbird into a
full DAV client for groupware servers such as SOGo, eGroupware or
@@ -116,7 +136,7 @@ extensions, please visit:
http://www.sogo.nu/downloads/frontends.html
Prior to installing the SOGo Integrator extension, you should read the
following chapter - _SOGo Integrator Customization_.
following chapter – _SOGo Integrator Customization_.
SOGo Integrator Customization
-----------------------------
@@ -137,7 +157,7 @@ the same user name used to connect to the first email server configured
in Thunderbird. It is a current limitation but it will fit nearly all
configurations out there.
For testing purpose, it is strongly recommended to create and
For testing purpose, you are strongly recommended to create and
configure an additional user profile for Thunderbird. This is for two
reasons. The first is because of the limitation mentioned above. The
second is because the Integrator will synchronize your personal address
@@ -148,7 +168,7 @@ you may want to make a copy of that address book beforehand.
The second part requires editing one file in the extension file sub tree
to specify where the SOGo server is located. This is done by hand. In an
enterprise environment, this step is only required once per release
since the updates are expected to propagate automatically.
since the updates are expected to propagate automatically. 
Uncompress (using a ZIP or jar tool) the SOGo Integrator XPI and locate
the following file:
@@ -167,7 +187,7 @@ For example, one would replace:
by:
<Seq about="https://sogo.nu" isi:updateURL="https://sogo.acme.com/plugins/updates.php?plugin=%ITEM_ID%&amp;version=%ITEM_VERSION%&amp;platform=%PLATFORM%">
<Seq about="http://inverse.ca/sogo-integrator/extensions" isi:updateURL="https://sogo.acme.com/plugins/updates.php?plugin=%ITEM_ID%&amp;version=%ITEM_VERSION%&amp;platform=%PLATFORM%">
if the SOGo server is accessible from the following URL:
@@ -175,7 +195,7 @@ if the SOGo server is accessible from the following URL:
Note that if you changed the `x-webobjects-server-url` configuration
setting from your HTTP server configuration file for SOGo, the
value *must* match the one you specify in `isi:updateURL` - even the
value *must* match the one you specify in `isi:updateURL` – even the
port number.
Moreover, you *must* change the value of the
@@ -196,7 +216,7 @@ In this section, you will learn how to install and configure the SOGo
Update Server.
The SOGo Update Server can be used to automatically install or uninstall
Mozilla Thunderbird extensions, push user settings and more - all from a
Mozilla Thunderbird extensions, push user settings and more – all from a
central place managed by system administrators.
Installation
@@ -259,7 +279,7 @@ The syntax is:
----
"<extension ID>"
=> array( "application" => "thunderbird",
"version" => "<exact version found in the extension's manifest.json file>",
"version" => "<exact version found in the extension's install.rdf file>",
"filename" => "<exact filename on the filesystem>" )
----
@@ -0,0 +1,758 @@
Native Microsoft Outlook Configuration Guide
============================================
////
This file is part of the SOGo project.
See SOGo Native Microsoft Outlook Configuration-docinfo.xml for
authors, copyright and license information.
////
include::includes/global-attributes.asciidoc[]
About this Guide
----------------
This guide will walk you through the installation and configuration of
the native Microsoft Outlook compatibility layer SOGo offers.
Prior going over this guide, you should have a working SOGo
installation. Please refer to the _SOGo Installation and Configuration
Guide_ for more information on installing and configuring SOGo.
This guide also includes instructions for configuring Microsoft Outlook
with SOGo.
The instructions are based on version {release_version} of SOGo.
The latest version of this guide is available
at http://www.sogo.nu/downloads/documentation.html.
Introduction
------------
SOGo is a free and modern scalable groupware server. It offers shared
calendars, address books, and emails through your favourite Web browser
and by using a native client such as Mozilla Thunderbird and Lightning.
SOGo is standard-compliant. It supports CalDAV, CardDAV, GroupDAV, iMIP
and iTIP and reuses existing IMAP, SMTP and database servers — making
the solution easy to deploy and interoperable with many applications.
SOGo features:
* Scalable architecture suitable for deployments from dozen to many
thousand users
* Rich Web-based interface that shares the look and feel, the features
and the data of Mozilla Thunderbird and Lightning
* Improved integration with Mozilla Thunderbird and Lightning by using
the SOGo Connector and the SOGo Integrator
* Native compatibility for Microsoft Outlook 2003, 2007, 2010, and 2013
* Two-way synchronization support with any Microsoft ActiveSync-capable
device, and Outlook 2013
SOGo is developed by a community of developers located mainly in North
America and Europe. More information can be found
on http://www.sogo.nu/.
Architecture
------------
The following diagram demonstrates the architecture of the native
Outlook compatibility layer of SOGo.
image::images/openchange.png[]
With Samba 4 and OpenChange, Microsoft Outlook clients can communicate
natively with SOGo using the Microsoft Exchange protocol, without
requiring costly and hard-to-maintain third-party MAPI connectors for
Microsoft Outlook.
Requirements
------------
Organizations generally have solutions to authenticate users such as
LDAP servers or Microsoft Active Directory servers.
The solution being used will influence how users are provisioned in
Samba 4, a key component for native Outlook compatibility in SOGo.
LDAP Server
~~~~~~~~~~~
If your organization uses a LDAP server such OpenLDAP, Novell
eDirectory, Apache Directory or any other solution, you must use
Samba 4's internal directory server and synchronize the data between
both.
Synchronization scripts are not provided and unless you have clear-text
passwords of your existing users, they will have to be changed during
your initial synchronization so that your LDAP's server passwords are
identical to the ones from Samba 4.
Any modifications to your existing LDAP server (password change, user
addition or deletion, etc.) will have to be replicated to Samba 4's
internal directory server.
Note that if you install Samba 4 on a server that is already running a
LDAP service, you will have to change to TCP port on which your LDAP
server listens to. Samba 4 will use the TCP port 389 and it can't be
changed.
For example, with OpenLDAP, you can use the `-h` parameter for `slapd`
to make it listen on an other TCP port.
Microsoft Active Directory
~~~~~~~~~~~~~~~~~~~~~~~~~~
If your organization uses Microsoft Active Directory, Samba 4 will need
to be joined to your Active Directory domain, as a DC.
Samba 4 will be able to reuse all the information contained in Microsoft
Active Directory and no synchronization process needs to be put in place
as information will get replicated to Samba 4 automatically.
For more information on joining Samba 4 to an existing Microsoft Active
Directory domain, please refer to the Samba 4 documentation available at
the following URL:
http://wiki.samba.org/index.php/Samba4
More specifically, have a look at the `samba-tool domain join` command.
Note that joining Samba 4 to your Active Directory domain as a member
will currently not work. An authentication bug is present in Samba 4
which then prevents all Outlook users to successfully authenticate
through Samba 4. This issue has been reported to the Samba team and is
being worked on.
Other or No Solution
~~~~~~~~~~~~~~~~~~~~
If your organization neither uses a LDAP server or Microsoft Active
Directory, you can start using Samba 4 as your directory server.
Samba 4's directory can be queried over LDAP just like Microsoft Active
Directory and can also serve as a domain controller for Windows-based
environments.
For example, SOGo can very well use Samba 4's built-in directory server
to authenticate users. A SOGoUserSources entry to achieve this wold look
like this:
----
su – sogo
defaults write sogod SOGoUserSources '(
{
CNFieldName = displayName;
IDFieldName = cn;
UIDFieldName = sAMAccountName;
baseDN = "cn=Users,dc=example,dc=com";
bindDN = "cn=Administrator,cn=Users,dc=example,dc=com";
bindFields = (
sAMAccountName
);
bindPassword = "%1OpenChange";
canAuthenticate = YES;
displayName = "Shared Addresses";
hostname = "127.0.0.1";
id = samba;
isAddressBook = YES;
port = 389;
}
)'
----
Please refer to the _SOGo Installation and Configuration Guide_ for more
information regarding `SOGoUserSources`.
IMAP Server and Trust
~~~~~~~~~~~~~~~~~~~~~
An IMAP server supporting the ACL, UIDPLUS and QRESYNC 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. The follow
configuration example makes Dovecot proxy all IMAP request to an
existing server:
----
auth_mechanisms = plain login
imapc_host = inverse.ca
imapc_port = 993
imapc_ssl = imaps
imapc_ssl_verify = no
mail_gid = imapproxy
mail_home = /home/imapproxy/%u
mail_location = imapc:~/imapc
mail_uid = imapproxy
passdb {
args = host=inverse.ca ssl=imaps port=993 ssl_ca_dir=/etc/pki/tls/certs
default_fields = userdb_imapc_user=%u userdb_imapc_password=%w
driver = imap
}
protocols = imap
ssl = no
userdb {
driver = prefetch
}
----
SOGo would then be configured to use Dovecot's proxy as the IMAP server.
Moreover, the authentication mode in use by Windows with Samba and
Exchange servers prevent the backend from knowing the real password
being used by the user. This implies that the IMAP server must accept
any passwords from the host on which Samba is running.
To accomplish this with Cyrus IMAP Server, set `sasl_pwcheck_method`
to `alwaystrue` in `/etc/imapd.conf`. You should restrain this to
an `imapd` instance dedicated to SOGo.
For Dovecot, use an authentication source similar to:
----
passdb {
driver = static
args = nopassword=y allow_nets=127.0.0.1/32
}
----
You should also make sure that you restrain this only to the SOGo
processes.
For any other IMAP server, refer to the product's documentation. If such
capability is not offered, you can alternatively define the cleartext
password for each user. Please refer to the _Adding Users_ section from
this document.
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_nightly.html.
In order to satisfy certain dependencies, you should also add the EPEL
source corresponding to your distribution and architecture. More
information on this is available here:
http://fedoraproject.org/wiki/EPEL – or more specifically,
http://fedoraproject.org/wiki/EPEL/FAQ#How_can_I_install_the_packages_from_the_EPEL_software_repository.3F.
Once ready, install the OpenChange packages on top of an existing SOGo
installation:
----
yum clean all && yum makecache
yum install samba \
openchange \
sogo-openchange-backend \
openchange-ocsmanager \
openchange-rpcproxy \
mysql-server \
MySQL-python
----
Once the packages are installed, refer to the _Configuration_ chapter
from this guide.
[NOTE]
Samba4/OpenChange are not available for now on CentOS 5 i386/x86_64,
CentOS 6 i386 and CentOS 7.
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.
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 -t wheezy-backports install samba samba-dev
----
Once completed, install the packages related to OpenChange and the SOGo
provider:
----
apt-get install openchangeserver \
sogo-openchange \
openchangeproxy \
python-ocsmanager \
mysql-server \
python-mysqldb
----
Once the packages are installed, refer to the _Configuration_ chapter
from this guide.
[NOTE]
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
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
apt sources.
Then install Samba 4 on top of an existing SOGo
installation:
----
apt-get update
apt-get install samba samba-dev
----
Once completed, install the packages related to OpenChange and the SOGo
provider:
----
apt-get install openchangeserver \
sogo-openchange \
openchangeproxy \
python-ocsmanager \
mysql-server \
python-mysqldb
----
Once the packages are installed, refer to the _Configuration_ chapter
from this guide.
Configuration
-------------
In this section, you'll learn how to configure the native Microsoft
Outlook compatibility layer that SOGo offers.
SOGo Configuration
~~~~~~~~~~~~~~~~~~
First thing to do is to configure SOGo to use your current services,
which are your IMAP, SMTP and SQL database servers. The configuration
instructions for this are available in the SOGo Installation and
Configuration Guide available from http://www.sogo.nu/.
Please refer to that documentation before continuing with the
instructions included in this guide.
Samba 4 Configuration
~~~~~~~~~~~~~~~~~~~~~
Run the following commands as root: 
----
samba-tool domain provision --realm=example.com \
--domain=OPENCHANGE \
--adminpass='%1OpenChange' \
--server-role='domain controller'
samba-tool user setexpiry administrator --noexpiry
----
You might consider changing the realm and domain used, to suit your
enviroment.
You might also have to
remove `/etc/samba/smb.conf` prior running this command.
Add the following parameters to the `[global]` section of the
`/etc/samba/smb.conf` configuration file:
----
### Configuration required by OpenChange server ###
dcerpc endpoint servers = epmapper, mapiproxy, dnsserver
dcerpc_mapiproxy:server = true
dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
### Configuration required by OpenChange server ###
----
Your Samba 4 configuration file should look like this:
----
# Global parameters
[global]
server role = active directory domain controller
workgroup = EXAMPLE
realm = example.com
netbios name = sogo
passdb backend = samba4
### Configuration required by OpenChange server ###
dcerpc endpoint servers = +epmapper, +mapiproxy
dcerpc_mapiproxy:server = true
dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
### Configuration required by OpenChange server ###
[netlogon]
path = /var/lib/samba/sysvol/example.com/scripts
read only = No
[sysvol]
path = /var/lib/samba/sysvol
read only = No
----
OpenChange Configuration
~~~~~~~~~~~~~~~~~~~~~~~~
OpenChange 2.2 stores its metadata in MySQL so you need to have it installed.
First, create the OpenChange MySQL user:
----
$ mysql -u root -p
mysql> CREATE USER 'openchange-user'@'localhost' IDENTIFIED BY 'openchange$123';
mysql> GRANT ALL PRIVILEGES ON `openchange`.* TO 'openchange-user'@'localhost' WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;
----
The Samba AD schema needs to be filled with additional object
definitions by running the following commands: 
----
openchange_provision --standalone
NOTE: This operation can take several minutes
[+] Step 1: Register Exchange OIDs
[+] Step 2: Add Exchange attributes to Samba schema
[+] Step 3: Add Exchange auxiliary classes to Samba schema
[+] Step 4: Add Exchange objectCategory to Samba schema
[+] Step 5: Add Exchange containers to Samba schema
[+] Step 6: Add Exchange *sub* containers to Samba schema
[+] Step 7: Add Exchange CfgProtocol subcontainers to Samba schema
[+] Step 8: Add Exchange mailGateway subcontainers to Samba schema
[+] Step 9: Add Exchange classes to Samba schema
[+] Step 10: Add possSuperior attributes to Exchange classes
[+] Step 11: Extend existing Samba classes and attributes
[+] Step 12: Generic Exchange configuration objects
[+] Step 13: Finalize generic Exchange configuration objects
[SUCCESS] Done!
[+] Step 1: Exchange Samba registration
[SUCCESS] Done!
[+] Step 1: Register Exchange Samba as the main server
[SUCCESS] Done!
----
Create the OpenChange database: 
----
openchange_provision --openchangedb --openchangedb-uri 'mysql://openchange-user:openchange$123@localhost/openchange'
Setting up openchange db
[+] Public Folders
===================
* Public Folder Root : 0x0100000000000001 (72057594037927937)
* IPM_SUBTREE : 0x0200000000000001 (144115188075855873)
* NON_IPM_SUBTREE : 0x0300000000000001 (216172782113783809)
* EFORMS REGISTRY : 0x0400000000000001 (288230376151711745)
* OFFLINE ADDRESS BOOK : 0x0500000000000001 (360287970189639681)
* /o=First Organization/cn=addrlists/cn=oabs/cn=Default Offline Address Book: 0x0600000000000001 (432345564227567617)
* SCHEDULE+ FREE BUSY : 0x0700000000000001 (504403158265495553)
* EX:/o=first organization/ou=first administrative group: 0x0800000000000001 (576460752303423489)
* Events Root : 0x0900000000000001 (648518346341351425)
----
Finally, modify `/etc/samba/smb.conf` to specify OpenChange connection information
for its indexing database. Add the following at the end of the `[global]` section:
----
mapistore:namedproperties = mysql
namedproperties:mysql_user = openchange-user
namedproperties:mysql_pass = openchange$123
namedproperties:mysql_host = localhost
namedproperties:mysql_db = openchange
mapistore:indexing_backend = mysql://openchange-user:openchange$123@localhost/openchange
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:
/etc/init.d/samba start
On upstart-based distributions, use:
start samba-ad-dc
You can also launch the OpenChange web services:
/etc/init.d/openchange-ocsmanager start
Apache Configuration for Web Services
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The OpenChange web services consist of two components:
1. *OCS Manager* which is used for autodiscovery and freebusy lookups on
Outlook 2007 and 2010. This service runs in its own application server
which listens on `127.0.0.1:5000` by default. Apache needs to be
configured to forward certain requests to it to make it accessible from
the outside.
Note that this service *MUST* be accessible over*HTTPS*, otherwise Outlook
won't use it.
2. *RPC Proxy* which is used for RPC over HTTP ("Outlook Anywhere").
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/`.
The configuration requires three Apache modules:  _mod_proxy_,
_mod_proxy_http_ and _mod_wsgi_. These are usually already installed but
might need to be activated on Debian-based installations:
a2enmod proxy proxy_http wsgi
On RHEL-based distributions, make sure the `LoadModule` directive is
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
which the HTTP body hasn't arrived in 10 seconds.
While this is arguably good practice with regular HTTP, it will disrupt
the RPC over HTTP protocol implemented by RPC Proxy: Outlook will
continuously disconnect and reconnect leading to suboptimal performance.
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:
chkconfig httpd on && /etc/init.d/httpd restart
On Debian-based distributions, do:
update-rc.d apache2 defaults && /etc/init.d/apache2 restart
[NOTE]
Debian-based distributions are not supported anymore for
OCSManager/rpcproxy. Support will soon resume.
Name Service Configuration for Web Services
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The autodiscovery service must be made accessible in order to advertise
the web services provided by OpenChange. This can be done in two ways.
1. The first is to associate the FQDN `autodiscover.example.com.` with
the machine that hosts Samba 4 / OpenChange, by adding a `CNAME` entry
in your DNS configuration. Note that, instead or changing your DNS
server configuration, you can simply add a similar entry to the _hosts_
file of the Windows machine from where you'll run Outlook, which is
handy for testing purposes.
2. The second option is to add a `SRV` entry to your DNS configuration
where the `_service` value would be `Autodiscover` and the `_protocol`
would be `_tcp`.
For example:
_autodiscover._tcp.example.com. IN SRV 0 0 443 sogo.example.com.
Again, the autodiscovery service must be accessible over HTTPS.
Adding Users
------------
Users that wish to connect natively to SOGo must be provisioned in
Samba 4 and in OpenChange – even if they already exist in your current
LDAP or Microsoft Active Directory server.
To add a user, execute the following commands: 
----
# add user to samba
samba-tool domain passwordsettings set --complexity=off
samba-tool domain passwordsettings set --min-pwd-length=1
samba-tool user add <username>
samba-tool user setexpiry <username> --noexpiry
# create user in openchange
openchange_newuser --create <username>
----
If you don't have a trust between your IMAP server and SOGo, you must at
this point set the cleartext password of the newly created user in
`/var/lib/samba/private/mapistore/<username/password`.
This per-user file contains the cleartext password of the user as a
UTF-8 string, on a single line. This password will be used to
authenticate SOGo/OpenChange storage provider to your IMAP server.
Microsoft Outlook Configuration
-------------------------------
To connect Microsoft Outlook, you can either use the IP address of the
server or its DNS name. If you prefer using the DNS name, add an entry
like the following to the `c:\windows\system32\drivers\etc\hosts` file
in order to associate the IP address with the right DNS names:
192.168.1.1 sogo.example.com autodiscover.example.com
Next, you must configure Microsoft Outlook.
* Open the Control Panel => Mail => Email Accounts.
* Select _Add a new e-mail account_
* Choose _Microsoft Exchange Server_
* Fill the required information. Enter the DNS name or the IP address of
your SOGo server in the _Microsoft Exchange Server_ field
* Leave the _Use Cached Exchange Mode_ checkbox enabled
* Enter your username in the _User Name_ field
* Click on _More Settings_ and ignore the warning, if any, about
Exchange being offline by clicking on Cancel
* From the Security tab, enable Always prompt for user name and password
* From the _Connection_ tab, enable _"Outlook Anywhere"_ if you plan to
use Outlook outside of your LAN. Moreover, click on the _Exchange Proxy
Settings..._ button to enable it for slow and fast networks. Specify
also the host, which should be the same value you specified in the
Microsoft Exchange Server field.
* Finally, click on Check Name and confirm your username and password
Start Microsoft Outlook and enter your username and password. It will
start to synchronize your mailbox. This could take a long time if you
have many emails, events, tasks and contacts. Once this step is
completed, check the autodiscovery service with Outlook 2007 or 2010 by
simultaneously holding the CTRL key on your keyboard and right-clicking
on the Outlook icon in the notification toolbar. A special entry named
"Test E-mail AutoConfiguration..." will appear and will enable you to
check the service.
Known Issues or Limitations
---------------------------
* Make sure you periodically backup all your data regarding SOGo.
* Make sure you have no firewalls activated between your Microsoft
Outlook clients and the SOGo server with Native Outlook Compatibility
module. If you do, use "Outlook Anywhere" to connect Outlook to
SOGo/OpenChange.
Current Limitations
~~~~~~~~~~~~~~~~~~~
The current version of the Native Microsoft Outlook compatibility layer
has some limitations.
Those limitations will be overcome in the upcoming releases. If you are
interested in having those limitations fixed more rapidly, please
contact Inverse by sending an email to support@inverse.ca.
General
^^^^^^^
* If you can't see any email's content with Microsoft Outlook 2007,
install the latest Service Pack available from Microsoft's website for
this specific version. Microsoft Outlook 2007 (12.0.6423.100) SP2 MSO
(12.0.6425.1000) is known to work.
* When you create a new Microsoft Outlook profile, not all folders might
be synchronized during the first start. Simply select the appropriate
folder and click "Send and Receive". Synchronizing a folder may take
some time. For example, a folder with 1000 email messages might take
around 5 minutes based on the underlying hardware.
* Errors when synchronizing the "Offline Address Book" are normal and
can be ignored for now. This feature is currently not supported.
* If you face strange issues from Microsoft Outlook, you might want to
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 SOGo. The script
can be found in `/usr/share/doc/sogo/` (`/usr/share/sogo-VERSION/` on
RHEL).
To reset a user, run the script as root:
`python openchange_user_cleanup username`. See the usage output for additional options.
* 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
server), below the Personal Calendar or Personal Address Book will work
in Outlook cached mode but the server-side operation will fail and these
folders will never be created. Potentially data loss can occur if the
Outlook profile is destroyed. If you wan to create additional top-level
mail folders, calendars or address books, open Outlook's folder list,
select the top level node (usually, "email@example.com") and choose "New
Folder..." from the contextual menu. Choose the relevant item types.
Mail
^^^^
* Sharing mail folders is not supported.
* To avoid possibly lossy conversion from RTF to HTML, Outlook should be
configured to send all mails as HTML (or plaintext) instead of _Outlook
Rich Text Format_.
Calendar
^^^^^^^^
* Labels will not work.
* It might be impossible to view event details from a shared calendar.
This issue is being worked on.
Tasks
^^^^^
* Tasks with start/due dates created from Outlook might not appear
correctly in SOGo due to a timezone issue.
* Reminders are not yet supported.
* Assigning tasks will not work.
Contacts
^^^^^^^^
* Categories will not work.
* Distribution lists will not work.
* Under Microsoft Outlook 2010, the special folder "Suggested Contacts"
will not work.
* The "Offline Address Book" will not work. This feature is not yet
supported.
Notes
^^^^^
* Notes are not synchronized in any ways with SOGo. The current version
of SOGo lacks support for notes.
If you notice anything else, please send contact Inverse by sending an
email to support@inverse.ca.
include::includes/additional-info.asciidoc[]
include::includes/commercial-support.asciidoc[]
@@ -1,495 +0,0 @@
Microsoft Outlook CalDAVSynchronizer Configuration Guide
========================================================
////
This file is part of the SOGo project.
See includes/global-attributes.asciidoc
for authors, copyright and license information.
////
include::includes/global-attributes.asciidoc[]
About this Guide
----------------
This guide will walk you through the installation and configuration of Microsoft Outlook for a better integration with SOGo through the use of the CalDavSynchronizer addon.
Prior going over this guide, you should have a working SOGo
installation. Please refer to the _SOGo Installation and Configuration
Guide_ for more information on installing and configuring SOGo.
The instructions are based on version {release_version} of SOGo.
The latest version of this guide is available
at https://www.sogo.nu/support.html#/documentation.
Introduction
------------
Outlook CalDav Synchronizer is an open source addon for Microsoft Windows Outlook. It synchronizes events, tasks and contacts between Microsoft Outlook and CalDAV or CardDAV servers. Supported Outlook versions are Outlook 2007 to Outlook 2016.
Together with other open source solutions like SOGo, a full open source Microsoft Exchange server replacement for desktop users is finally possible and enterprise ready.
Outlook CalDav Synchronizer is Free and Open-Source Software (FOSS) , licensed under AGPL3 and developed by
* https://sourceforge.net/u/nertsch/profile/[Gerhard Zehetbauer]
* https://sourceforge.net/u/nimm/profile/[Alexander Nimmervoll]
Project Links
~~~~~~~~~~~~~
The project source and binaries for installation are hosted on GitHub and SourceForge or can be downloaded from https://caldavsynchronizer.org[caldavsynchronizer.org]
* https://github.com/aluxnimm/outlookcaldavsynchronizer
* https://sourceforge.net/projects/outlookcaldavsynchronizer/
Social Media
~~~~~~~~~~~~
https://www.facebook.com/caldavsynchronizer/[CalDav Synchronizer on Facebook]
Enterprise Support
~~~~~~~~~~~~~~~~~~
Alinto (https://alinto.com/[http://alinto.com]) offers professional services around SOGo to help organizations deploy the solution and
migrate from their legacy systems.
For enterprise support on the integration between SOGo and Microsoft Outlook using the Outlook CalDav Synchronizer, please visit https://caldavsynchronizer.org/enterprise
Features
--------
The most important features are
* Open Source, the only free Outlook CalDAV and CardDAV addon
* two-way-sync
* support for CalDAV calendars and tasks, CardDAV contacts
* support for Google native Contacts and Tasks API
* full support for timezones and recurring events with exceptions
* SSL/TLS support, support for self-signed certificates
* proxy support
* Autodiscovery of calendars and addressbooks
* configurable sync timerange filter
* time-triggered-sync and sync changes from Outlook immediately
* Category Filtering (sync CalDAV calendar/tasks to Outlook categories)
* map CalDAV server colors to Outlook category colors
* Use server settings from Outlook IMAP/POP3 account profile
* Mapping of Distribution Lists to SOGo VLIST contact groups
* Configurable mapping of Outlook custom properties
Installation
------------
Download and extract the `OutlookCalDavSynchronizer-<Version>.zip` into any directory and start setup.exe. You can change the default install path, but you need to use a directory on the `C:\` drive. Follow the instructions and restart Outlook after the installation is finished.
image::images/installer1.png[scaledwidth="100%",alt="Installer Step 1"]
image::images/installer2.png[scaledwidth="100%",alt="Installer Step 2"]
Next, you will see a ribbon CalDav Synchronizer in Outlook and can add synchronization profiles for you SOGo calendars, addressbooks and tasks.
image::images/outlook_ribbon.png[scaledwidth="100%",alt="Outlook Ribbon"]
In the Synchronization profiles dialog, press *Add new profile* if you just need to synchronize one resource or *Add multiple profiles* if you need to synchronize multiple calendars, addressbooks or task folders.
image::images/add_multiple.png[scaledwidth="75%",alt="Add multiple profiles"]
Next, select the SOGo profile type
image::images/select_profiletype.png[scaledwidth="100%",alt="Select Profile type"]
In the multiple profile setup dialog you can configure the details of the sync profiles.
image::images/configure_multiple.png[scaledwidth="100%",alt="Multiple Profile Configuration"]
First, you should change the profile name and configure the server settings, the DAV URL is prefilled with the default SOGo DAV path and you should only change the hostname of your SOGo server, enter Username and Password. If you also have configured an IMAP account and your domain supports autodiscovery using DNS SRV records you can also try to fetch the server settings from your existing mail account in Outlook by pressing *Get IMAP/POP3 account settings*. If successful, username and password will be used from the existing mail account and the DAV URL will be discovered.
If all server settings are configured press *Discover resources and assign to Outlook folders* to start the autodiscovery of all server resources.
You can assign Outlook folders to found calendar, addressbook and task resources in the three tab views.
image::images/select_calendar.png[scaledwidth="100%",alt="Add calendar resources"]
image::images/select_addressbook.png[scaledwidth="100%",alt="Add addressbook resources"]
image::images/select_task.png[scaledwidth="100%",alt="Add task resources"]
To assign a folder click on the "..." button for the corresponding resource and either choose an existing Outlook folder or create a new one in the folder dialog.
image::images/select_folder.png[scaledwidth="60%",alt="Select Outlook folder"]
image::images/new_folder.png[scaledwidth="60%",alt="Add new Outlook folder"]
If you chose *Add new profile* for only one resource you can also choose the Outlook folder and dependent on the folder type you will create a calendar, addressbook or task profile.
image::images/profile_config.png[scaledwidth="100%",alt="Single Profile Configuration"]
If you know the correct calendar CalDAV URL, you can also enter that directly into the DAV Url textbox or paste it from the SOGo Web Frontend, when selecting Link in the calendar properties. For the personal calendar it looks like
https://server.example/remote.php/dav/calendars/caldav/personal/
Furthermore, you can configure sync settings and intervals or keep the default settings which are automatic Two-Way-Sync every 30 minutes for all events from 60 days in the past to 365 days in the future.
image::images/profile_advanced.png[scaledwidth="100%",alt="Advanced Settings"]
For addressbooks, the profile setup is similar, just choose an Outlook contacts folder for synchronization.
If needed, you can configure network and proxy options or special mapping configuration parameters in the corresponding option pages.
image::images/profile_network.png[scaledwidth="100%",alt="Network settings"]
image::images/profile_advanced_event_mapping.png[scaledwidth="100%",alt="Event mapping configuration"]
image::images/profile_advanced_contact_mapping.png[scaledwidth="100%",alt="Contact mapping configuration"]
image::images/profile_advanced_task_mapping.png[scaledwidth="100%",alt="Task mapping configuration"]
image::images/profile_advanced_custom_mapping.png[scaledwidth="100%",alt="Custom mapping configuration"]
See *Advanced settings* below for a detailed description of all available options.
After the configuration of the sync profile is finished you can start the synchronization with pressing *Synchronize now* in the CalDav Synchronizer ribbon and your Outlook resources will be in sync with your SOGo resources.
You can check the status of the last sync runs with the *Status* button in the ribbon.
image::images/status_report.png[scaledwidth="50%",alt="Status report"]
Should there be any errors or warnings during synchronization, you can check the *Reports* in the ribbon.
image::images/sync_report.png[scaledwidth="100%",alt="Sync report"]
Configuration Options
---------------------
Synchronization Settings
~~~~~~~~~~~~~~~~~~~~~~~~
* *Outlook → Server (Replicate):* syncronize everything from Outlook to the server (one way)
* *Outlook ← Server (Replicate):* synchronize everything from the server to Outlook (one way)
* *Outlook → Server (Merge):* synchronize everything from Outlook to the server but don’t change events created on the server
* *Outlook ← Server (Merge):* synchronize everything from the server to Outlook but don’t change events created in Outlook
* *Outlook ←→ Server (Two-Way):* Two-Way synchronization between Outlook and the server with one of the following conflict resolution
* *Conflict resolution*
(only used in Two-Way synchronization mode and only available in *advanced settings*)
** *Outlook Wins:* If an event is modified in Outlook and in the server since last snyc, use the Outlook version. If an event is modified in Outlook and deleted in the server since last snyc, also use the Outlook version. If an event is deleted in Outlook and modified in the server, also delete it in the server.
** *Server Wins:* If an event is modified in Outlook and in the server since last snyc, use the server version. If an event is modified in Outlook and deleted in the server since last snyc, also delete it in Outlook. If an event is deleted in Outlook and modified in the server, recreate it in Outlook.
** *Automatic:* If event is modified in Outlook and in the server since last snyc, use the last recent modified version. If an event is modified in Outlook and deleted in the server since last snyc, delete it also in Outlook. If an event is deleted in Outlook and modified in the server, also delete it in the server.
* *Synchronization interval (minutes):* Choose the interval for synchronization in minutes, if 'Manual only' is choosen, there is no automatic sync but you can use the 'Synchronize now' menu item.
* *Perform synchronization in chunks* perform CalDAV/CardDAV sync in chunks with configurable chunk size to avoid OutOfMemoryEceptions, enabled by default because of lower memory consumption for huge resources. *(only in advanced settings)*
* *Use time range filter* *(only in advanced settings)*
For performance reasons it is useful to sync only a given timespan of a big calendar, especially past events are normally not necessary to sync after a given timespan. But be aware that Outlook and Google and some other CalDAV servers calculate the intersection with the time-range differently for recurring events which can cause doubled or deleted events, so it is recommended to select a time-range which is larger than the largest interval of your recurring events (e.g. 1 year for birthdays).
Advanced Settings
~~~~~~~~~~~~~~~~~
When *Show advanced settings* is enabled, you can expand the tree view of the profile to configure network and proxy options and mapping configuration options.
Network and Proxy Options
^^^^^^^^^^^^^^^^^^^^^^^^^
Here you can configure advanced network options and proxy settings.
* *Close connection after each request* Don’t use KeepAlive, only useful for servers which don’t support it.
* *Use Preemptive Authentication* Send Authentication header with each request to avoid 401 responses and resending the request, disable only if the server has problems with preemptive authentication.
* *Force basic authentication* Set basic authentication headers to avoid problems with negotiation or digest authentication with servers like Apple OS X / macOS. This is only recommended if you use a secure HTTPS connection, otherwise passwords are sent in cleartext.
* *Use System Default Proxy* Use proxy settings from Internet Explorer or config file, uses default credentials if available for NTLM authentication.
* *Use manual proxy configuration* Specify proxy URL as `http://<your-proxy-domain>:<your-proxy-port>` and optional Username and Password for Basic Authentication.
Mapping Configuration
^^^^^^^^^^^^^^^^^^^^^
Here you can configure what properties should be synced.
Event Mapping Configuration
+++++++++++++++++++++++++++
For appointments you can choose if you want to map reminders (just upcoming, all or none) and the description body.
* *Export html description X-ALT-DESC converted from RTF Body* If enabled, convert formatted RTF Body of Outlook appointment to html and export it as X-ALT-DESC property. The RTF to html conversion is experimental, inline images and some formatting properties can’t be converted! Be aware that some servers like Google Calendar drop this attribute!
* *Set RTF Body from X-ALT-DESC html description* If enabled, convert X-ALT-DESC description html property to RTF and set Outlook appointment RTF Body. The html to RTF conversion is experimental, not all html formatting options can be converted! This overwrites also the plaintext Body!
* *Timezone settings* See section Timezone mapping below.
*Use GlobalAppointmentID for UID attribute:* Use Outlook GlobalAppointmendID instead of random Guid for UID attribute in new CalDAV events. This can avoid duplicate events from invitations.
* In *Privacy settings* you can configure if you want to map Outlook private appointments to CLASS:CONFIDENTIAL and vice versa. This could be useful for Owncloud for example, if you share your calendar with others and they should see start/end dates of your private appointments. You can also map all CLASS:PUBLIC events to Outlook private appointments.
* In *Scheduling settings* you can configure if you want to map attendees and organizer and if notifications should be sent by the server.
* Use *Don’t send appointment notifications* for SOGo servers and *SCHEDULE-AGENT=CLIENT* for other servers if you want to send invitations from Outlook and avoid that the server sends invitations too, but be aware that not all servers (e.g. Google) support the SCHEDULE-AGENT=CLIENT setting.
* In *Outlook settings* you can also define a filter category so that multiple CalDAV-Calendars can be synchronized into one Outlook calendar via the defined category (see Category Filter and Color below).
* *Cleanup duplicate events after each sync run:* removes duplicate Outlook appointments based on start,end and subject of the events after each sync run, be aware of possible performance penalties with this option enabled.
Contact Mapping Configuration
+++++++++++++++++++++++++++++
* For contacts you can configure if birthdays should be mapped or not. If birthdays are mapped, Outlook also creates an recurring appointment for every contact with a defined birthday.
* You can also configure if contact photos should be mapped or not. Contact photo mapping from Outlook to the server doesn’t work in Outlook 2007. You can also add an option to not overwrite the contact photo in Outlook when it changes on the server, which could happen due to other mobile clients reducing the resolution for example.
* Don’t overwrite FileAs in Outlook uses the Outlook settings for FileAs and doesn’t overwrite the contact FileAs with the FN from the server.
* Fix imported phone number format adds round brackets to the area code of phone numbers, so that Outlook can show correct phone number details with country and area code, e.g. +1 23 45678 is mapped to +1 (23) 45678.
* Map OutlookEmailAddress1 to WORK instead of HOME, enable when you need to change the order of email address mapping.
* Write IM addresses as IMPP attributes. If enabled IMPP is used instead of X-AIM,X-ICQ,X-JABBER etc. for writing Instant messenger addresses in vCards. (SOGo is only using X-AIM atm.)
* Default IM protocol. Choose the default IM service type protocol which will be added to the chat address field from Outlook when writing vCards, defaults to AIM.
* Map Distribution Lists enables the sync of contact groups / Distribution Lists, right now the DAV contact group format SOGo VLIST or vCards with KIND:group are available, see *Distribution Lists* below.
Task Mapping Configuration
++++++++++++++++++++++++++
* For tasks (not for Google task profiles) you can configure if you want to map reminders (just upcoming, all or none), the priority of the task, the description body and if recurring tasks should be synchronized.
* You can also define if task start and due dates should be mapped as floating without timezone to avoid issues with tasks across different timezones.
* Similar to calendars you can also define a filter category so that multiple CalDAV Tasklists can be synchronized into one Outlook task folder via the defined category.
Timezone Settings
^^^^^^^^^^^^^^^^^
Outlook and Windows use different timezone definitions than most CalDAV servers and other clients. When adding new events on the server you have different options how the timezone of the newly created VEVENT is generated. The default setting uses the default Windows timezone from Outlook (e.g. W. Europe Standard Time) or the selected timezones for the start and end of the appointment. Since some servers have problems with that timezone definitions you can change that behaviour in the event mapping configuration with the following options:
* *Create events on server in UTC* Use UTC instead of Outlook Appointment Timezone for creating events on CalDAV server. Not recommended for general use, because recurrence exceptions over DST changes can’t be mapped and Appointments with different start and end timezones can’t be represented.
* *Create events on server in downloaded IANA Timezones* Use IANA instead of Windows Timezones for creating events on CalDAV server. Needed for servers which do not accept non standard Windows Timezones like GMX for example. Timezone definitions will be downloaded from http://tzurl.org.
* *Use IANA Timezone* Use this IANA timezone for default Outlook/Windows timezone. Manually selected different timezones in Outlook appointments will be mapped to first corresponding IANA timezone.
* *Include full IANA zone with historical data* Use full IANA timezone definition with historical data. Needs more bandwith and can be incompatible when manually importing in Outlook.
Custom Properties Mapping
^^^^^^^^^^^^^^^^^^^^^^^^^
When you expand the tree view of the profile for events and tasks, you can configure the mapping of custom properties.
* *Map all Outlook custom properties to X-CALDAVSYNCHRONIZER attributes* If enabled, all Outlook custom text properties of the appointment/task are mapped to DAV attributes with the prefix X-CALDAVSYNCHRONIZER- and vice versa.
* You can also define manual mapping pairs of Outlook custom attributes and DAV X-Attributes. This will overrule the general mapping of all Outlook custom properties if both is activated. Outlook properties that don’t exist, will be created. DAV properties MUST start with X-. Only Outlook custom properties of type Text can be mapped.
Managing Meetings and Invites
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Outlook can only track meeting responses and invites in the main calender folder. If you schedule meetings from Outlook which are synced with the CalDAV server you have two possibilities to avoid double invitation mails for all attendees. First, you can enable the option *Don’t send appointment notifications (enabled by default for SOGo profiles)* or *SCHEDULE-AGENT=CLIENT* (for other servers) and let only Outlook send the meeting invites, if the server supports this option. Or you can disable this option and let the server schedule the meetings after syncing the meeting. Then you need to disable the invitation mails sent from Outlook. This is possible by unchecking the checkbox left to the attendee name in the meeting planning dialog. When syncing meetings created in Outlook to the server, the option *Use GlobalAppointmentID for UID attribute* is recommended. This can avoid duplicate events from invitations.
The response status of all attendees can be synced from Outlook to the server but only the status of the own Outlook identity (if included in the attendees) can be synced from the server to Outlook due to limitations of the Outlook Object Model.
When receiving invites from the CalDAV server and via Email in your INBOX, Outlook will automatically create a tentative meeting in the main calendar folder
To avoid double meetings the option *Cleanup duplicate events after each sync run* in event mapping configuration is recommended.
Free/busy Lookups
^^^^^^^^^^^^^^^^^
You can configure free/busy lookups globally in the Outlook options.
Select Options/Calendar and there free/busy information and use a free/busy URL of your server with placeholder like %Name%, e.g. http://myserver/freebusy.php/%Name%
For SOGo the URL looks like: http://<hostname>/SOGo/dav/public/%NAME%/freebusy.ifb
And `SOGoEnablePublicAccess` must be set to `YES`
Then every attendee in the Outlook planning view gets resolved with that URL for a free/busy lookup against your server.
Scheduling Settings and Resources
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If your server supports resources (for SOGo see http://wiki.sogo.nu/ResourceConfiguration disable *set SCHEDULE-AGENT=CLIENT* in Mapping Configuration, so that the server can handle the resource invitation mails, add the resource email adress as attendee in the Outlook appointment and choose type ressource (house icon) for it.
Category Filter and Color
~~~~~~~~~~~~~~~~~~~~~~~~~
If you want to sync multiple CalDAV calendars or task lists into one Outlook folder you can configure an Outlook category for filtering in the *Mapping Configuration*. You can choose a category from the dropdown list of all available Outlook categories or enter a new category name.
For all events/tasks from the server the defined category is added in Outlook, when syncing back from Outlook to the server only appointments/tasks with that category are considered but the filter category is removed. The category name must not contain any commas or semicolons!
With the checkbox *Sync also Appointments without any category* also all appointments/tasks without a category are synced to the server.
With the checkbox below you can alternatively negate the filter and sync all appointments/tasks except this category.
For calendars it is also possible to choose the color of the category or to fetch the calendar color from the server and map it to the nearest supported Outlook category color with the button *Fetch Color*. With *Set DAV Color* it is also possible to sync the choosen category color back to set the server calendar color accordingly. With *Category Shortcut Key* you can define the shortcut key of the selected category for easier access when creating appointments.
Reminders
~~~~~~~~~
In event and task mapping configuration you can define if you want to map (all/non/just upcoming) reminders. If you get the following error message when trying to set reminders in Outlook
`The reminder will not appear because the item is in a folder that doesn’t support reminders.`
you can try to change the Outlook options as discussed in
http://answers.microsoft.com/en-us/office/forum/office_2016-outlook/outlook-2016-calendar-reminders/8f40bcdd-e3fc-4f29-acaf-544f48d63992
or try the following reported by user __Todo18__
1. Create a new storage folder in Outlook via the File menu, Info, Account Settings. In the Data Files tab, you can Add a new (.pst) data file. After the file has been added, Make it the default [data file], and close the dialog.
2. Go to the Calendar window, right click on the calendar that’s giving you problems, and select Move Calendar. In the dialog, pick the data file that you created in the first step, and confirm. Don’t forget to update the storage folder in the CalDav Synchronizer settings!
Distribution Lists
~~~~~~~~~~~~~~~~~~
When enabled in Contact Mapping configuration you can now also sync Outlook Distribution Lists with your server contact groups. Since different servers use different formats to store contact groups, you will be able to choose the used DAV contact group format. Right now, the VLIST format for SOGo servers and vCards with KIND:group are supported. Don’t enable any of these options when your server doesn’t support it!
Since Outlook Distribution Lists also support list members which aren’t in the addressbook but SOGo VLISTs don’t, we add them as custom X-Attributes. With this workaround those members aren’t displayed in SOGo but won’t get lost when syncing back to Outlook.
Since vCard in version 3.0 doesn’t support contact groups we use X-ADDRESSBOOK-SERVER attributes for KIND and MEMBER for contact groups.
General Options and SSL settings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In the General Options Dialog you can change settings which are used for all synchronization profiles.
* *Automatically check for newer versions* set to false to disable checking for updates.
* *Check Internet connection before sync run* checks if an interface is up and try DNS query to dns.msftncsi.com first and if that fails try to download http://www.msftncsi.com/ncsi.txt with the configured proxy before each sync run to avoid error reports if network is unavailable after hibernate for example. Disable this option if you are in a local network where DNS and that URL is blocked.
* *Store data in roaming folder* set to true if you need to store state and profile data in the AppData\Roaming\ directory for roaming profiles in a AD domain for example. When changing this option, a restart of Outlook is required.
* *Include custom message classes in Outlook filter* Disabled by default, enable only if you have custom forms with message_classes other than the default IPM.Appointment/Contact/Task. For better performance, Windows Search Service shouldn’t be deactivated if this option is enabled.
* *Use fast queries for Outlook folders* Enabled by default, uses fast GetTable queries when accessing Outlook folders. Disable only if you get errors in GetVersions, when disabled every item needs to be requested which causes a performance penalty!
* *Trigger sync after Outlook Send/Receive and on Startup* If checked a manual sync is triggered after the Outlook Send/Receive finishes and on Outlook startup.
* *Show advanced settings as default* Show the advanced settings in synchronization profiles as default if enabled.
* *Expand all nodes in Synchronization profiles* Enabled by default, expands all nodes in the synchronization profiles to see the suboptions for network settings and mapping configuration.
* *Enable Tray Icon* Enabled by default, you can disable the tray icon in the Windows Taskbar if you don’t need it.
* *Fix invalid settings* Fixes invalid settings automatically, when synchronization profiles are edited.
* *Show Sync Progress Bar* and *Sync Progress Bar Threshold (Items)* Enabled by default, show a progress bar if more than the treshold of items need to be loaded during a synchronization run. If disabled, no progress bar is shown but be aware that for larger changes Outlook can freeze, since some operations need to be performed in the Outlook main thread.
* *Accept invalid chars in server response* If checked invalid characters in XML server responses are allowed. A typical invalid char, sent by some servers is Form feed (0x0C).
* * Enable useUnsafeHeaderParsing* Enable, if the server sends invalid http headers, see common network errors. Needed for Yahoo and cPanel Horde servers for example. The general option overrides the setting in the app.config file.
* *CalDav Connection Timeout (secs)* For slow server connections you can increaste the timeout value (default 90 secs).
SSL/TLS settings
^^^^^^^^^^^^^^^^
If you have problems with SSL/TLS and self-signed certificates, you can change the following settings at your own risk.
The recommended way would be to add the self signed cert to the Local Computer Trusted Root Certification Authorities
You can import the cert by running the MMC as Administrator.
* *Disable Certificate Validation* set to true to disable SSL/TLS certificate validation, major security risk, use with caution!
* *Enable Client Certificates* If enabled, the available client certificates from the Windows user certificate store will automatically be provided.
* *Enable Tls12* set to false to disable TLS12, not recommended!
* *Enable Ssl3* set to true to enable deprecated SSLv3, major security risk, use with caution!
Logging
^^^^^^^
In the *General Logging* section you can show or clear the log file and define the log level. Possible log levels are `INFO` and `DEBUG`.
You can also configure Synchronization reports for all profiles, this can be configured via general Options:
* *Log* You can choose if you want to generate reports for *"Only sync runs with errors"* or *"Sync runs with errors or warnings"* or *"All sync runs"*.
* *Show immediately* configures if the Sync reports should be shown immediately after a sync run with errors, with warnings or errors, or not at all.
* *Delete reports older than (days)* Automatically delete reports which are older than the days configured.
You can show reports manually with the *Reports* button in the CalDav Synchronizer Ribbon. There you can choose from available reports (shown as profile name with timestamp of the sync run) and see informations about items synced and if there were any warnings or errors. You can also delete reports or add them to a zip file via the context menu. If the last sync run lead to any errors, a warning symbol is shown in the Ribbon or the Report window opens if configured in the general options.
Profile Import/Export
~~~~~~~~~~~~~~~~~~~~~
In the toolbar of the synchronization profiles you can export all profiles to a file and import profiles from an earlier exported file. When exporting, you can choose a filename, the extension is *.cdsp and all options are saved in an xml format into this file. When importing the file, existing profiles are merged with the imported ones. If the selected Outlook folder for the profile doesn’t exist during import, you need to manually select a folder before you can save the options, they are not automatically created. You need also be aware of the fact, that saved profile passwords won’t work on other accounts or machines, since the encryption is dependant on the current user. But you can use the account password from the IMAP/POP3 account if available. General options are not saved in that file, but in the registry in `HKEY_CURRENT_USER\Software\CalDavSynchronizer`.
Troubleshooting
---------------
Synchronization Status
~~~~~~~~~~~~~~~~~~~~~~
With the *Status* button in the CalDav Synchronizer Ribbon or via doubleclick from the TrayIcon you can access the status of the active sync profiles with their last sync run shown in minutes ago and the status OK, error, or warning. When clicking on the profile name you get to the according sync profile settings, when clicking the status icon, you can open the according sync report. When a sync run has any errors or warnings you will get a notification from the CalDav Synchronizer TrayIcon.
Debugging
~~~~~~~~~
Options and state information is normally stored in the following folder:
----
C:\Users\<Your Username>\AppData\Local\CalDavSychronizer
----
If you activated Store data in roaming folder the location is changed to the following folder:
----
C:\Users\<Your Username>\AppData\Roaming\CalDavSychronizer
----
There is one `options_<your outlook profile>.xml` file which stores the options for each outlook profile.
For each sync profile there is a subfolder with state information stored in a relations.xml file after the inital sync. If you delete that folder, a fresh inital sync is performed. In the Synchronization profiles dialog a context menu is available in each profile (right click), which allows to open the cache directory and read the relations.xml file.
Each synchronization attempt is logged in the `log.txt` file. There you can find information about sync duration and the amount of added, deleted or modified events. Errors and Exceptions are logged aswell. You can view and clear the log file in *General Options*. There you can also change the log level from `INFO` to `DEBUG`.
In the install dir (The default is `C:\Program Files (x86)\CalDavSynchronizer`) you will find the app config file
` CalDavSynchronizer.dll.config`
In that xml file you can config timeout parameters and config options in the section `appSettings`
After changing parameters you have to restart Outlook.
* *wpfRenderModeSoftwareOnly*: When set to true, turn off hardware acceleration and use Software Rendering only. Useful if you have issues with WPF and your graphics card driver.
You can also change defaults for some of the general options like CheckForNewVersions, StoreAppDatainRoamingFolder, IncludeCustomMessageClasses and SSL/TLS options, useful for All Users deployment, because general options are stored per user in the HKCU registry hive.
In the section `system.net` you can define proxy settings, e.g. use of NTLM credentials
----
<defaultProxy useDefaultCredentials="true">
</defaultProxy>
----
In this section you can also allow UnsafeHeaderParsing if the server sends invalid http headers.
----
<system.net>
<settings>
<servicePointManager expect100Continue="false" />
<httpWebRequest useUnsafeHeaderParsing="true" />
</settings>
</system.net>
----
This setting can also be enabled in the general options, starting with version 2.10.0.
In the section `log4net` you can define the log level for the main log (also possible in general options now).
level value can be DEBUG or INFO, e.g.:
----
<root>
<level value="DEBUG" />
<appender-ref ref="MainLogAppender" />
</root>
----
Common network errors
^^^^^^^^^^^^^^^^^^^^^
* System.Net.Http.HttpRequestException: Response status code does not indicate success: '401' ('Unauthorized').
** Wrong Username and/or Password provided.
* System.Net.Http.HttpRequestException: An error occurred while sending the request. --→ System.Net.WebException: The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.
** The server has KeepAlive disabled. Use *"Close connection after each request"* in *Network and proxy options*.
* System.Net.Http.HttpRequestException: An error occurred while sending the request. --→ System.Net.WebException: The server committed a protocol violation. Section=ResponseStatusLine
** The server sends invalid headers. Enable the general option *Enable useUnsafeHeaderParsing* or the commented out option *useUnsafeHeaderparsing* in the app config file.
-323
View File
@@ -1,323 +0,0 @@
#
# https://github.com/asciidoctor/asciidoctor-pdf/blob/master/docs/theming-guide.adoc
#
font:
catalog:
# Noto Serif supports Latin, Latin-1 Supplement, Latin Extended-A, Greek, Cyrillic, Vietnamese & an assortment of symbols
#Noto Serif:
# normal: notoserif-regular-subset.ttf
# bold: notoserif-bold-subset.ttf
# italic: notoserif-italic-subset.ttf
# bold_italic: notoserif-bold_italic-subset.ttf
Lato-Light:
normal: lato/Lato-Light.ttf
bold: lato/Lato-Regular.ttf
italic: lato/Lato-LightItalic.ttf
bold_italic: lato/Lato-Italic.ttf
# M+ 1mn supports ASCII and the circled numbers used for conums
#M+ 1mn:
# normal: mplus1mn-regular-subset.ttf
# bold: mplus1mn-bold-subset.ttf
# italic: mplus1mn-italic-subset.ttf
# bold_italic: mplus1mn-bold_italic-subset.ttf
Inconsolata:
normal: inconsolata.ttf
bold: inconsolata.ttf
italic: inconsolata.ttf
bold_italic: inconsolata.ttf
page:
background_color: FFFFFF
layout: portrait
initial_zoom: FitH
margin: [1in, 1in, 1in, 1in]
# margin_inner and margin_outer keys are used for recto/verso print margins when media=prepress
margin_inner: 1in
margin_outer: 1in
size: Letter
base:
align: justify
# color as hex string (leading # is optional)
font_color: 333333
font_color: 000000
# color as RGB array
#font_color: [51, 51, 51]
# color as CMYK array (approximated)
#font_color: [0, 0, 0, 0.92]
#font_color: [0, 0, 0, 92%]
font_family: Lato-Light
# choose one of these font_size/line_height_length combinations
#font_size: 14
#line_height_length: 20
#font_size: 11.25
#line_height_length: 18
#font_size: 11.2
#line_height_length: 16
font_size: 10
#line_height_length: 15
# correct line height for Noto Serif metrics
line_height_length: 10
#font_size: 11.25
#line_height_length: 18
line_height: $base_line_height_length / $base_font_size
font_size_large: round($base_font_size * 1.25)
font_size_small: round($base_font_size * 0.85)
font_size_min: $base_font_size * 0.75
font_style: normal
border_color: EEEEEE
border_radius: 4
border_width: 0.5
section:
indent: [0.67in, 0]
role:
line-through:
text_decoration: line-through
underline:
text_decoration: underline
big:
font_size: $base_font_size_large
small:
font_size: $base_font_size_small
subtitle:
font_size: 0.8em
font_color: 999999
# FIXME vertical_rhythm is weird; we should think in terms of ems
#vertical_rhythm: $base_line_height_length * 2 / 3
# correct line height for Noto Serif metrics (comes with built-in line height)
vertical_rhythm: $base_line_height_length
horizontal_rhythm: $base_line_height_length
# QUESTION should vertical_spacing be block_spacing instead?
vertical_spacing: $vertical_rhythm
link:
font_color: 428BCA
font_color: 007BFF
# literal is currently used for inline monospaced in prose and table cells
literal:
font_color: 333333
font_color: B12146
font_color: E83E8C
font_family: Inconsolata
button:
content: "[\u2009%s\u2009]"
font_style: bold
key:
background_color: F5F5F5
background_color: F8F8F8
border_color: CCCCCC
border_offset: 2
border_radius: 2
border_width: 0.5
font_family: $literal_font_family
separator: "\u202f+\u202f"
mark:
background_color: FFFF00
border_offset: 1
menu:
caret_content: " <font size=\"1.15em\"><color rgb=\"b12146\">\u203a</color></font> "
heading:
align: left
font_color: $base_font_color
font_style: bold
# h1 is used for part titles (book doctype) or the doctitle (article doctype)
h1_font_size: floor($base_font_size * 2.6)
# h2 is used for chapter titles (book doctype only)
h2_font_size: floor($base_font_size * 2.15)
h3_font_size: round($base_font_size * 1.7)
h4_font_size: $base_font_size_large
h5_font_size: $base_font_size
h6_font_size: $base_font_size_small
#line_height: 1.4
# correct line height for Noto Serif metrics (comes with built-in line height)
line_height: 1
margin_top: $vertical_rhythm * 0.4
margin_bottom: $vertical_rhythm * 0.9
min_height_after: $base_line_height_length * 1.5
h2-margin_bottom: 60
#h2-text_decoration: underline
title_page:
align: right
logo:
top: 10%
title:
top: 55%
font_size: $heading_h1_font_size
font_color: 999999
font_color: $base_font_color
line_height: 0.9
subtitle:
font_size: $heading_h3_font_size
font_style: bold_italic
line_height: 1
authors:
margin_top: $base_font_size * 1.25
font_size: $base_font_size_large
font_color: 181818
revision:
margin_top: $base_font_size * 1.25
block:
margin_top: 0
margin_bottom: $vertical_rhythm
caption:
align: left
font_size: $base_font_size * 0.95
font_style: italic
# FIXME perhaps set line_height instead of / in addition to margins?
margin_inside: $vertical_rhythm / 3
#margin_inside: $vertical_rhythm / 4
margin_outside: 0
lead:
font_size: $base_font_size_large
line_height: 1.4
abstract:
font_color: 5C6266
font_size: $lead_font_size
line_height: $lead_line_height
font_style: italic
first_line_font_style: bold
title:
align: center
font_color: $heading_font_color
font_size: $heading_h4_font_size
font_style: $heading_font_style
admonition:
column_rule_color: $base_border_color
column_rule_width: $base_border_width
padding: [0, $horizontal_rhythm, 0, $horizontal_rhythm]
# icon:
# caution:
# name: far-lightbulb
# name: fa-fire
# stroke_color: 111111
# size: 24
label:
text_transform: uppercase
font_style: bold
# caution:
# font_color: F77D05
blockquote:
font_size: $base_font_size_large
border_color: $base_border_color
border_width: 0
border_left_width: 5
# FIXME disable negative padding bottom once margin collapsing is implemented
padding: [0, $horizontal_rhythm, $block_margin_bottom * -0.75, $horizontal_rhythm + $blockquote_border_left_width / 2]
cite_font_size: $base_font_size_small
cite_font_color: 999999
verse:
font_size: $blockquote_font_size
border_color: $blockquote_border_color
border_width: $blockquote_border_width
border_left_width: $blockquote_border_left_width
padding: $blockquote_padding
cite_font_size: $blockquote_cite_font_size
cite_font_color: $blockquote_cite_font_color
# code is used for source blocks (perhaps change to source or listing?)
code:
font_color: $base_font_color
#font_color: FFFFFF
font_family: $literal_font_family
font_size: ceil($base_font_size)
padding: $code_font_size
line_height: 1.25
# line_gap is an experimental property to control how a background color is applied to an inline block element
line_gap: 3.8
background_color: F5F5F5
background_color: F8F8F8
#background_color: 6C757D
border_color: CCCCCC
border_radius: $base_border_radius
border_radius: 0
border_width: 0.75
border_width: 0
conum:
font_family: $literal_font_family
font_color: $literal_font_color
font_size: $base_font_size
line_height: 4 / 3
glyphs: circled
example:
border_color: $base_border_color
border_radius: $base_border_radius
border_width: 0.75
background_color: $page-background-color
# FIXME reenable padding bottom once margin collapsing is implemented
padding: [$vertical_rhythm, $horizontal_rhythm, 0, $horizontal_rhythm]
image:
align: left
prose:
margin_top: $block_margin_top
margin_bottom: $block_margin_bottom
sidebar:
background_color: EEEEEE
border_color: E1E1E1
border_radius: $base_border_radius
border_width: $base_border_width
# FIXME reenable padding bottom once margin collapsing is implemented
padding: [$vertical_rhythm, $vertical_rhythm * 1.25, 0, $vertical_rhythm * 1.25]
title:
align: center
font_color: $heading_font_color
font_size: $heading_h4_font_size
font_style: $heading_font_style
thematic_break:
border_color: $base_border_color
border_style: solid
border_width: $base_border_width
margin_top: $vertical_rhythm * 0.5
margin_bottom: $vertical_rhythm * 1.5
description_list:
term_font_style: bold
term_spacing: $vertical_rhythm / 4
description_indent: $horizontal_rhythm * 1.25
outline_list:
indent: $horizontal_rhythm * 1.5
#marker_font_color: 404040
# NOTE outline_list_item_spacing applies to list items that do not have complex content
item_spacing: $vertical_rhythm / 2
table:
background_color: $page_background_color
border_color: DDDDDD
border_width: $base_border_width
cell_padding: 3
head:
font_style: bold
border_bottom_width: $base_border_width * 2.5
body:
stripe_background_color: F9F9F9
foot:
background_color: F0F0F0
toc:
indent: $horizontal_rhythm
line_height: $base_line_height
dot_leader:
#content: ". "
font_color: A9A9A9
#levels: 2 3
footnotes:
font_size: round($base_font_size * 0.75)
item_spacing: $outline_list_item_spacing / 2
header:
# Can't show chapter number. See https://github.com/asciidoctor/asciidoctor-pdf/issues/1373
font_size: $base_font_size_small
line_height: 1
vertical_align: middle
footer:
font_size: $base_font_size_small
# NOTE if background_color is set, background and border will span width of page
#border_color: DDDDDD
border_width: 0.25
#height: $base_line_height_length * 2.5
height: $base_line_height_length * 5
line_height: 1
padding: [$base_line_height_length / 2, 1, 0, 1]
vertical_align: top
recto: &shared_footer
#columns: "<50% =0% >50%"
left:
content: 'Copyright © Inverse inc.'
center:
content: '{chapter-title}'
right:
content: '{page-number}'
verso: *shared_footer
#columns: $footer_recto_columns
+16
View File
@@ -0,0 +1,16 @@
#
# fop fix to build our documentation on CentOS 6
#
# Inverse inc. <info@inverse.ca>
#
--- /usr/bin/fop.orig 2012-01-17 21:25:50.000000000 -0500
+++ /usr/bin/fop 2012-01-17 21:26:04.000000000 -0500
@@ -26,7 +26,7 @@
# Set parameters
set_jvm
set_classpath commons-io batik-all avalon-framework xmlgraphics-commons \
- commons-logging fop
+ commons-logging fop xalan-j2
set_flags $BASE_FLAGS
set_options $BASE_OPTIONS
@@ -0,0 +1,17 @@
#
# xmlgraphics-fop fix to build our documentation on CentOS 5
# taken from https://build.opensuse.org/request/show/68994
#
# Inverse inc. <info@inverse.ca>
#
--- /usr/bin/xmlgraphics-fop.orig 2012-01-17 18:42:08.000000000 -0500
+++ /usr/bin/xmlgraphics-fop 2012-01-17 18:42:18.000000000 -0500
@@ -24,7 +24,7 @@
# Rest of the configuration
MAIN_CLASS=org.apache.fop.cli.Main
-BASE_JARS="xmlgraphics-fop xmlgraphics-batik/util xml-commons-jaxp-1.3-apis excalibur/avalon-framework-api xerces-j2 xalan-j2 xalan-j2-serializer"
+BASE_JARS="xmlgraphics-fop batik-all xml-commons-jaxp-1.3-apis excalibur/avalon-framework-impl excalibur/avalon-framework-api xerces-j2 xalan-j2 xalan-j2-serializer"
# Set parameters
set_jvm
@@ -0,0 +1,107 @@
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0">
<!-- ********************************************************************
Header / Footer customizations
This file is part of the SOGo project.
Authors:
- Inverse inc. <info@inverse.ca>
Copyright (C) 2011-2014 Inverse inc.
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
******************************************************************** -->
<!--
Here we are re-defining docbook-xsl/fo/pagesetup.xsl to fit our needs.
- top: chapter number on the left
- bottom: copyright, chapter name, page
-->
<xsl:param name="header.rule" select="0"/>
<xsl:template name="header.content">
<xsl:param name="pageclass" select="''"/>
<xsl:param name="sequence" select="''"/>
<xsl:param name="position" select="''"/>
<xsl:param name="gentext-key" select="''"/>
<fo:block>
<!-- sequence can be odd, even, first, blank -->
<!-- position can be left, center, right -->
<xsl:choose>
<xsl:when test="$sequence = 'blank'">
<!-- nothing -->
</xsl:when>
<xsl:when test="($sequence='first' or $sequence='odd' or $sequence='even') and $position='left'">
<xsl:if test="$pageclass != 'titlepage' and $pageclass != 'lot'">
<xsl:call-template name="gentext">
<xsl:with-param name="key" select="'chapter'"/>
</xsl:call-template>
<xsl:call-template name="gentext.space"/>
<xsl:number count="chapter" from="book" level="any"/>
</xsl:if>
</xsl:when>
<!-- draft -->
<xsl:when test="$position='right'">
<xsl:call-template name="draft.text"/>
</xsl:when>
<xsl:otherwise>
<!-- nop -->
</xsl:otherwise>
</xsl:choose>
</fo:block>
</xsl:template>
<xsl:param name="footer.rule" select="0"/>
<xsl:template name="footer.content">
<xsl:param name="pageclass" select="''"/>
<xsl:param name="sequence" select="''"/>
<xsl:param name="position" select="''"/>
<xsl:param name="gentext-key" select="''"/>
<fo:block>
<!-- pageclass can be front, body, back -->
<!-- sequence can be odd, even, first, blank -->
<!-- position can be left, center, right -->
<xsl:choose>
<xsl:when test="$pageclass = 'titlepage'">
<!-- nop; no footer on title pages -->
</xsl:when>
<xsl:when test="$double.sided = 0 and $position='left'">
<xsl:apply-templates select="//copyright[1]" mode="titlepage.mode"/>
</xsl:when>
<xsl:when test="($sequence='first' or $sequence='odd' or $sequence='even') and $position='center'">
<xsl:if test="$pageclass != 'titlepage' and $pageclass != 'lot'">
<xsl:apply-templates select="." mode="titleabbrev.markup"/>
</xsl:if>
</xsl:when>
<xsl:when test="$double.sided = 0 and $position='right'">
<fo:page-number/>
</xsl:when>
<xsl:when test="$sequence='blank'">
<!-- nop -->
</xsl:when>
<xsl:otherwise>
<!-- nop -->
</xsl:otherwise>
</xsl:choose>
</fo:block>
</xsl:template>
</xsl:stylesheet>
<!-- vim: set shiftwidth=2 tabstop=2 expandtab: -->
+182
View File
@@ -0,0 +1,182 @@
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0">
<!-- ********************************************************************
SOGo Documentation Docbook FO Parameters
This file is part of the SOGo project.
Authors:
- Inverse inc. <info@inverse.ca>
Copyright (C) 2011-2014 Inverse inc.
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
******************************************************************** -->
<!--
Global Tasks
TODO prettier revhistory
TODO prettier Table of Contents
TODO generate PDF table of contents (like OSX's Preview shows on the right hand side)
TODO title 2
- align with text?
- more above whitespace
TODO change the bullet for a prettier one
TODO title 3 and 4
- align with text?
- should be easier to differentiate (check network guide)
TODO icon on line wrap in monospace boxes
TODO caution, notes, warnings, etc.
- box around it
- sexy icon
TODO -> is converted into an arrow but it's not pretty (is it font or docbook-thingy?)
-->
<!--
Load default values
Real upstream schema is at:
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl"/>
but we decided to load all sensible local xsd since it only produce a warning on missing imports.
-->
<!-- CentOS / RHEL -->
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/fo/docbook.xsl"/>
<!-- Debian / Ubuntu -->
<xsl:import href="/usr/share/xml/docbook/stylesheet/docbook-xsl/fo/docbook.xsl"/>
<!-- OSX through mac ports -->
<xsl:import href="/opt/local/share/xsl/docbook-xsl/fo/docbook.xsl"/>
<!-- title page extra styling -->
<xsl:import href="titlepage-fo.xsl"/>
<!-- header / footer extra styling -->
<xsl:import href="headerfooter-fo.xsl"/>
<!-- attaching an image to the verso legalnotice component -->
<xsl:template match="legalnotice" mode="book.titlepage.verso.mode">
<xsl:apply-templates mode="titlepage.mode"/>
<fo:block text-align="right">
<fo:external-graphic src="url('images/inverse-logo.jpg')" width="3in" content-width="scale-to-fit"/>
</fo:block>
</xsl:template>
<!-- stylesheet options -->
<xsl:param name="title.font.family">Lato-Medium</xsl:param>
<xsl:param name="chapter.autolabel" select="0"/>
<xsl:attribute-set name="component.title.properties">
<xsl:attribute name="padding-bottom">2.5em</xsl:attribute>
<xsl:attribute name="border-bottom">solid 2px</xsl:attribute>
<xsl:attribute name="margin-bottom">1em</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="section.title.level1.properties">
<xsl:attribute name="border-bottom">solid 1px</xsl:attribute>
<xsl:attribute name="margin-top">2em</xsl:attribute>
<xsl:attribute name="margin-bottom">1em</xsl:attribute>
</xsl:attribute-set>
<!-- titles spacing -->
<xsl:attribute-set name="section.title.level2.properties">
<xsl:attribute name="margin-top">1em</xsl:attribute>
</xsl:attribute-set>
<!-- default fonts -->
<xsl:param name="body.font.family">Lato-Light</xsl:param>
<xsl:param name="body.font.master">10</xsl:param>
<xsl:param name="monospace.font.family">Incosolata</xsl:param>
<!-- revision table layout -->
<xsl:attribute-set name="revhistory.title.properties">
<xsl:attribute name="font-size">12pt</xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="text-align">center</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="revhistory.table.properties">
<xsl:attribute name="break-before">page</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="revhistory.table.cell.properties">
<xsl:attribute name="border-bottom">1px solid</xsl:attribute>
</xsl:attribute-set>
<!-- Table Of Contents (TOC) options -->
<!-- We only want 2 level of ToC depth -->
<xsl:param name="toc.section.depth" select="1"/>
<!-- titles left margin -->
<xsl:attribute-set name="section.title.properties">
<xsl:attribute name="start-indent"><xsl:value-of select="$body.start.indent"/></xsl:attribute>
</xsl:attribute-set>
<!-- lists type -->
<xsl:template name="itemizedlist.label.markup">
<xsl:param name="itemsymbol" select="'square'"/>
<xsl:choose>
<xsl:when test="$itemsymbol='square'"><fo:inline font-family="Lato-Light">&#x25aa;</fo:inline></xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="next.itemsymbol">
<xsl:param name="itemsymbol" select="'default'"/>
<xsl:choose>
<xsl:otherwise>square</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- admonition -->
<xsl:param name="admon.graphics" select="1"></xsl:param>
<xsl:param name="admon.graphics.path">images/</xsl:param>
<xsl:param name="admon.graphics.extension">.png</xsl:param>
<xsl:attribute-set name="graphical.admonition.properties">
<xsl:attribute name="border-top">1px solid</xsl:attribute>
<xsl:attribute name="border-bottom">1px solid</xsl:attribute>
<xsl:attribute name="padding-top">0.5em</xsl:attribute>
<xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
<xsl:attribute name="margin-left">2em</xsl:attribute>
</xsl:attribute-set>
<!-- grey boxes around code (screen, programlisting) -->
<xsl:param name="shade.verbatim" select="1"/>
<xsl:attribute-set name="shade.verbatim.style">
<xsl:attribute name="background-color">#E0E0E0</xsl:attribute>
<xsl:attribute name="border">thin #9F9F9F solid</xsl:attribute>
<xsl:attribute name="margin">0pt</xsl:attribute>
<xsl:attribute name="padding">0.5em</xsl:attribute>
<!-- prevent page breaks in screen and programlisting tags -->
<xsl:attribute name="keep-together.within-column">always</xsl:attribute>
</xsl:attribute-set>
<!-- breaking long lines in code (screen, programlisting) -->
<xsl:attribute-set name="monospace.verbatim.properties">
<xsl:attribute name="wrap-option">wrap</xsl:attribute>
</xsl:attribute-set>
<!-- don't show raw links in [ .. ] after a link -->
<xsl:param name="ulink.show" select="0"/>
<!-- blue underlined hyperlink -->
<xsl:attribute-set name="xref.properties">
<xsl:attribute name="color">blue</xsl:attribute>
<xsl:attribute name="text-decoration">underline</xsl:attribute>
</xsl:attribute-set>
<!-- strong emphasis in bold -->
<xsl:template match="emphasis[@role='strong']">
<fo:inline font-family="Lato" font-weight="normal">
<xsl:apply-templates/>
</fo:inline>
</xsl:template>
<!-- copyright in range instead of seperated years -->
<xsl:param name="make.year.ranges" select="1" />
<!-- variablelist behavior (asciidoc's term:: lists) -->
<!-- <xsl:param name="variablelist.term.break.after" select="1" /> -->
</xsl:stylesheet>
<!-- vim: set shiftwidth=2 tabstop=2 expandtab: -->
@@ -0,0 +1,96 @@
<!DOCTYPE t:templates [
<!ENTITY hsize0 "10pt">
<!ENTITY hsize1 "12pt">
<!ENTITY hsize2 "14.4pt">
<!ENTITY hsize3 "17.28pt">
<!ENTITY hsize4 "20.736pt">
<!ENTITY hsize5 "24.8832pt">
<!ENTITY hsize0space "7.5pt"> <!-- 0.75 * hsize0 -->
<!ENTITY hsize1space "9pt"> <!-- 0.75 * hsize1 -->
<!ENTITY hsize2space "10.8pt"> <!-- 0.75 * hsize2 -->
<!ENTITY hsize3space "12.96pt"> <!-- 0.75 * hsize3 -->
<!ENTITY hsize4space "15.552pt"> <!-- 0.75 * hsize4 -->
<!ENTITY hsize5space "18.6624pt"> <!-- 0.75 * hsize5 -->
]>
<t:templates xmlns:t="http://nwalsh.com/docbook/xsl/template/1.0"
xmlns:param="http://nwalsh.com/docbook/xsl/template/1.0/param"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- ********************************************************************
SOGo title page
This file is part of the SOGo project.
Authors:
- Inverse inc. <info@inverse.ca>
Copyright (C) 2011-2014 Inverse inc.
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
******************************************************************** -->
<!--
If you make changes you need to rebuild XSL:
xsltproc -o docs/docbook/xsl/titlepage-fo.xsl \
/usr/share/xml/docbook/stylesheet/docbook-xsl/template/titlepage.xsl \
docs/docbook/xsl/titlepage-fo.xml
On some platforms the titlepage.xsl is located elsewhere:
* OSX: /opt/local/share/xsl/docbook-xsl/template/titlepage.xsl
This is a customized version of docbook-xsl/fo/titlepage.templates.xml.
I removed every section except the book one. Feel free to add more if more
customization are required.
-->
<t:titlepage t:element="book" t:wrapper="fo:block">
<t:titlepage-content t:side="recto">
<mediaobject/>
<title
t:named-template="division.title"
param:node="ancestor-or-self::book[1]"
text-align="right"
font-size="&hsize5;"
space-before="&hsize5space;"
font-weight="bold"
font-family="{$title.fontset}"
margin-top="8em"/>
<subtitle
text-align="right"
font-size="&hsize4;"
space-before="&hsize4space;"
font-family="{$title.fontset}"
border-bottom="solid"/>
</t:titlepage-content>
<t:titlepage-content t:side="verso">
<title
font-size="&hsize2;"
font-weight="bold"
font-family="{$title.fontset}"/>
<corpauthor/>
<authorgroup t:named-template="verso.authorgroup"/>
<author/>
<othercredit/>
<releaseinfo space-before="0.5em"/>
<pubdate space-before="1em"/>
<copyright/>
<abstract/>
<legalnotice font-size="8pt"/>
</t:titlepage-content>
<t:titlepage-separator>
<fo:block break-after="page"/>
</t:titlepage-separator>
<t:titlepage-before t:side="recto">
</t:titlepage-before>
<t:titlepage-before t:side="verso">
<fo:block break-after="page"/>
</t:titlepage-before>
</t:titlepage>
</t:templates>
+208
View File
@@ -0,0 +1,208 @@
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" version="1.0" exclude-result-prefixes="exsl">
<!-- This stylesheet was created by template/titlepage.xsl-->
<xsl:template name="book.titlepage.recto">
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="bookinfo/mediaobject"/>
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="info/mediaobject"/>
<xsl:choose>
<xsl:when test="bookinfo/title">
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="bookinfo/title"/>
</xsl:when>
<xsl:when test="info/title">
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="info/title"/>
</xsl:when>
<xsl:when test="title">
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="title"/>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="bookinfo/subtitle">
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="bookinfo/subtitle"/>
</xsl:when>
<xsl:when test="info/subtitle">
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="info/subtitle"/>
</xsl:when>
<xsl:when test="subtitle">
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="subtitle"/>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="book.titlepage.verso">
<xsl:choose>
<xsl:when test="bookinfo/title">
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/title"/>
</xsl:when>
<xsl:when test="info/title">
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/title"/>
</xsl:when>
<xsl:when test="title">
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="title"/>
</xsl:when>
</xsl:choose>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/corpauthor"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/corpauthor"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/authorgroup"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/authorgroup"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/author"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/author"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/othercredit"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/othercredit"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/releaseinfo"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/releaseinfo"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/pubdate"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/pubdate"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/copyright"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/copyright"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/abstract"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/abstract"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/legalnotice"/>
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/legalnotice"/>
</xsl:template>
<xsl:template name="book.titlepage.separator"><fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" break-after="page"/>
</xsl:template>
<xsl:template name="book.titlepage.before.recto">
</xsl:template>
<xsl:template name="book.titlepage.before.verso"><fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" break-after="page"/>
</xsl:template>
<xsl:template name="book.titlepage">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:variable name="recto.content">
<xsl:call-template name="book.titlepage.before.recto"/>
<xsl:call-template name="book.titlepage.recto"/>
</xsl:variable>
<xsl:variable name="recto.elements.count">
<xsl:choose>
<xsl:when test="function-available('exsl:node-set')"><xsl:value-of select="count(exsl:node-set($recto.content)/*)"/></xsl:when>
<xsl:when test="contains(system-property('xsl:vendor'), 'Apache Software Foundation')">
<!--Xalan quirk--><xsl:value-of select="count(exsl:node-set($recto.content)/*)"/></xsl:when>
<xsl:otherwise>1</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:if test="(normalize-space($recto.content) != '') or ($recto.elements.count &gt; 0)">
<fo:block><xsl:copy-of select="$recto.content"/></fo:block>
</xsl:if>
<xsl:variable name="verso.content">
<xsl:call-template name="book.titlepage.before.verso"/>
<xsl:call-template name="book.titlepage.verso"/>
</xsl:variable>
<xsl:variable name="verso.elements.count">
<xsl:choose>
<xsl:when test="function-available('exsl:node-set')"><xsl:value-of select="count(exsl:node-set($verso.content)/*)"/></xsl:when>
<xsl:when test="contains(system-property('xsl:vendor'), 'Apache Software Foundation')">
<!--Xalan quirk--><xsl:value-of select="count(exsl:node-set($verso.content)/*)"/></xsl:when>
<xsl:otherwise>1</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:if test="(normalize-space($verso.content) != '') or ($verso.elements.count &gt; 0)">
<fo:block><xsl:copy-of select="$verso.content"/></fo:block>
</xsl:if>
<xsl:call-template name="book.titlepage.separator"/>
</fo:block>
</xsl:template>
<xsl:template match="*" mode="book.titlepage.recto.mode">
<!-- if an element isn't found in this mode, -->
<!-- try the generic titlepage.mode -->
<xsl:apply-templates select="." mode="titlepage.mode"/>
</xsl:template>
<xsl:template match="*" mode="book.titlepage.verso.mode">
<!-- if an element isn't found in this mode, -->
<!-- try the generic titlepage.mode -->
<xsl:apply-templates select="." mode="titlepage.mode"/>
</xsl:template>
<xsl:template match="mediaobject" mode="book.titlepage.recto.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.recto.style">
<xsl:apply-templates select="." mode="book.titlepage.recto.mode"/>
</fo:block>
</xsl:template>
<xsl:template match="title" mode="book.titlepage.recto.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.recto.style" text-align="right" font-size="24.8832pt" space-before="18.6624pt" font-weight="bold" font-family="{$title.fontset}" margin-top="8em">
<xsl:call-template name="division.title">
<xsl:with-param name="node" select="ancestor-or-self::book[1]"/>
</xsl:call-template>
</fo:block>
</xsl:template>
<xsl:template match="subtitle" mode="book.titlepage.recto.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.recto.style" text-align="right" font-size="20.736pt" space-before="15.552pt" font-family="{$title.fontset}" border-bottom="solid">
<xsl:apply-templates select="." mode="book.titlepage.recto.mode"/>
</fo:block>
</xsl:template>
<xsl:template match="title" mode="book.titlepage.verso.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style" font-size="14.4pt" font-weight="bold" font-family="{$title.fontset}">
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
</fo:block>
</xsl:template>
<xsl:template match="corpauthor" mode="book.titlepage.verso.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style">
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
</fo:block>
</xsl:template>
<xsl:template match="authorgroup" mode="book.titlepage.verso.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style">
<xsl:call-template name="verso.authorgroup">
</xsl:call-template>
</fo:block>
</xsl:template>
<xsl:template match="author" mode="book.titlepage.verso.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style">
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
</fo:block>
</xsl:template>
<xsl:template match="othercredit" mode="book.titlepage.verso.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style">
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
</fo:block>
</xsl:template>
<xsl:template match="releaseinfo" mode="book.titlepage.verso.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style" space-before="0.5em">
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
</fo:block>
</xsl:template>
<xsl:template match="pubdate" mode="book.titlepage.verso.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style" space-before="1em">
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
</fo:block>
</xsl:template>
<xsl:template match="copyright" mode="book.titlepage.verso.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style">
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
</fo:block>
</xsl:template>
<xsl:template match="abstract" mode="book.titlepage.verso.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style">
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
</fo:block>
</xsl:template>
<xsl:template match="legalnotice" mode="book.titlepage.verso.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style" font-size="8pt">
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
</fo:block>
</xsl:template>
</xsl:stylesheet>
+24
View File
@@ -0,0 +1,24 @@
<!-- TODO have the build system take care of this -->
<releaseinfo>Version 2.2.16 - February 2015</releaseinfo>
<subtitle>for version 2.2.16</subtitle>
<date>2015-02-12</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>
<!-- font licenses -->
<para>The fonts used in this guide are licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: <ulink url="http://scripts.sil.org/OFL">http://scripts.sil.org/OFL</ulink></para>
<para>Copyright © Łukasz Dziedzic, <ulink url="http://www.latofonts.com/">http://www.latofonts.com</ulink>, with Reserved Font Name: "Lato".</para>
<para>Copyright © Raph Levien, <ulink url="http://levien.com/">http://levien.com/</ulink>, with Reserved Font Name: "Inconsolata".</para>
</legalnotice>
<mediaobject>
<objectinfo>
<corpname>Inverse inc.</corpname>
</objectinfo>
<textobject>
<phrase>SOGo logo</phrase>
</textobject>
<imageobject>
<imagedata align="left" width="4in" format="PNG" fileref="images/sogo-logo.png" />
</imageobject>
</mediaobject>
+32
View File
@@ -0,0 +1,32 @@
<fop version="1.0">
<renderers>
<renderer mime="application/pdf">
<fonts>
<font metrics-url="fonts/inconsolata.xml" kerning="yes" embed-url="fonts/inconsolata.ttf">
<font-triplet name="Incosolata" style="normal" weight="normal"/>
</font>
<font metrics-url="fonts/lato/Lato-Regular.xml" kerning="yes" embed-url="fonts/lato/Lato-Regular.ttf">
<font-triplet name="Lato" style="normal" weight="normal"/>
</font>
<font metrics-url="fonts/lato/Lato-Italic.xml" kerning="yes" embed-url="fonts/lato/Lato-Italic.ttf">
<font-triplet name="Lato" style="italic" weight="normal"/>
</font>
<font metrics-url="fonts/lato/Lato-Light.xml" kerning="yes" embed-url="fonts/lato/Lato-Light.ttf">
<font-triplet name="Lato-Light" style="normal" weight="normal"/>
</font>
<font metrics-url="fonts/lato/Lato-LightItalic.xml" kerning="yes" embed-url="fonts/lato/Lato-LightItalic.ttf">
<font-triplet name="Lato-Light" style="italic" weight="normal"/>
</font>
<font metrics-url="fonts/lato/Lato-Medium.xml" kerning="yes" embed-url="fonts/lato/Lato-Medium.ttf">
<font-triplet name="Lato-Medium" style="normal" weight="normal"/>
</font>
<font metrics-url="fonts/lato/Lato-MediumItalic.xml" kerning="yes" embed-url="fonts/lato/Lato-MediumItalic.ttf">
<font-triplet name="Lato-Medium" style="italic" weight="normal"/>
</font>
<font metrics-url="fonts/lato/Lato-Semibold.xml" kerning="yes" embed-url="fonts/lato/Lato-Semibold.ttf">
<font-triplet name="Lato-Semibold" style="normal" weight="normal"/>
</font>
</fonts>
</renderer>
</renderers>
</fop>
+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Inconsolata</font-name><full-name>Inconsolata</full-name><family-name>Inconsolata</family-name><embed/><cap-height>624</cap-height><x-height>458</x-height><ascender>820</ascender><descender>-180</descender><bbox><left>-1</left><bottom>-177</bottom><right>510</right><top>835</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="3" ue="126" us="32"/><bf gi="98" ue="255" us="160"/><bf gi="194" ue="263" us="258"/><bf gi="200" ue="273" us="268"/><bf gi="206" ue="283" us="280"/><bf gi="210" ue="287" us="286"/><bf gi="212" ue="305" us="304"/><bf gi="214" ue="314" us="312"/><bf gi="217" ue="318" us="317"/><bf gi="219" ue="324" us="321"/><bf gi="223" ue="328" us="327"/><bf gi="225" ue="331" us="330"/><bf gi="227" ue="333" us="333"/><bf gi="228" ue="341" us="336"/><bf gi="234" ue="347" us="344"/><bf gi="238" ue="357" us="350"/><bf gi="246" ue="369" us="366"/><bf gi="250" ue="382" us="376"/><bf gi="257" ue="402" us="402"/><bf gi="258" ue="567" us="567"/><bf gi="259" ue="711" us="710"/><bf gi="261" ue="713" us="713"/><bf gi="262" ue="715" us="715"/><bf gi="263" ue="733" us="728"/><bf gi="269" ue="8218" us="8216"/><bf gi="272" ue="8222" us="8220"/><bf gi="275" ue="8226" us="8224"/><bf gi="278" ue="8230" us="8230"/><bf gi="279" ue="8250" us="8249"/><bf gi="281" ue="8260" us="8260"/><bf gi="282" ue="8308" us="8308"/><bf gi="283" ue="8364" us="8364"/><bf gi="284" ue="8482" us="8482"/><bf gi="285" ue="8593" us="8593"/><bf gi="286" ue="8595" us="8595"/><bf gi="287" ue="8722" us="8722"/><bf gi="288" ue="9251" us="9251"/><bf gi="0" ue="65535" us="65535"/></bfranges><cid-widths start-index="0"><wx w="500"/><wx w="0"/><wx w="333"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wLine truncated
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 KiB

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

File renamed without changes.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

@@ -5,9 +5,8 @@
This file is part of the SOGo project.
Authors:
- Inverse inc. <info@inverse.ca>
- Alinto <contact@sogo.nu>
Copyright (C) 2008-2022 Inverse inc. / Alinto
Copyright (C) 2008-2014 Inverse inc.
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
////
@@ -18,11 +17,11 @@ Additional Information
For more information, please consult the online FAQs (Frequently Asked
Questions) :
https://sogo.nu/support/faq.html
http://www.sogo.nu/english/support/faq.html
You can also read the mailing archives or post your questions to it. For
details, see :
https://mailing.sogo.nu/sympa/info/users
https://lists.inverse.ca/sogo
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:
@@ -5,9 +5,8 @@
This file is part of the SOGo project.
Authors:
- Inverse inc. <info@inverse.ca>
- Alinto <contact@sogo.nu>
Copyright (C) 2008-2022 Inverse inc. / Alinto
Copyright (C) 2008-2014 Inverse inc.
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
////
@@ -16,14 +15,12 @@ Commercial Support and Contact Information
------------------------------------------
For any questions or comments, do not hesitate to contact us by writing
an email to contact@sogo.nu.
an email to :
Alinto (https://alinto.com) offers professional services around SOGo
to help organizations deploy the solution, customize, migrate versions or
from another system, performance tuning or aligning with best practices.
mailto:support@inverse.ca[support@inverse.ca]
Hourly rates or support packages are offered to best suit your needs.
Please visit https://alinto.com/ for details.
Inverse (http://inverse.ca/[http://inverse.ca]) offers professional
services around SOGo to help organizations deploy the solution and
migrate from their legacy systems.
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:
-14
View File
@@ -1,14 +0,0 @@
Version {release_version} - {release_month} {docyear}
Copyright © {docyear} Inverse inc. / Alinto
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".
The fonts used in this guide are licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL
Copyright © Łukasz Dziedzic, http://www.latofonts.com, with Reserved Font Name: "Lato".
Copyright © Raph Levien, http://levien.com/, with Reserved Font Name: "Inconsolata".
image::images/inverse-logo.jpeg[width="25%",pdfwidth="50%",align="right"]
image::images/alinto.small.png[width="25%",pdfwidth="50%",align="right"]
@@ -5,27 +5,14 @@
This file is part of the SOGo project.
Authors:
- Inverse inc. <info@inverse.ca>
- Alinto <contact@sogo.nu>
Copyright (C) 2008-2022 Inverse inc. / Alinto
Copyright (C) 2008-2015 Inverse inc.
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
////
:encoding: UTF-8
:lang: en
:doctype: book
SOGo v{release_version}
:toc: left
:sectanchors:
:sectlinks:
// Add numbers to each section
:sectnums:
// Remove chapter prefix
:chapter-signifier:
:front-cover-image: image:images/sogo-logo.png[fit=none,pdfwidth=50%,position=center]
:source-highlighter: rouge
:rouge-style: github
// Above empty line will insert page brake
include::docinfo.asciidoc[]
// TODO have the build system take care of this
:release_version: 2.2.16
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:
+1 -2
View File
@@ -5,9 +5,8 @@
This file is part of the SOGo project.
Authors:
- Inverse inc. <info@inverse.ca>
- Alinto <contact@sogo.nu>
Copyright (C) 2008-2022 Inverse inc. / Alinto
Copyright (C) 2008-2014 Inverse inc.
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
////
+2
View File
@@ -19,6 +19,7 @@
02111-1307, USA.
*/
#import <Foundation/NSObject.h>
@interface MainUIProduct : NSObject
{
@@ -26,6 +27,7 @@
@end
#import <Foundation/Foundation.h>
@implementation MainUIProduct
+1
View File
@@ -20,6 +20,7 @@
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSException.h>
@interface NSException (SOGoExtensions)
+1
View File
@@ -19,6 +19,7 @@
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <execinfo.h>
#import "NSException+Stacktrace.h"
+4 -1
View File
@@ -1,6 +1,8 @@
/* SOGo+DAV.h - this file is part of SOGo
*
* Copyright (C) 2010-2016 Inverse inc.
* Copyright (C) 2010 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -29,6 +31,7 @@
@interface SOGo (SOGoWebDAVExtensions)
- (WOResponse *) davPrincipalMatch: (WOContext *) localContext;
// - (WOResponse *) davPrincipalPropertySearch: (WOContext *) localContext;
- (WOResponse *) davPrincipalSearchPropertySet: (WOContext *) localContext;
@end
+30 -18
View File
@@ -1,6 +1,6 @@
/* SOGo+DAV.m - this file is part of SOGo
*
* Copyright (C) 2010-2016 Inverse inc.
* Copyright (C) 2010-2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,12 +18,18 @@
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/SoObject+SoDAV.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WORequest.h>
#import <NGExtensions/NSObject+Logs.h>
#import <DOM/DOMDocument.h>
#import <DOM/DOMNode.h>
#import <DOM/DOMProtocols.h>
#import <SaxObjC/XMLNamespaces.h>
#import <SOGo/NSArray+Utilities.h>
@@ -36,7 +42,6 @@
#import <SOGo/SOGoPermissions.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserFolder.h>
#import <SOGo/SOGoUserManager.h>
#import "SOGo+DAV.h"
@@ -179,8 +184,9 @@
[hrefs addObject: [self davURLAsString]];
}
- (NSDictionary *) _handlePrincipalMatchPrincipalProperty: (id <DOMElement>) child
inContext: (WOContext *) localContext
- (NSDictionary *)
_handlePrincipalMatchPrincipalProperty: (id <DOMElement>) child
inContext: (WOContext *) localContext
{
NSMutableArray *hrefs;
NSDictionary *response;
@@ -261,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])
@@ -359,26 +365,31 @@
withEmailAddressSetMatching: (NSString *) value
inContext: (WOContext *) localContext
{
SOGoUserManager *um;
id <SOGoSource> authenticationSource;
SOGoUser *activeUser;
NSArray *records;
NSUInteger count, max;
NSString *uid;
SOGoUserFolder *collection;
um = [SOGoUserManager sharedUserManager];
records = [um fetchUsersMatching: value
inDomain: [[localContext activeUser] domain]];
max = [records count];
for (count = 0; count < max; count++)
activeUser = [localContext activeUser];
if ([activeUser respondsToSelector: @selector (authenticationSource)])
{
uid = [[records objectAtIndex: count] objectForKey: @"c_uid"];
if ([uid length] > 0)
{
collection = [[SOGoUser userWithLogin: uid]
authenticationSource = [[localContext activeUser] authenticationSource];
records = [authenticationSource
fetchContactsMatching: value
inDomain: [activeUser domain]];
max = [records count];
for (count = 0; count < max; count++)
{
uid = [[records objectAtIndex: count] objectForKey: @"c_uid"];
if ([uid length] > 0)
{
collection = [[SOGoUser userWithLogin: uid]
homeFolderInContext: localContext];
[collections addObject: collection];
}
[collections addObject: collection];
}
}
}
}
@@ -574,6 +585,7 @@
@"addressbook", @"calendar-access",
@"calendar-schedule", @"calendar-auto-schedule",
@"calendar-proxy",
@"calendar-query-extended",
@"extended-mkcol",
@"calendarserver-principal-property-search",
+3 -1
View File
@@ -1,5 +1,6 @@
/*
Copyright (C) 2005-2016 Inverse inc.
Copyright (C) 2005-2010 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of SOGo.
@@ -26,6 +27,7 @@
@class NSArray;
@class NSDictionary;
@class NSMutableDictionary;
@class SOGoCache;
+39 -181
View File
@@ -1,5 +1,6 @@
/*
Copyright (C) 2005-2022 Inverse inc.
Copyright (C) 2005-2014 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of SOGo
@@ -19,15 +20,21 @@
02111-1307, USA.
*/
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSDebug.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDate.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSProcessInfo.h>
#import <Foundation/NSRunLoop.h>
#import <Foundation/NSURL.h>
#import <GDLAccess/EOAdaptorChannel.h>
#import <GDLContentStore/GCSChannelManager.h>
#import <GDLContentStore/GCSFolderManager.h>
#import <GDLContentStore/GCSFolderType.h>
#import <GDLContentStore/GCSAlarmsFolder.h>
#import <GDLContentStore/GCSSessionsFolder.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/SoClassSecurityInfo.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WORequest+So.h>
@@ -51,6 +58,7 @@
#import <SOGo/SOGoPublicBaseFolder.h>
#import <SOGo/SOGoProductLoader.h>
#import <SOGo/SOGoProxyAuthenticator.h>
#import <SOGo/SOGoUserFolder.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <SOGo/SOGoWebAuthenticator.h>
@@ -115,7 +123,7 @@ static BOOL debugLeaks;
vMemSizeLimit = [defaults vmemLimit];
if (vMemSizeLimit > 0)
[self logWithFormat: @"vmem size check enabled: shutting down app when "
@"vmem > %d MB. Currently at %d MB", vMemSizeLimit, [[NSProcessInfo processInfo] virtualMemorySize]/1048576];
@"vmem > %d MB", vMemSizeLimit];
/* SoClass security declarations */
sInfo = [self soClassSecurityInfo];
@@ -137,9 +145,7 @@ static BOOL debugLeaks;
[$(@"SOGoFolder") soClass];
/* load products */
[[SOGoProductLoader productLoader] loadAllProducts: YES];
if (vMemSizeLimit > 0)
[self logWithFormat: @"All products loaded - current memory usage at %d MB", [[NSProcessInfo processInfo] virtualMemorySize]/1048576];
[[SOGoProductLoader productLoader] loadAllProducts];
}
- (id) init
@@ -172,9 +178,10 @@ static BOOL debugLeaks;
bundle = [bm bundleWithName: @"MainUI" type: @"SOGo"];
length = [tableType length] - 3;
tableFile = [tableType substringToIndex: length];
descFile = [bundle pathForResource: [NSString stringWithFormat: @"%@-%@",
tableFile, fileSuffix]
ofType: @"sql"];
descFile
= [bundle pathForResource: [NSString stringWithFormat: @"%@-%@",
tableFile, fileSuffix]
ofType: @"sql"];
if (!descFile)
descFile = [bundle pathForResource: tableFile ofType: @"sql"];
@@ -190,7 +197,6 @@ static BOOL debugLeaks;
NSString *tableName, *fileSuffix, *tableScript;
EOAdaptorChannel *tc;
NSURL *channelURL;
NSException *ex;
channelURL = [NSURL URLWithString: url];
fileSuffix = [channelURL scheme];
@@ -199,19 +205,14 @@ static BOOL debugLeaks;
/* FIXME: make use of [EOChannelAdaptor describeTableNames] instead */
tableName = [url lastPathComponent];
if ([tc evaluateExpressionX:
[NSString stringWithFormat: @"SELECT 1 FROM %@ WHERE 1 = 2",
[NSString stringWithFormat: @"SELECT count(*) FROM %@",
tableName]])
{
// We re-acquire the channel in case it was abruptly closed between statements
if (![tc isOpen])
tc = [cm acquireOpenChannelForURL: channelURL];
tableScript = [self _sqlScriptForTable: tableName
withType: tableType
andFileSuffix: fileSuffix];
if (!(ex = [tc evaluateExpressionX: tableScript]))
if (![tc evaluateExpressionX: tableScript])
[self logWithFormat: @"table '%@' successfully created!", tableName];
else
[self logWithFormat: @"table '%@' creation failed! Reason: %@", tableName, ex];
}
else
[tc cancelFetch];
@@ -219,104 +220,40 @@ static BOOL debugLeaks;
[cm releaseChannel: tc];
}
- (void) _checkQuickTableWithTypeName: typeName
withCm: (GCSChannelManager *) cm
tableURL: (NSString *) url
{
NSString *tableName, *sql, *driver;
EOAdaptorChannel *channel;
GCSFolderType *type;
NSException *ex;
channel = [cm acquireOpenChannelForURL: [NSURL URLWithString: url]];
tableName = [NSString stringWithFormat: @"sogo_quick_%@", typeName];
driver = [url substringToIndex: [url rangeOfString: @":"].location];
sql = [NSString stringWithFormat: @"SELECT 1 FROM %@ WHERE 1 = 2",
tableName];
if ([channel evaluateExpressionX: sql])
{
type = [GCSFolderType folderTypeWithName: typeName driver: driver];
if (type)
{
sql = [type sqlQuickCreateWithTableName: tableName];
if (!(ex = [channel evaluateExpressionX: sql]))
[self logWithFormat: @"sogo quick table '%@' successfully created!",
tableName];
else
[self logWithFormat: @"sogo quick table '%@' creation failed! Reason: %@", tableName, ex];
}
}
else
[channel cancelFetch];
[cm releaseChannel:channel];
}
//
// If OCSStoreURL is defined, we also check for OCSAclURL, OCSCacheFolderURL
// and we create the combined quick tables.
//
- (BOOL) _checkMandatoryTables
{
GCSChannelManager *cm;
GCSFolderManager *fm;
NSArray *urlStrings;
NSArray *quickTypeStrings;
NSString *tmp, *value;
NSString *urlStrings[] = {@"SOGoProfileURL", @"OCSFolderInfoURL", nil};
NSString **urlString;
NSString *value;
SOGoSystemDefaults *defaults;
NSEnumerator *e;
BOOL ok, combined;
BOOL ok;
defaults = [SOGoSystemDefaults sharedSystemDefaults];
ok = YES;
if ([GCSFolderManager singleStoreMode])
{
urlStrings = [NSArray arrayWithObjects: @"SOGoProfileURL", @"OCSFolderInfoURL", @"OCSStoreURL", @"OCSAclURL", @"OCSCacheFolderURL", nil];
quickTypeStrings = [NSArray arrayWithObjects: @"contact", @"appointment", nil];
combined = YES;
}
else
{
urlStrings = [NSArray arrayWithObjects: @"SOGoProfileURL", @"OCSFolderInfoURL", nil];
combined = NO;
}
cm = [GCSChannelManager defaultChannelManager];
e = [urlStrings objectEnumerator];
while (ok && (tmp = [e nextObject]))
urlString = urlStrings;
while (ok && *urlString)
{
value = [defaults stringForKey: tmp];
value = [defaults stringForKey: *urlString];
if (value)
[self _checkTableWithCM: cm tableURL: value andType: tmp];
{
[self _checkTableWithCM: cm tableURL: value andType: *urlString];
urlString++;
}
else
{
[self errorWithFormat: @"No value specified for '%@'", tmp];
[self errorWithFormat: @"No value specified for '%@'", *urlString];
ok = NO;
}
}
if (combined)
{
e = [quickTypeStrings objectEnumerator];
while ((tmp = [e nextObject]))
{
[self _checkQuickTableWithTypeName: tmp
withCm: cm
tableURL: [defaults stringForKey: @"OCSFolderInfoURL"]];
}
}
if (ok)
{
fm = [GCSFolderManager defaultFolderManager];
// Create the sessions table
[[fm adminFolder] createFolderIfNotExists];
// Create the sessions table
[[fm sessionsFolder] createFolderIfNotExists];
@@ -352,10 +289,8 @@ static BOOL debugLeaks;
{
if ([[context request] handledByDefaultHandler])
authenticator = [SOGoWebAuthenticator sharedSOGoWebAuthenticator];
else {
else
authenticator = [SOGoDAVAuthenticator sharedSOGoDAVAuthenticator];
}
}
return authenticator;
@@ -368,16 +303,10 @@ static BOOL debugLeaks;
{
SOGoUser *user;
id userFolder;
NSData *decodedLogin;
NSString *login;
WORequest *request;
request = [_ctx request];
login = [SOGoUser getDecryptedUsernameIfNeeded: _key request: request];
user = [SOGoUser userWithLogin: login roles: nil];
user = [SOGoUser userWithLogin: _key roles: nil];
if (user)
userFolder = [$(@"SOGoUserFolder") objectWithName: login
userFolder = [$(@"SOGoUserFolder") objectWithName: _key
inContainer: self];
else
userFolder = nil;
@@ -440,12 +369,8 @@ static BOOL debugLeaks;
"GET" if no method was provided in the query path.
*/
if ([_key length] > 0 && ![_key isEqualToString:@"favicon.ico"])
{
obj = [self lookupUser: _key inContext: _ctx];
if (!obj && ![_key isEqualToString: @"public"])
obj = [self lookupUser: @"anonymous" inContext: _ctx];
}
}
obj = [self lookupUser: _key inContext: _ctx];
}
}
else
obj = nil;
@@ -471,19 +396,15 @@ static BOOL debugLeaks;
- (WOResponse *) handleException: (NSException *) _exc
inContext: (WOContext *) _ctx
{
WOResponse *resp;
NSLog(@"EXCEPTION: %s\n", [[_exc description] cString]);
resp = [WOResponse responseWithRequest: [_ctx request]];
[resp setStatus: 501];
return resp;
printf("EXCEPTION: %s\n", [[_exc description] cString]);
abort();
}
/* runtime maintenance */
- (void) checkIfDaemonHasToBeShutdown
{
unsigned long long vmem;
unsigned int vmem;
if (vMemSizeLimit > 0)
{
@@ -504,12 +425,8 @@ static BOOL debugLeaks;
{
static NSArray *runLoopModes = nil;
static BOOL debugOn = NO;
SOGoSystemDefaults *sd;
WOResponse *resp;
NSDate *startDate;
NSString *path;
NSTimeInterval timeDelta;
if (debugRequests)
@@ -519,7 +436,6 @@ static BOOL debugLeaks;
startDate = [NSDate date];
}
sd = [SOGoSystemDefaults sharedSystemDefaults];
cache = [SOGoCache sharedCache];
#ifdef GNUSTEP_BASE_LIBRARY
if (debugLeaks)
@@ -534,64 +450,6 @@ static BOOL debugLeaks;
}
#endif
// We check for rate-limiting settings - ignore anything actually
// sent to /SOGo/ (so unauthenticated requests).
path = [_request requestHandlerPath];
if ([path length] && [sd maximumRequestCount] > 0)
{
NSDictionary *requestCount;
NSString *username;
NSRange r;
r = [path rangeOfString: @"/"];
// We handle /sogo1/Calendar/.../ and "sogo1" as paths
if (r.length)
username = [path substringWithRange: NSMakeRange(0, r.location)];
else
username = path;
requestCount = [cache requestCountForLogin: username];
if (requestCount)
{
unsigned int current_time, start_time, delta, block_time, request_count;
current_time = [[NSCalendarDate date] timeIntervalSince1970];
start_time = [[requestCount objectForKey: @"InitialDate"] unsignedIntValue];
delta = current_time - start_time;
block_time = [sd requestBlockInterval];
request_count = [[requestCount objectForKey: @"RequestCount"] intValue];
if ( request_count >= [sd maximumRequestCount] &&
delta < [sd maximumRequestInterval] &&
delta <= block_time )
{
resp = [WOResponse responseWithRequest: _request];
[resp setStatus: 429];
return resp;
}
if (delta > block_time)
{
[cache setRequestCount: 1
forLogin: username
interval: current_time];
}
else
[cache setRequestCount: (request_count+1)
forLogin: username
interval: start_time];
}
else
{
[cache setRequestCount: 1
forLogin: username
interval: 0];
}
}
resp = [super dispatchRequest: _request];
[cache killCache];
+3 -10
View File
@@ -21,8 +21,10 @@
*/
#include <unistd.h>
#include <sys/types.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGObjWeb/SoApplication.h>
@@ -48,16 +50,7 @@ main (int argc, char **argv, char **env)
rc = 0;
sd = [SOGoSystemDefaults sharedSystemDefaults];
[NSTimeZone setDefaultTimeZone: [sd timeZone]];
//Check if sogo secret is set and correct
if([sd isSogoSecretSet] && ![sd sogoSecretValue])
{
rc =-1;
NSLog (@"Sogo secret is not correctly set");
}
else
{
WOWatchDogApplicationMain (@"SOGo", argc, (void *) argv);
}
WOWatchDogApplicationMain (@"SOGo", argc, (void *) argv);
}
else
{
+1723
View File
File diff suppressed because it is too large. Load diff
+674
View File
@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program 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 of the License, or
(at your option) any later version.
This program 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. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+191
View File
@@ -0,0 +1,191 @@
# GNUstep makefile
include ../config.make
include $(GNUSTEP_MAKEFILES)/common.make
include ../Version
BACKEND_VERSION = 1.0.0
### bootstrap library
MAPISTORESOGO = MAPIStoreSOGo
LIBRARY_NAME = $(MAPISTORESOGO)
$(MAPISTORESOGO)_VERSION = $(BACKEND_VERSION)
$(MAPISTORESOGO)_OBJC_FILES += \
MAPIStoreSOGo.m
### backend bundle
SOGOBACKEND = SOGoBackend
BUNDLE_NAME = $(SOGOBACKEND)
BUNDLE_EXTENSION = .MAPIStore
BUNDLE_INSTALL_DIR = $(SOGO_LIBDIR)
PYTHON = /usr/bin/python
PYTHON_IS_GOOD = $(shell $(PYTHON) -c 'from sys import version_info; a=version_info; print a[0] == 2 and a[1] >= 6')
ifeq (${PYTHON_IS_GOOD},False)
PYTHON = /usr/bin/python2.6
endif
all::
@echo " Python executable: ${PYTHON}"
SAMBA_PRIVATE_DIR = $(shell $(PYTHON) ./samba-get-config.py "private dir")
$(SOGOBACKEND)_PRINCIPAL_CLASS = MAPIApplication
$(SOGOBACKEND)_OBJC_FILES += \
MAPIApplication.m \
MAPIStoreActiveTables.m \
MAPIStoreAuthenticator.m \
MAPIStoreMapping.m \
MAPIStoreMIME.m \
MAPIStoreTypes.m \
MAPIStorePropertySelectors.m \
MAPIStoreSamDBUtils.m \
MAPIStoreUserContext.m \
\
SOGoMAPIDBMessage.m \
SOGoCacheGCSObject+MAPIStore.m \
\
MAPIStoreAppointmentWrapper.m \
MAPIStoreAttachment.m \
MAPIStoreAttachmentTable.m \
MAPIStoreContext.m \
MAPIStoreEmbeddedMessage.m \
MAPIStoreFolder.m \
MAPIStoreMessage.m \
MAPIStoreObject.m \
MAPIStoreObjectProxy.m \
MAPIStoreSOGoObject.m \
MAPIStoreTable.m \
MAPIStoreMessageTable.m \
MAPIStoreFolderTable.m \
MAPIStorePermissionsTable.m \
\
MAPIStoreDBBaseContext.m \
MAPIStoreDBFolder.m \
MAPIStoreDBFolderTable.m \
MAPIStoreDBMessage.m \
MAPIStoreDBMessageTable.m \
\
MAPIStoreFAIMessage.m \
MAPIStoreFAIMessageTable.m \
\
MAPIStoreGCSBaseContext.m \
MAPIStoreGCSFolder.m \
MAPIStoreGCSMessage.m \
MAPIStoreGCSMessageTable.m \
\
MAPIStoreCalendarAttachment.m \
MAPIStoreCalendarContext.m \
MAPIStoreCalendarFolder.m \
MAPIStoreCalendarMessage.m \
MAPIStoreCalendarEmbeddedMessage.m \
MAPIStoreCalendarMessageTable.m \
MAPIStoreRecurrenceUtils.m \
\
MAPIStoreContactsAttachment.m \
MAPIStoreContactsContext.m \
MAPIStoreContactsFolder.m \
MAPIStoreContactsMessage.m \
MAPIStoreContactsMessageTable.m \
\
MAPIStoreTasksContext.m \
MAPIStoreTasksFolder.m \
MAPIStoreTasksMessage.m \
MAPIStoreTasksMessageTable.m \
\
MAPIStoreMailAttachment.m \
MAPIStoreMailContext.m \
MAPIStoreMailFolder.m \
MAPIStoreMailMessage.m \
MAPIStoreMailVolatileMessage.m \
MAPIStoreMailMessageTable.m \
\
MAPIStoreNotesContext.m \
MAPIStoreNotesFolder.m \
MAPIStoreNotesMessage.m \
\
MAPIStoreFallbackContext.m \
\
NSArray+MAPIStore.m \
NSData+MAPIStore.m \
NSDate+MAPIStore.m \
NSObject+MAPIStore.m \
NSString+MAPIStore.m \
NSValue+MAPIStore.m \
\
iCalEvent+MAPIStore.m \
iCalTimeZone+MAPIStore.m \
\
RTFHandler.m
$(SOGOBACKEND)_RESOURCE_FILES += \
product.plist
### pl reader
PLREADER_TOOL = plreader
$(PLREADER_TOOL)_OBJC_FILES += \
plreader.m \
DBMSGREADER_TOOL = dbmsgreader
$(DBMSGREADER_TOOL)_OBJC_FILES += \
dbmsgreader.m \
NSObject+PropertyList.m
$(DBMSGREADER_TOOL)_LIB_DIRS += \
-L../SoObjects/SOGo/SOGo.framework/sogo -lSOGo \
-L../SOPE/GDLContentStore/obj/ -lGDLContentStore \
-L../SOPE/NGCards/obj/ -lNGCards \
-lNGObjWeb
TEST_TOOL_NAME += $(PLREADER_TOOL) $(DBMSGREADER_TOOL)
### cflags and libs
LIBMAPI_CFLAGS = $(shell pkg-config libmapi --cflags)
ifeq ($(LIBMAPI_CFLAGS),)
all install::
@echo "Cannot build the OpenChange SOGo backend (empty CFLAGS for libmapistore)"
else
SAMBA_LIB_DIR = $(shell pkg-config libmapistore --variable=libdir)
LIBMAPI_LIBS = $(shell pkg-config libmapi --libs)
LIBMAPISTORE_CFLAGS = $(shell pkg-config libmapistore --cflags) -DSAMBA_PREFIX="\"$(shell pkg-config libmapistore --variable=prefix)\""
LIBMAPISTORE_LIBS = $(shell pkg-config libmapistore --libs) -lmapiproxy -lWEExtensions
$(MAPISTORESOGO)_INSTALL_DIR = $(DESTDIR)/$(SAMBA_LIB_DIR)/mapistore_backends
$(MAPISTORESOGO)_LIB_DIRS += \
-L../SoObjects/SOGo/SOGo.framework/sogo/ -lSOGo -lgnustep-base -lobjc -lNGObjWeb \
$(LIBMAPI_LIBS) \
$(LIBMAPISTORE_LIBS)
$(SOGOBACKEND)_LIB_DIRS += \
-L../SoObjects/SOGo/SOGo.framework/sogo/ -lSOGo \
$(LIBMAPI_LIBS) \
$(LIBMAPISTORE_LIBS)
ADDITIONAL_INCLUDE_DIRS += \
-Werror -Wall \
-DSAMBA_PRIVATE_DIR=@"\"$(SAMBA_PRIVATE_DIR)\"" \
$(LIBMAPI_CFLAGS) \
$(LIBMAPISTORE_CFLAGS) \
-I../SoObjects -I../SOPE \
-DBACKEND_BUNDLE_NAME="@\"$(BUNDLE_NAME)$(BUNDLE_EXTENSION)\"" \
-DSOGO_BUNDLES_DIR="@\"$(BUNDLE_INSTALL_DIR)\""
ADDITIONAL_LDFLAGS += -Wl,--rpath,$(SOGO_SYSLIBDIR)/sogo
-include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/bundle.make
include $(GNUSTEP_MAKEFILES)/library.make
include $(GNUSTEP_MAKEFILES)/test-tool.make
include $(GNUSTEP_MAKEFILES)/aggregate.make
-include GNUmakefile.postamble
endif
+8
View File
@@ -0,0 +1,8 @@
all:: MAPIStorePropertySelectors.m MAPIStorePropertySelectors.h
MAPIStorePropertySelectors.m MAPIStorePropertySelectors.h: gen-property-selectors.py code-MAPIStorePropertySelectors.m code-MAPIStorePropertySelectors.h
@echo " Auto-generating MAPIStorePropertySelectors.[hm]..."
@$(PYTHON) ./gen-property-selectors.py -o MAPIStorePropertySelectors $(LIBMAPISTORE_CFLAGS)
distclean clean::
-rm -f MAPIStorePropertySelectors.m MAPIStorePropertySelectors.h
+43
View File
@@ -0,0 +1,43 @@
/* MAPIApplication.h - this file is part of SOGo
*
* Copyright (C) 2010-2012 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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 MAPIAPPLICATION_H
#define MAPIAPPLICATION_H
#import <NGObjWeb/SoApplication.h>
@class MAPIStoreUserContext;
@interface MAPIApplication : SoApplication
{
MAPIStoreUserContext *userContext;
}
- (id) authenticatorInContext: (id) context;
- (void) setUserContext: (MAPIStoreUserContext *) newContext;
@end
extern MAPIApplication *MAPIApp;
#endif /* MAPIAPPLICATION_H */
+91
View File
@@ -0,0 +1,91 @@
/* MAPIApplication.m - this file is part of SOGo
*
* Copyright (C) 2010 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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/NSUserDefaults.h>
#import <Foundation/NSTimeZone.h>
#import <WEExtensions/WEResourceManager.h>
#import <SOGo/SOGoProductLoader.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <Appointments/iCalEntityObject+SOGo.h>
#import "MAPIStoreUserContext.h"
#import "MAPIStoreTypes.h"
#import "MAPIApplication.h"
MAPIApplication *MAPIApp = nil;
@implementation MAPIApplication
+ (BOOL) isCachingEnabled;
{
return NO;
}
- (NSString *) name
{
return @"SOGo";
}
- (id) init
{
if (!MAPIApp)
{
WEResourceManager *rm;
// TODO publish
[iCalEntityObject initializeSOGoExtensions];
MAPIApp = [super init];
[MAPIApp retain];
rm = [[WEResourceManager alloc] init];
[self setResourceManager:rm];
[rm release];
utcTZ = [NSTimeZone timeZoneWithName: @"UTC"];
[utcTZ retain];
}
return MAPIApp;
}
- (BOOL) shouldSetupSignalHandlers
{
return NO;
}
- (void) setUserContext: (MAPIStoreUserContext *) newContext
{
/* user contexts must not be retained here ad their holder (mapistore)
contexts must be active when any operation occurs. */
userContext = newContext;
}
- (id) authenticatorInContext: (id) context
{
return [userContext authenticator];
}
@end
+47
View File
@@ -0,0 +1,47 @@
/* MAPIStoreActiveTables.h - this file is part of SOGo
*
* Copyright (C) 2011-2012 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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 MAPISTOREACTIVETABLES_H
#define MAPISTOREACTIVETABLES_H
#import <Foundation/NSObject.h>
@class NSMutableArray;
@class MAPIStoreTable;
@interface MAPIStoreActiveTables : NSObject
{
NSMutableArray *records;
}
+ (id) activeTables;
- (void) registerTable: (MAPIStoreTable *) table;
- (void) unregisterTable: (MAPIStoreTable *) table;
- (NSArray *) activeTablesForFMID: (uint64_t) fmid
andType: (uint8_t) tableType;
@end
#endif /* MAPISTOREACTIVETABLES_H */
+198
View File
@@ -0,0 +1,198 @@
/* MAPIStoreActiveTables.m - this file is part of SOGo
*
* Copyright (C) 2011-2012 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.
*/
/* MAPIStoreActiveTables provides an interface to keep accounting of all
instances of a given table, independently from its store and context.
Primary useful for notifications across different connections. */
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import "MAPIStoreFolder.h"
#import "MAPIStoreTable.h"
#import "MAPIStoreActiveTables.h"
@interface MAPIStoreActiveTableRecord : NSObject
{
uint64_t folderId;
uint8_t tableType;
MAPIStoreTable *table;
}
+ (id) recordForTable: (MAPIStoreTable *) newTable;
- (id) initWithTable: (MAPIStoreTable *) newTable;
- (MAPIStoreTable *) table;
- (BOOL) exactlyMatchesTable: (MAPIStoreTable *) otherTable;
- (BOOL) matchesFMID: (uint64_t) otherFMid
andTableType: (uint8_t) otherTableType;
- (BOOL) matchesTable: (MAPIStoreTable *) otherTable;
@end
@implementation MAPIStoreActiveTableRecord : NSObject
+ (id) recordForTable: (MAPIStoreTable *) newTable
{
MAPIStoreActiveTableRecord *record;
record = [[self alloc] initWithTable: newTable];
[record autorelease];
return record;
}
- (id) init
{
if ((self = [super init]))
{
folderId = 0;
tableType = 0;
table = nil;
}
return self;
}
- (id) initWithTable: (MAPIStoreTable *) newTable
{
if ((self = [self init]))
{
table = newTable;
folderId = [[table container] objectId];
tableType = [table tableType];
}
return self;
}
- (MAPIStoreTable *) table
{
return table;
}
- (BOOL) exactlyMatchesTable: (MAPIStoreTable *) otherTable
{
return (table == otherTable);
}
- (BOOL) matchesFMID: (uint64_t) otherFMid
andTableType: (uint8_t) otherTableType
{
return (tableType == otherTableType
&& folderId == otherFMid);
}
- (BOOL) matchesTable: (MAPIStoreTable *) otherTable
{
uint64_t otherFMid;
BOOL rc;
rc = [self exactlyMatchesTable: otherTable];
if (!rc)
{
otherFMid = [[otherTable container] objectId];
rc = [self matchesFMID: otherFMid andTableType: [otherTable tableType]];
}
return rc;
}
@end
@implementation MAPIStoreActiveTables
+ (id) activeTables
{
static MAPIStoreActiveTables *activeTables = nil;
if (!activeTables)
activeTables = [self new];
return activeTables;
}
- (id) init
{
if ((self = [super init]))
{
records = [NSMutableArray new];
}
return self;
}
- (void) dealloc
{
[records release];
[super dealloc];
}
- (void) registerTable: (MAPIStoreTable *) table
{
MAPIStoreActiveTableRecord *newRecord;
newRecord = [MAPIStoreActiveTableRecord recordForTable: table];
[records addObject: newRecord];
}
- (void) unregisterTable: (MAPIStoreTable *) table
{
MAPIStoreActiveTableRecord *currentRecord;
NSUInteger count, max;
BOOL done = NO;
max = [records count];
for (count = 0; !done && count < max; count++)
{
currentRecord = [records objectAtIndex: count];
if ([currentRecord exactlyMatchesTable: table])
{
[records removeObject: currentRecord];
done = YES;
}
}
}
- (NSArray *) activeTablesForFMID: (uint64_t) fmid
andType: (uint8_t) tableType
{
NSUInteger count, max;
NSMutableArray *tables;
MAPIStoreActiveTableRecord *currentRecord;
tables = [NSMutableArray arrayWithCapacity: 5];
max = [records count];
for (count = 0; count < max; count++)
{
currentRecord = [records objectAtIndex: count];
if ([currentRecord matchesFMID: fmid andTableType: tableType])
[tables addObject: [currentRecord table]];
}
return tables;
}
@end
Loaded 100 of 3465 files, more files were not shown because too many files have changed in this diff. Show more