Compare commits
177
Commits
SOGo-5.12.3
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be3630d009 | ||
|
|
6c93d6b66c | ||
|
|
aa7f82c09d | ||
|
|
c0a83f5c35 | ||
|
|
1bf1031ab2 | ||
|
|
012e6eff47 | ||
|
|
04a3e98238 | ||
|
|
3d9853e95b | ||
|
|
382118a93b | ||
|
|
3f4f949664 | ||
|
|
089b50c0de | ||
|
|
152f44b90e | ||
|
|
d089c4046f | ||
|
|
10dc173349 | ||
|
|
7ce69e3ea7 | ||
|
|
045a0b9c0a | ||
|
|
8813677ecb | ||
|
|
0d66d7503d | ||
|
|
f7fce46371 | ||
|
|
2a8f20e080 | ||
|
|
41e2b7b1ab | ||
|
|
f0c23407bf | ||
|
|
1caa25711f | ||
|
|
a156f4ce9f | ||
|
|
47133fdf3b | ||
|
|
78807d01ae | ||
|
|
aefc14b265 | ||
|
|
a99a848064 | ||
|
|
3a78a3bbb4 | ||
|
|
f11f34cdef | ||
|
|
39a35830e9 | ||
|
|
6904911ac1 | ||
|
|
fbd5bd19c6 | ||
|
|
97bbd7ed7f | ||
|
|
b5c83f5839 | ||
|
|
b978ceb020 | ||
|
|
d97472b93c | ||
|
|
d823cadda0 | ||
|
|
fd427f9196 | ||
|
|
b18f1a09f5 | ||
|
|
accc1c2302 | ||
|
|
6e590115fb | ||
|
|
c45233c11e | ||
|
|
27ad4ddbab | ||
|
|
e27b083213 | ||
|
|
be440baa23 | ||
|
|
28c4daa504 | ||
|
|
4e5c2516d4 | ||
|
|
baf26ae19d | ||
|
|
0cb21f8fb9 | ||
|
|
d7232618e6 | ||
|
|
93b82a0f60 | ||
|
|
2af96d10d5 | ||
|
|
29d0bbc9eb | ||
|
|
67ce01ec2a | ||
|
|
6119d6cf23 | ||
|
|
0ddc4281b8 | ||
|
|
b7641be5c8 | ||
|
|
d902756aaf | ||
|
|
f9b71059f4 | ||
|
|
ee2ebbb81c | ||
|
|
6f0b4f9d05 | ||
|
|
40228c619b | ||
|
|
d7f02b6083 | ||
|
|
453ddceae9 | ||
|
|
55d615e4dd | ||
|
|
1f7e5d2b2c | ||
|
|
f322fa2721 | ||
|
|
623f083cd9 | ||
|
|
7f7e1ad496 | ||
|
|
4f92da4971 | ||
|
|
1fdb4d3026 | ||
|
|
fbd056cc29 | ||
|
|
39b820a549 | ||
|
|
1be58da745 | ||
|
|
6ce884b3e7 | ||
|
|
4a587fe000 | ||
|
|
d993227b36 | ||
|
|
54e65233d9 | ||
|
|
2c2dbe4c61 | ||
|
|
d7e51655fb | ||
|
|
83d4c522f8 | ||
|
|
e821b20f87 | ||
|
|
dba92852f1 | ||
|
|
af984f58c0 | ||
|
|
71d865b86a | ||
|
|
3abbc31ed4 | ||
|
|
389e8e64c4 | ||
|
|
b46bf8b8dd | ||
|
|
7a09408ef8 | ||
|
|
95efe73e69 | ||
|
|
eb77a8e048 | ||
|
|
7876013a4c | ||
|
|
e9b3f2a43d | ||
|
|
47239ba0fd | ||
|
|
6f916008e9 | ||
|
|
16ab99e7cf | ||
|
|
bd0547fb73 | ||
|
|
03fa91dc22 | ||
|
|
e2b8494a9c | ||
|
|
d69f55c265 | ||
|
|
f8638a3f4e | ||
|
|
f18e3a05c3 | ||
|
|
6425a62e1a | ||
|
|
5021376daf | ||
|
|
8c38c9ce03 | ||
|
|
f86a32d0a1 | ||
|
|
2ebb63767e | ||
|
|
c755ab3b4e | ||
|
|
07e9d34865 | ||
|
|
645be8fcc5 | ||
|
|
0f24c17516 | ||
|
|
c675dbfaa7 | ||
|
|
dd367b0e94 | ||
|
|
1a80fd6284 | ||
|
|
ec4d7807d9 | ||
|
|
972ffcc0c6 | ||
|
|
3a442f1b3d | ||
|
|
eab6d9f249 | ||
|
|
3dc9b90992 | ||
|
|
798bed54e2 | ||
|
|
2b455fe587 | ||
|
|
ad7dc8f45e | ||
|
|
ed9121175a | ||
|
|
6514fbb8f1 | ||
|
|
9a295c5944 | ||
|
|
1bb74c7522 | ||
|
|
56e4929ca7 | ||
|
|
401e2f51cd | ||
|
|
799e8c21af | ||
|
|
070705acfa | ||
|
|
95e19379f6 | ||
|
|
f017fef4b2 | ||
|
|
a914fd4151 | ||
|
|
c0c506f910 | ||
|
|
b42882b564 | ||
|
|
ae293ec3ce | ||
|
|
e662f10389 | ||
|
|
c7a519ca12 | ||
|
|
22ab0b3c75 | ||
|
|
b77129e2e7 | ||
|
|
4585293d99 | ||
|
|
9d277c3f15 | ||
|
|
4461122697 | ||
|
|
b96e531f66 | ||
|
|
6c3e66142f | ||
|
|
16fcb46c4b | ||
|
|
f252e0e2c2 | ||
|
|
09d87b2d23 | ||
|
|
9e20190fad | ||
|
|
981748754a | ||
|
|
8d8ef5fd67 | ||
|
|
666c979eea | ||
|
|
1d59c616ac | ||
|
|
a7f7950d91 | ||
|
|
5d616600df | ||
|
|
a077512e34 | ||
|
|
23c8648169 | ||
|
|
9fad7e6f9c | ||
|
|
0fb3db0608 | ||
|
|
a7651e56c5 | ||
|
|
481a9bf1de | ||
|
|
f48f27c812 | ||
|
|
86d94ab8fe | ||
|
|
aba41a06b4 | ||
|
|
ed7a136e0f | ||
|
|
d99f020f82 | ||
|
|
244d1388eb | ||
|
|
dfcbbba514 | ||
|
|
7bee193413 | ||
|
|
4ef79e219c | ||
|
|
736d7589b1 | ||
|
|
4d8cca10f6 | ||
|
|
c8dd5535b3 | ||
|
|
42f620e562 | ||
|
|
3662846900 | ||
|
|
b9f6b90740 |
No files matched your search
@@ -15,9 +15,9 @@
|
||||
* *
|
||||
* **************************************************************************/
|
||||
|
||||
/* Database configuration (mysql://, postgresql:// or oracle://) */
|
||||
WOPort = "0.0.0.0:50000";
|
||||
|
||||
/* Database configuration (mysql://, postgresql:// or oracle://) */
|
||||
|
||||
// MySQL
|
||||
SOGoProfileURL = "mysql://sogobuild:sogo123@mariadb:3306/sogo/sogo_user_profile";
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[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, ko: Korean, th: Thai
|
||||
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, ko: Korean, th: Thai, el: Greek
|
||||
|
||||
[o:alinto:p:sogo:r:soobjects-appointments]
|
||||
source_file = SoObjects/Appointments/English.lproj/Localizable.strings
|
||||
|
||||
@@ -1627,7 +1627,7 @@ struct GlobalObjectId {
|
||||
|
||||
[map setObject: dateReceived forKey: @"date"];
|
||||
|
||||
messageId = [NSString generateMessageID];
|
||||
messageId = [NSString generateMessageID: [identity objectForKey: @"email"]];
|
||||
[map setObject: messageId forKey: @"message-id"];
|
||||
|
||||
attachmentKeys = [self fetchFileAttachmentKeys];
|
||||
|
||||
+217
@@ -2,6 +2,223 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [5.12.11](https://github.com/Alinto/sogo/compare/SOGo-5.12.10...SOGo-5.12.11) (2026-09-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **junk:** add junk action on mail view ([3f4f949](https://github.com/Alinto/sogo/commit/3f4f9496644953010a4a429f90eae733a50d61c4))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** keep the [@import](https://github.com/import) cleanup working in stringWithoutHTMLInjection ([8813677](https://github.com/Alinto/sogo/commit/8813677ecb171e5d27cd582989c1d87b308c6df3))
|
||||
* **db:** release db channel after using them ([152f44b](https://github.com/Alinto/sogo/commit/152f44b90e08013b5c132473a2de249682d997df))
|
||||
* **db:** release db channel after using them part 2 ([089b50c](https://github.com/Alinto/sogo/commit/089b50c0defdb48e8c0bc0a13334591f3ee2dd11))
|
||||
* **junk:** extend list of junk icon available ([012e6ef](https://github.com/Alinto/sogo/commit/012e6eff471893efaac033c69ddf7838ca51b791))
|
||||
* **mail:** escape mail data placed in attributes of a compiled part ([045a0b9](https://github.com/Alinto/sogo/commit/045a0b9c0ac57aeea1b619f281acff0427cd81c7)), closes [#115](https://bugs.sogo.nu/view.php?id=115)
|
||||
* **mail:** stop interpreting iMIP card text fields as markup ([0d66d75](https://github.com/Alinto/sogo/commit/0d66d7503d8fd147842e87b9b4f1b921986ef44b))
|
||||
* **pwd:** use the proper url for reset password mail ([382118a](https://github.com/Alinto/sogo/commit/382118a93b6925de2ce7f774abc1865ebea2dbba))
|
||||
* **pwd:** use the proper url for reset password mail part2 ([04a3e98](https://github.com/Alinto/sogo/commit/04a3e9823889acaf6c247b224f5f7a0108f8f829))
|
||||
* **sanitization:** update regex for html sanitization ([10dc173](https://github.com/Alinto/sogo/commit/10dc1733496fb2f393537d864d83408e357f2215))
|
||||
* **UI:** use legitimate sorting value ([d089c40](https://github.com/Alinto/sogo/commit/d089c4046ffac8124874c504491db9d1f15ae650))
|
||||
|
||||
|
||||
### Localization
|
||||
|
||||
* **hu:** Update Hungarian translations ([1bf1031](https://github.com/Alinto/sogo/commit/1bf1031ab2932f196f1adcc8fdfc9dea7dfb1f65))
|
||||
|
||||
## [5.12.10](https://github.com/Alinto/sogo/compare/SOGo-5.12.9...SOGo-5.12.10) (2026-08-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **sogo-tool:** add init-user command to create a user's personal folders and preferences without a login ([aefc14b](https://github.com/Alinto/sogo/commit/aefc14b265172e5ff94fa0fc1e4799f05d8e29f8))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bug:** escape angularJS only if needed to keep legitimate directive ([41e2b7b](https://github.com/Alinto/sogo/commit/41e2b7b1ab59fefe48cedf49ba82f4e03b646d23))
|
||||
* **bug:** incorrect method called ([1caa257](https://github.com/Alinto/sogo/commit/1caa25711f5891135c7ebca63f33b8758c00c8e8))
|
||||
* **calendar:** do not transmit og http status to external calendar ([3a78a3b](https://github.com/Alinto/sogo/commit/3a78a3bbb44484c95c141b0f3c0c8fabdc8bcf6a))
|
||||
* **ckeditor:** Sync resized image width/height into style and HTML attributes so Outlook and other mail clients ignoring CSS aspect-ratio render the correct dimensions. Closes [#6169](https://bugs.sogo.nu/view.php?id=6169). ([39a3583](https://github.com/Alinto/sogo/commit/39a35830e9d01a26b533515a20c1b4f527064519))
|
||||
* **dav:** properly parse MKCOL request ([78807d0](https://github.com/Alinto/sogo/commit/78807d01aee9195b95e2ed21344f260aadb2faef))
|
||||
* **event:** clean import of event ([b5c83f5](https://github.com/Alinto/sogo/commit/b5c83f58393e31151939d0d6fc227c0d0f127f33))
|
||||
* **event:** clean import of event ([b18f1a0](https://github.com/Alinto/sogo/commit/b18f1a09f59424a36f6de5aa7c30e6f27405c15d))
|
||||
* **mail:** escape angularJS directive for description ([47133fd](https://github.com/Alinto/sogo/commit/47133fdf3bc3148d374bbf413f058d714776e832))
|
||||
* **mail:** escape References/Organization/Newsgroups headers in HTML forward so message-id chevrons aren't parsed as HTML tags hiding the quoted body. Closes [#6046](https://bugs.sogo.nu/view.php?id=6046). ([f11f34c](https://github.com/Alinto/sogo/commit/f11f34cdefdd4175ae6c8b0814c2ccaecfd7c373))
|
||||
* **mail:** Some links broken in HTML rendering due to libxml2 (SOPE) only supporting HTML4 — when an anchor has no content between its opening and closing tags, store it and re-open it around the next element, closing </a> after that element's end tag. Closes [#5961](https://bugs.sogo.nu/view.php?id=5961). Closes [#6172](https://bugs.sogo.nu/view.php?id=6172). ([6904911](https://github.com/Alinto/sogo/commit/6904911ac17651de754246aff26fbb85aa8e01c7))
|
||||
* **passwordRecoveyr:** get the domain from the user mail ([a156f4c](https://github.com/Alinto/sogo/commit/a156f4ce9f0eda3ff54633d4bcb7051388d2f39b))
|
||||
* **tool:** wrong method called ([97bbd7e](https://github.com/Alinto/sogo/commit/97bbd7ed7f8173894f01b259f2f0f539ad6e95ed))
|
||||
|
||||
|
||||
### Localization
|
||||
|
||||
* **hu:** Update Hungarian translations ([2a8f20e](https://github.com/Alinto/sogo/commit/2a8f20e080cdb39544622874a12fef807cc66612))
|
||||
|
||||
### [5.12.9](https://github.com/Alinto/sogo/compare/SOGo-5.12.8...SOGo-5.12.9) (2026-05-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **mail:** do not encode non-html element ([6e59011](https://github.com/Alinto/sogo/commit/6e590115fbce073847369495997228fba2fc3ce8))
|
||||
* **mail:** render the subject without html when searching ([be440ba](https://github.com/Alinto/sogo/commit/be440baa23fd8b6ad5d8c947f60f9105ad717214))
|
||||
* **pref:** prevent onevent cleaning to remove legitimate words ([c45233c](https://github.com/Alinto/sogo/commit/c45233c11e250a22fa1e1f3e47fee2d6e232045b))
|
||||
|
||||
|
||||
### Localization
|
||||
|
||||
* **ca:** Update Catalan translations ([fd427f9](https://github.com/Alinto/sogo/commit/fd427f91967b99ca0d8eb42c4e5432f9ae4b49cf))
|
||||
* **es_ES:** Update SpanishSpain translations ([d823cad](https://github.com/Alinto/sogo/commit/d823cadda084e735c6dbeb2694f583bdf9fb7f9b))
|
||||
|
||||
### [5.12.8](https://github.com/Alinto/sogo/compare/SOGo-5.12.7...SOGo-5.12.8) (2026-05-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **acl:** fix folder path ([d902756](https://github.com/Alinto/sogo/commit/d902756aaf955a9ade6061806bb372e15b673197))
|
||||
* **acl:** only add existing uid ([f9b7105](https://github.com/Alinto/sogo/commit/f9b71059f4f382d7b337d16ce1257443ade43d02))
|
||||
* **css:** do not escape css if missing ([d723261](https://github.com/Alinto/sogo/commit/d7232618e6d6518acd148d3fafc5476d6a83aae1))
|
||||
* **mail:** correctly render mail when searching ([0cb21f8](https://github.com/Alinto/sogo/commit/0cb21f8fb95d3fcb5da5112e3dcf082fa7cb1fe3))
|
||||
* **mail:** remove negative margin from mail ([6119d6c](https://github.com/Alinto/sogo/commit/6119d6cf232cdf322b6c9d6d8beec7c8f47b8ad2))
|
||||
* **mail:** render properly the subject v2 ([29d0bbc](https://github.com/Alinto/sogo/commit/29d0bbc9eb96c2b4a0ada4d93eac79a66c789b22))
|
||||
* **mail:** sanitise mail with ics (invitation to event) ([67ce01e](https://github.com/Alinto/sogo/commit/67ce01ec2a1a7854d8e9f615dd65afb949043e86))
|
||||
* **openid:** check the userinfo mail + avoid infinite loop ([93b82a0](https://github.com/Alinto/sogo/commit/93b82a0f60ce5d8b0938e3f03d86baee8d075162))
|
||||
* **UI:** render properly the subject ([b7641be](https://github.com/Alinto/sogo/commit/b7641be5c80c0c02dc1b4742ce92e4de9a948b72))
|
||||
|
||||
|
||||
### Localization
|
||||
|
||||
* **pl:** Update Polish translations ([4e5c251](https://github.com/Alinto/sogo/commit/4e5c2516d43a3d80fad75f0a08c114ff3cb3eb03))
|
||||
|
||||
### [5.12.7](https://github.com/Alinto/sogo/compare/SOGo-5.12.6...SOGo-5.12.7) (2026-03-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **sql:** use proper sql adaptor for usr source ([1f7e5d2](https://github.com/Alinto/sogo/commit/1f7e5d2b2c2047c44a6a9e05f73c36491cb96d21))
|
||||
* **typo:** pass the correct arg to checkLogin ([d7f02b6](https://github.com/Alinto/sogo/commit/d7f02b6083197ecabc57c6e3c6f16a3bc23c68d0))
|
||||
|
||||
|
||||
### Localization
|
||||
|
||||
* **all:** update several translations ([40228c6](https://github.com/Alinto/sogo/commit/40228c619b6df02be4ed5e3f2e0b8d78d8cf15b2))
|
||||
* **fr:** Typo in French ([55d615e](https://github.com/Alinto/sogo/commit/55d615e4dd563bc31d82400b1bf110eed61248f6))
|
||||
|
||||
### [5.12.6](https://github.com/Alinto/sogo/compare/SOGo-5.12.6...SOGo-5.12.6) (2026-03-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **totp:** new user can properly use totp ([623f08](https://github.com/Alinto/sogo/commit/623f083cd94842766c6d9430cf3bdad8fc4d5dbc))
|
||||
|
||||
### [5.12.5](https://github.com/Alinto/sogo/compare/SOGo-5.12.4...SOGo-5.12.5) (2026-03-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **db:** increase some column size ([f8638a3](https://github.com/Alinto/sogo/commit/f8638a3f4edd3487901c119b079dea2a3746cd7c))
|
||||
* **encryptedUrl:** fix cache key data and expect uncrypted name for freebusy ([95efe73](https://github.com/Alinto/sogo/commit/95efe73e69abaae7fb8c1bdd0fe7ac660d59d7a4))
|
||||
* **event:** also add jitsi url in the location as outlook doesn't support attach url ([7876013](https://github.com/Alinto/sogo/commit/7876013a4c1b0c7a1ac7153f2c61ff5f3de39632))
|
||||
* **identity:** fix signatrue when changing identity ([71d865b](https://github.com/Alinto/sogo/commit/71d865b86a7c11dc6aa8612999ae515f14a3bdf2))
|
||||
* **login:** prevent user search for login keyword ([6f91600](https://github.com/Alinto/sogo/commit/6f916008e9e30bceaf5942e0c8645006d07d3aec))
|
||||
* **Mail:** correctly update quota when refreshing ([af984f5](https://github.com/Alinto/sogo/commit/af984f58c043cb7ddc8597f119c8a5b9737612b2))
|
||||
* **mail:** use the correct replyTo when set to a non*default identity ([03fa91d](https://github.com/Alinto/sogo/commit/03fa91dc22b268ce230f78e7386234ca84814f27))
|
||||
* **minsearch:** fix instance of minsearch ([d7e5165](https://github.com/Alinto/sogo/commit/d7e51655fb0a543cff68a9fbc10ceb67540e4bec))
|
||||
* **tool:** rename-user properly change data in c_defaults and c_settings ([d69f55c](https://github.com/Alinto/sogo/commit/d69f55c265e0e5873032d5e14e49636ed6c36631))
|
||||
* **trad:** typo in a transation key ([e2b8494](https://github.com/Alinto/sogo/commit/e2b8494a9cde046a8aad71808353366c328e0230))
|
||||
* **ui:** prevent UI to search for users with empty string ([389e8e6](https://github.com/Alinto/sogo/commit/389e8e64c4933edbcc1f756f422594e70d70c903))
|
||||
* **vulnerability:** prevent javascript njection with hint query ([e821b20](https://github.com/Alinto/sogo/commit/e821b20f87d1a9757f1d0aff7d1e31703f97054b))
|
||||
* **vulnerability:** prevent sogo to execute scripts pass in theme query ([16ab99e](https://github.com/Alinto/sogo/commit/16ab99e7cf8db2c30b211f0d5e338d7f9e3a9efb))
|
||||
* **vulnerability:** prevent xss with events, tasks and contacts categories ([e9b3f2a](https://github.com/Alinto/sogo/commit/e9b3f2a43d7557e8416f6749df4ab4f9128af2d1))
|
||||
* **vulnerability:** properly change the totp code after disabling it ([83d4c52](https://github.com/Alinto/sogo/commit/83d4c522f87cfde0ba543837d9b24c3479083ec2))
|
||||
|
||||
|
||||
### Localization
|
||||
|
||||
* **ca:** Update Catalan translations ([4a587fe](https://github.com/Alinto/sogo/commit/4a587fe00044bfce55186a7f75af64b5256399d7))
|
||||
* **es_ES:** Update SpanishSpain translations ([6ce884b](https://github.com/Alinto/sogo/commit/6ce884b3e71cc08c1e3eedb722be00ade6d1263f))
|
||||
* **pt_BR:** Update BrazilianPortuguese translations ([39b820a](https://github.com/Alinto/sogo/commit/39b820a5490eadbbadc6872f0814c23b7a6d4a13))
|
||||
* **pt:** Add Greek (partial) ([1fdb4d3](https://github.com/Alinto/sogo/commit/1fdb4d30261f5d69d83eef7d8615ef62ddd94a7e))
|
||||
* **pt:** Update Portuguese translations ([fbd056c](https://github.com/Alinto/sogo/commit/fbd056cc293a7c53f0ff0de4dd8a50a0d998291f))
|
||||
* **ru:** Update Russian translations ([1be58da](https://github.com/Alinto/sogo/commit/1be58da745b875aeb12096ac8fb8c51c6df99068))
|
||||
* **th:** Update Thai translations ([d993227](https://github.com/Alinto/sogo/commit/d993227b36b6fbddebf113a5b544aa3bebf01bcc))
|
||||
|
||||
## [5.12.4](https://github.com/Alinto/sogo/compare/SOGo-5.12.3...SOGo-5.13.0) (2025-10-06)
|
||||
|
||||
|
||||
### Enhancements
|
||||
|
||||
* **mail:** Add a setting to show the attachments above the mail body ([5d61660](https://github.com/Alinto/sogo/commit/5d616600dfa6258e4eebcb5c065e393ebfae8f3a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **calendar:** fetch our own iana timezone instead of trusting VTIMEZONE ([244d138](https://github.com/Alinto/sogo/commit/244d1388eb00c060c5302e5bfd997fd397820bc0))
|
||||
* **curl:** properly close curl connection ([42f620e](https://github.com/Alinto/sogo/commit/42f620e56201e17391532507c02ae370f117c574))
|
||||
* **eas:** use proper imap mech for EAS request when using openid ([a7f7950](https://github.com/Alinto/sogo/commit/a7f7950d91c83acd75c0b0d55dec74ab85d38d6c))
|
||||
* **ldap:** don't try to fetch for a nobody user ([4d8cca1](https://github.com/Alinto/sogo/commit/4d8cca10f63aff9499b71d61d59d6f81570eb659))
|
||||
* **label:** ensure the translation kept is not null ([0fb3db0](https://github.com/Alinto/sogo/commit/0fb3db060871a14e2abd8c6963ccd812cbacf200))
|
||||
* **label:** missing trad ([23c8648](https://github.com/Alinto/sogo/commit/23c8648169b4893aaafa2e369259d94d56c76831))
|
||||
* **ldap:** fetch the correct user source when creating an event with an attendee ([736d758](https://github.com/Alinto/sogo/commit/736d7589b16be4ebcf9fc6931a79187888c3b444))
|
||||
* **login:** Only remember the login if the auth was successful ([9e20190](https://github.com/Alinto/sogo/commit/9e20190fad1a437f7e1307f0adcfe19a8d45184c))
|
||||
* **log:** remove the ics from the log line ([86d94ab](https://github.com/Alinto/sogo/commit/86d94ab8fefaf3aa5ba99e13c28a0b24036d94ff))
|
||||
* **mailer:** correctly show interline for p element ([666c979](https://github.com/Alinto/sogo/commit/666c979eeae6d51a6bc09684ebbab57ed9ce4b91))
|
||||
* **mailer:** don't add mailto: to string starting with @ ([9817487](https://github.com/Alinto/sogo/commit/981748754a4857bab66a6fb94cdc5da4265ce003))
|
||||
* **mail:** preoperly generates the message-id header value ([7bee193](https://github.com/Alinto/sogo/commit/7bee193413935ca03e4936a15791fbbb534493ec))
|
||||
* **openid:** correcly type userTokenInterval ([4ef79e2](https://github.com/Alinto/sogo/commit/4ef79e219c289697eec0c2d100c8af1a5d0889b6))
|
||||
* **password:** Correctly check the secret question answer when hitting enter instead of the button next ([ed7a136](https://github.com/Alinto/sogo/commit/ed7a136e0f2c5ecd35033aef6d0561d9fcf2ccdc))
|
||||
* **task:** fix reminder for tasks ([a7651e5](https://github.com/Alinto/sogo/commit/a7651e56c53a4dc33892d86f404a132a2b8af83a))
|
||||
* **ui:** add css class for login page ([a077512](https://github.com/Alinto/sogo/commit/a077512e34bf42933457b92613b348ff2e06642a))
|
||||
* **calendar:** don't allocate and copy all children for each time we call _filterComponent: ([481a9bf](https://github.com/Alinto/sogo/commit/481a9bf1de1da8e07b5ed4c1786aac89d19ca6c3))
|
||||
* **core:** store translations in a globally static NSMutableDictionary ([f48f27c](https://github.com/Alinto/sogo/commit/f48f27c812466ce806ab60b43ebe5a2bfc97ed0a))
|
||||
|
||||
### Localization
|
||||
|
||||
* **ar:** Update Arabic translations ([6c3e661](https://github.com/Alinto/sogo/commit/6c3e66142f50c68ee9b1435e5d6961573e7445d4))
|
||||
* **bg_BG:** Update Bulgarian translations ([4585293](https://github.com/Alinto/sogo/commit/4585293d999152e6c7b54f00f73f925051a4ed64))
|
||||
* **bs_BA:** Update Bosnian translations ([4461122](https://github.com/Alinto/sogo/commit/446112269705ae1565a21d3e39e4665c172fc3d4))
|
||||
* **ca:** Update Catalan translations ([b77129e](https://github.com/Alinto/sogo/commit/b77129e2e7608f163eeeb1c4ed7e35fb5558c3cb))
|
||||
* **cs:** Update Czech translations ([f252e0e](https://github.com/Alinto/sogo/commit/f252e0e2c271118cceb2979a828f5220350ba57f))
|
||||
* **cy:** Update Welsh translations ([6425a62](https://github.com/Alinto/sogo/commit/6425a62e1ab8900dc83df5ca165eb92718856886))
|
||||
* **da_DK:** Update Danish translations ([ae293ec](https://github.com/Alinto/sogo/commit/ae293ec3ce7488530199e82bd7bde50b2d506a43))
|
||||
* **de:** Update German translations ([95e1937](https://github.com/Alinto/sogo/commit/95e19379f6fa698f54a09d7b7bcb4cfe16b4c358))
|
||||
* **es_AR:** Update SpanishArgentina translations ([07e9d34](https://github.com/Alinto/sogo/commit/07e9d34865e57fa64f8db1b7ed4a5a67a0c1f234))
|
||||
* **es_ES:** Update SpanishSpain translations ([c755ab3](https://github.com/Alinto/sogo/commit/c755ab3b4ea5ecad2c98d396d6bca6d873d0f1de))
|
||||
* **eu:** Update Basque translations ([b96e531](https://github.com/Alinto/sogo/commit/b96e531f662a41802bd83e54e4a8055987d36164))
|
||||
* **fi:** Update Finnish translations ([c0c506f](https://github.com/Alinto/sogo/commit/c0c506f9103b12ed5a39b340c4bccac500a2f6a8))
|
||||
* **fr:** Update French translations ([a914fd4](https://github.com/Alinto/sogo/commit/a914fd4151e5565d4f168819c2664dc460587dec))
|
||||
* **gl:** Update Galician translations ([f017fef](https://github.com/Alinto/sogo/commit/f017fef4b2a86f210f36bd5e62afe37c7bba3a18))
|
||||
* **he:** Update Hebrew translations ([070705a](https://github.com/Alinto/sogo/commit/070705acfaa65ad435c1d2fa659e4b1f333b59a8))
|
||||
* **hr_HR:** Update Croatian translations ([e662f10](https://github.com/Alinto/sogo/commit/e662f10389795e281abd283775f0d168a519e25d))
|
||||
* **hu:** Update Hungarian translations ([799e8c2](https://github.com/Alinto/sogo/commit/799e8c21af79b2a8beb082a9d56a238aee30ae4a))
|
||||
* **id_ID:** Update Indonesian translations ([56e4929](https://github.com/Alinto/sogo/commit/56e4929ca78c105dde470a6d26749b1328fad47f))
|
||||
* **is:** Update Icelandic translations ([401e2f5](https://github.com/Alinto/sogo/commit/401e2f51cd3a69afa72fb76ffeb8fc91a5779cca))
|
||||
* **it:** Update Italian translations ([1bb74c7](https://github.com/Alinto/sogo/commit/1bb74c75227f858d680035a5eccd7c5ef954f869))
|
||||
* **ja:** Update Japanese translations ([9a295c5](https://github.com/Alinto/sogo/commit/9a295c5944886df95b941f716fc5e6b4c62525b7))
|
||||
* **kk:** Update Kazakh translations ([6514fbb](https://github.com/Alinto/sogo/commit/6514fbb8f1c2745dd44be49c72da88937fcf107f))
|
||||
* **ko:** Update Korean translations ([ed91211](https://github.com/Alinto/sogo/commit/ed9121175aa6164a73987a247cebe47e53676529))
|
||||
* **lt:** Update Lithuanian translations ([2b455fe](https://github.com/Alinto/sogo/commit/2b455fe587f96700c4398538b995680251660ac1))
|
||||
* **lv:** Update Latvian translations ([ad7dc8f](https://github.com/Alinto/sogo/commit/ad7dc8f45ee316c4d39ebf5fa71207947b4be2f8))
|
||||
* **mk_MK:** Update Macedonian translations ([798bed5](https://github.com/Alinto/sogo/commit/798bed54e2eb0f76f26dc6c6c423285c565b9888))
|
||||
* **nb_NO:** Update NorwegianBokmal translations ([eab6d9f](https://github.com/Alinto/sogo/commit/eab6d9f2492eccc2397c3ad49ab284223cb8771c))
|
||||
* **nl:** Update Dutch translations ([b42882b](https://github.com/Alinto/sogo/commit/b42882b564ad9aa1b510b00d06da21688d959785))
|
||||
* **nn_NO:** Update NorwegianNynorsk translations ([3a442f1](https://github.com/Alinto/sogo/commit/3a442f1b3d38350a5544f0fb62718f45b70c37ad))
|
||||
* **pl:** Update Polish translations ([16fcb46](https://github.com/Alinto/sogo/commit/16fcb46c4be26497d12be712c5bacf0f0056a5b3))
|
||||
* **pt_BR:** Update BrazilianPortuguese translations ([9d277c3](https://github.com/Alinto/sogo/commit/9d277c3f157e21183648609e5bee429559e87a63))
|
||||
* **pt:** Update Portuguese translations ([972ffcc](https://github.com/Alinto/sogo/commit/972ffcc0c6f4f67da5557da28b6c5af87d632b96))
|
||||
* **ro_RO:** Update Romanian translations ([ec4d780](https://github.com/Alinto/sogo/commit/ec4d7807d994836218c6ba9c5979283623a520d4))
|
||||
* **ru:** Update Russian translations ([1a80fd6](https://github.com/Alinto/sogo/commit/1a80fd6284750cc9997e6cbbafcdf86765032405))
|
||||
* **sk:** Update Slovak translations ([0f24c17](https://github.com/Alinto/sogo/commit/0f24c175163e2a000d6cace4d9302cae384f3b49))
|
||||
* **sl_SI:** Update Slovenian translations ([645be8f](https://github.com/Alinto/sogo/commit/645be8fcc53cd2729dad9906e66a8f630cffaf52))
|
||||
* **sr_ME@latin:** Update Montenegrin translations ([3dc9b90](https://github.com/Alinto/sogo/commit/3dc9b9099223940ec4a4f660d499ac450398d6cc))
|
||||
* **sr@latin:** Update SerbianLatin translations ([c675dbf](https://github.com/Alinto/sogo/commit/c675dbfaa70755abf4300462f538dfa878c7c969))
|
||||
* **sr:** Update Serbian translations ([dd367b0](https://github.com/Alinto/sogo/commit/dd367b0e94b74dccfc862d9ca07906cc16234965))
|
||||
* **sv:** Update Swedish translations ([2ebb637](https://github.com/Alinto/sogo/commit/2ebb63767e53c39bc982d9959dabacfdce8b9b19))
|
||||
* **th:** Update Thai translations ([f86a32d](https://github.com/Alinto/sogo/commit/f86a32d0a148b8465a01f098855dc58470c1a689))
|
||||
* **tr_TR:** Update TurkishTurkey translations ([8c38c9c](https://github.com/Alinto/sogo/commit/8c38c9ce038e902d4b79f2093448ffec2c1f1d55))
|
||||
* **uk:** Update Ukrainian translations ([5021376](https://github.com/Alinto/sogo/commit/5021376daf92c95a69afa2a2d99cf559f858d478))
|
||||
* **zh_CN:** Update ChineseChina translations ([22ab0b3](https://github.com/Alinto/sogo/commit/22ab0b3c751f7c20c234c1824552aaa4c661f983))
|
||||
* **zh_TW:** Update ChineseTaiwan translations ([c7a519c](https://github.com/Alinto/sogo/commit/c7a519ca124121e259a00473e6163cbd93e16aa4))
|
||||
|
||||
### [5.12.3](https://github.com/Alinto/sogo/compare/SOGo-5.12.2...SOGo-5.12.3) (2025-07-12)
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
Installation and Configuration Guide
|
||||
====================================
|
||||
= Installation and Configuration Guide
|
||||
////
|
||||
|
||||
This file is part of the SOGo project.
|
||||
@@ -10,8 +9,8 @@ Installation and Configuration Guide
|
||||
////
|
||||
include::includes/global-attributes.asciidoc[]
|
||||
|
||||
About this Guide
|
||||
----------------
|
||||
|
||||
== About this Guide
|
||||
|
||||
This guide will walk you through the installation and configuration of
|
||||
the SOGo solution. It also covers the installation and configuration of
|
||||
@@ -23,8 +22,8 @@ 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
|
||||
------------
|
||||
|
||||
== Introduction
|
||||
|
||||
SOGo is a free and modern scalable groupware server. It offers shared
|
||||
calendars, address books, and emails through your favourite Web browser
|
||||
@@ -48,8 +47,8 @@ device, or Outlook 2013/2016
|
||||
SOGo is developed by a community of developers located mainly in North
|
||||
America and Europe. More information can be found at https://sogo.nu/
|
||||
|
||||
Architecture and Compatibility
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Architecture and Compatibility
|
||||
|
||||
image::images/architecture.png[System Architecture, 400, 964]
|
||||
|
||||
@@ -61,11 +60,11 @@ protocol are also supported.
|
||||
To install and configure the Outlook CalDav Synchronizer, please refer
|
||||
to the _Outlook Connector Configuration Guide_.
|
||||
|
||||
System Requirements
|
||||
-------------------
|
||||
|
||||
Assumptions
|
||||
~~~~~~~~~~~
|
||||
== System Requirements
|
||||
|
||||
|
||||
=== Assumptions
|
||||
|
||||
SOGo reuses many components in an infrastructure. Thus, it requires the
|
||||
following:
|
||||
@@ -73,7 +72,7 @@ following:
|
||||
* Database server (MariaDB, MySQL, PostgreSQL or Oracle)
|
||||
* LDAP server (OpenLDAP, Novell eDirectory, Microsoft Active Directory
|
||||
and others)
|
||||
* SMTP server (Postfix, Sendmail and others)
|
||||
* SMTP server (Postfix)
|
||||
* IMAP server (Courier, Cyrus IMAP Server, Dovecot and others)
|
||||
|
||||
If you plan to use ActiveSync, an IMAP server supporting the ACL,
|
||||
@@ -104,8 +103,8 @@ components, together with version numbers:
|
||||
|
||||
More recent versions of the software mentioned above can also be used.
|
||||
|
||||
Minimum Hardware Requirements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Minimum Hardware Requirements
|
||||
|
||||
The following table provides hardware recommendations for the server,
|
||||
desktops and mobile devices:
|
||||
@@ -157,8 +156,8 @@ Linux
|
||||
Microsoft ActiveSync.
|
||||
|=======================================================================
|
||||
|
||||
Operating System Requirements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Operating System Requirements
|
||||
|
||||
The following operating systems are currently supported by SOGo:
|
||||
|
||||
@@ -182,16 +181,16 @@ directly to the SOGo website at https://sogo.nu/faq/installation.html.
|
||||
Note that once the SOGo packages are installed under Debian and Ubuntu,
|
||||
this guide can be followed in order to fully configure SOGo.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
== Installation
|
||||
|
||||
This section will guide you through the installation of SOGo together
|
||||
with its dependencies. The steps described here apply to an RPM-based
|
||||
installation for a Red Hat or CentOS 7 distribution. Most of these steps
|
||||
should apply to all supported operating systems.
|
||||
|
||||
Software Downloads
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Software Downloads
|
||||
|
||||
**In order to access the community build, go to https://www.sogo.nu/download.html[SOGo website]
|
||||
and select "Development (nightly builds)" at the bottom of the page.**
|
||||
@@ -255,8 +254,8 @@ sed -i '/enabled=1/a exclude=gnustep* ytnef*' /etc/yum.repos.d/epel.repo
|
||||
|
||||
For more information on EPEL, visit http://fedoraproject.org/wiki/EPEL/.
|
||||
|
||||
Software Installation
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Software Installation
|
||||
|
||||
Once the yum configuration file has been created, you are now ready to
|
||||
install SOGo and its dependencies. To do so, proceed with the following
|
||||
@@ -276,8 +275,8 @@ for Oracle. The installation command will thus look like this:
|
||||
Once completed, SOGo will be fully installed on your server. You are now
|
||||
ready to configure it.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
== Configuration
|
||||
|
||||
In this section, you'll learn how to configure SOGo to use your existing
|
||||
LDAP, SMTP and database servers. As previously mentioned, we assume that
|
||||
@@ -285,8 +284,8 @@ those components run on the same server on which SOGo is being
|
||||
installed. If this is not the case, please adjust the configuration
|
||||
parameters to reflect those changes.
|
||||
|
||||
GNUstep Environment Overview
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== GNUstep Environment Overview
|
||||
|
||||
SOGo makes use of the GNUstep environment. GNUstep is a free software
|
||||
implementation of the OpenStep specification which provides many
|
||||
@@ -319,8 +318,8 @@ wrapped within curly brackets `{ [configuration] }`. If SOGo refuses to
|
||||
start due to syntax errors in its configuration file, `plparse` is helpful
|
||||
for finding these, as it indicates the line containing the problem.
|
||||
|
||||
Preferences Hierarchy
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Preferences Hierarchy
|
||||
|
||||
SOGo supports domain names segregation, meaning that you can separate
|
||||
multiple groups of users within one installation of SOGo. A user
|
||||
@@ -350,8 +349,8 @@ following abbreviations in the tables of this document:
|
||||
Remember that the hierarchy paradigm allow the default value of a
|
||||
parameter to be defined at a parent level.
|
||||
|
||||
General Preferences
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== General Preferences
|
||||
|
||||
The following table describes the general parameters that can be set:
|
||||
|
||||
@@ -841,6 +840,16 @@ Obiously, if your users can connect without specifying a domain, let this parame
|
||||
|S |SOGoPasswordRecoveryEnabled
|
||||
|Boolean enable password recovery with secret question or secondary e-mail. Default value is `NO`.
|
||||
|
||||
|S |SOGoPasswordRecoveryBaseURLs
|
||||
| *Since 5.12.11*. List of allowed base URL for password reset link.
|
||||
|
||||
`SOGoPasswordRecoveryBaseURLs = ("https://demo.sogo.nu");`
|
||||
`SOGoPasswordRecoveryBaseURLs = ("https://platform1.sogo.nu", "https://platform2.sogo.nu);`
|
||||
|
||||
Do not end the URLs by '/'.
|
||||
|
||||
No defaults, will throw an error if empty or unset.
|
||||
|
||||
|S |SOGoPasswordRecoveryDomains
|
||||
|List of domains where password recovery is enabled, for example `(example.org, example.net)`. If empty array `()`, disabled for all domains. If not set, enabled for all domains.
|
||||
|
||||
@@ -879,8 +888,8 @@ Obiously, if your users can connect without specifying a domain, let this parame
|
||||
|
||||
[[Secret-for-sensitive-data]]
|
||||
|
||||
Secret for sensitive data
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Secret for sensitive data
|
||||
|
||||
_Since 5.10_
|
||||
|
||||
@@ -974,8 +983,7 @@ sogo-tool user-preferences unset default <user> AuxiliaryMailAccounts
|
||||
user being the full mail address or just the username if domainless. After that, the user will have to set its auxiliary accounts again.
|
||||
|
||||
|
||||
Authentication using LDAP
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== Authentication using LDAP
|
||||
|
||||
SOGo can use a LDAP server to authenticate users and, if desired, to
|
||||
provide global address books. SOGo can also use an SQL backend for this
|
||||
@@ -1385,8 +1393,8 @@ Defaults to `NO` when unset.
|
||||
|
||||
|=======================================================================
|
||||
|
||||
LDAP Attributes Indexing
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== LDAP Attributes Indexing
|
||||
|
||||
To ensure proper performance of the SOGo application, the following LDAP
|
||||
attributes must be fully indexed:
|
||||
@@ -1402,8 +1410,8 @@ attributes must be fully indexed:
|
||||
Please refer to the documentation of the software you use in order to
|
||||
index those attributes.
|
||||
|
||||
LDAP Attributes Mapping
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== LDAP Attributes Mapping
|
||||
|
||||
Some LDAP attributes are mapped to contacts attributes in the SOGo UI.
|
||||
The table below list most of them. It is possible to override these by
|
||||
@@ -1463,8 +1471,8 @@ mapping = {
|
||||
|Photo |photo
|
||||
|===
|
||||
|
||||
Authenticating using C.A.S.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Authenticating using C.A.S.
|
||||
|
||||
SOGo natively supports C.A.S. authentication. For activating C.A.S.
|
||||
authentication you need first to make sure that the
|
||||
@@ -1568,9 +1576,7 @@ connection properly.
|
||||
|
||||
|
||||
[[openid-section]]
|
||||
|
||||
Authenticating using OPENID
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== Authenticating using OPENID
|
||||
|
||||
SOGo natively supports OPENID authentication. For activating OpenId authentication you need first to make sure that
|
||||
_SOGoAuthenticationType_ is set to `openid`,
|
||||
@@ -1643,8 +1649,8 @@ the session will stays in the table and be useless. That's why a new sogo-tool c
|
||||
You can put it in a cron to do that periodicly. +
|
||||
See _<<sogo-tool-clean-openid-sessions,sogo-tool clean-openid-sessions>>_.
|
||||
|
||||
Authenticating using SAML2
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Authenticating using SAML2
|
||||
|
||||
SOGo natively supports SAML2 authentication. Please refer to the documentation of your identity
|
||||
provider and the SAML2 configuration keys that are listed above for proper setup. Once a SOGo
|
||||
@@ -1677,8 +1683,7 @@ _NGImap4AuthMechanism_ is configured to use the `SAML` mechanism. If you
|
||||
make use of the CrudeSAML PAM plugin, this value may be left empty.
|
||||
|
||||
|
||||
Database Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== Database Configuration
|
||||
|
||||
SOGo requires a relational database system in order to store
|
||||
appointments, tasks and contacts information. It also uses the database
|
||||
@@ -1925,10 +1930,9 @@ calendar.
|
||||
|
||||
Ensure the computer used for the test has emoji fonts installed.
|
||||
|
||||
[[Authentication-using-SQL]]
|
||||
|
||||
Authentication using SQL
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
[[Authentication-using-SQL]]
|
||||
=== Authentication using SQL
|
||||
|
||||
SOGo can use a SQL-based database server for authentication. The
|
||||
configuration is very similar to LDAP-based authentication.
|
||||
@@ -2165,8 +2169,8 @@ or username@domain.tld
|
||||
Note that groups are currently not supported for SQL-based
|
||||
authentication sources.
|
||||
|
||||
SMTP Server Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== SMTP Server Configuration
|
||||
|
||||
SOGo makes use of a SMTP server to send emails from the Web interface,
|
||||
iMIP/iTIP messages and various notifications.
|
||||
@@ -2180,7 +2184,6 @@ The following table describes the related parameters.
|
||||
are:
|
||||
|
||||
[options="compact"]
|
||||
* `sendmail` - to use the sendmail binary
|
||||
* `smtp` - to use the SMTP protocol
|
||||
|
||||
|D |SOGoSMTPServer
|
||||
@@ -2208,10 +2211,6 @@ Current, Are supported `PLAIN` and 'xoauth2' for openid.
|
||||
|D |SOGoSMTPMasterUserPassword
|
||||
|SMTP account password for master account (`SOGoSMTPMasterUserEnabled` enabled).
|
||||
|
||||
|S |WOSendMail
|
||||
|The path of the sendmail binary.
|
||||
|
||||
Defaults to `/usr/lib/sendmail`.
|
||||
|
||||
|D |SOGoForceExternalLoginWithEmail
|
||||
|Parameter used to specify if, when logging in to the SMTP server, the
|
||||
@@ -2225,8 +2224,8 @@ Possible values are:
|
||||
Defaults to `NO` when unset.
|
||||
|=======================================================================
|
||||
|
||||
IMAP Server Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== IMAP Server Configuration
|
||||
|
||||
SOGo requires an IMAP server in order to let users consult their email
|
||||
messages, manage their folders and more.
|
||||
@@ -2394,8 +2393,8 @@ permissions for the individual user.
|
||||
The default prefix is `$`.
|
||||
|=======================================================================
|
||||
|
||||
Web Interface Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Web Interface Configuration
|
||||
|
||||
The following additional parameters only affect the Web interface
|
||||
behaviour of SOGo.
|
||||
@@ -2897,13 +2896,27 @@ SOGoMailJunkSettings = {
|
||||
};
|
||||
----
|
||||
|
||||
|D |mailJunkIcon
|
||||
|Choose the Junk icon. Values are :
|
||||
https://materialui.co/icon/thumb-down[thumb_down],
|
||||
https://materialui.co/icon/gpp-bad[gpp_bad],
|
||||
https://materialui.co/icon/local-fire-department[local_fire_department],
|
||||
https://materialui.co/icon/bug-report[bug_report],
|
||||
https://materialui.co/icon/error[error],
|
||||
https://materialui.co/icon/warning[warning],
|
||||
https://materialui.co/icon/dangerous[dangerous] and
|
||||
https://materialui.co/icon/report-gmailerrorred[report_gmailerrorred].
|
||||
|
||||
|
||||
Defaults to `thumb_down`.
|
||||
|
||||
|D |SOGoMailKeepDraftsAfterSend
|
||||
|Parameter used to keep mails in the drafts folder once they have been
|
||||
sent by SOGo. Defaults to `NO` when unset.
|
||||
|=======================================================================
|
||||
|
||||
SOGo Configuration Summary
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== SOGo Configuration Summary
|
||||
|
||||
The complete SOGo configuration file `/etc/sogo/sogo.conf` should look
|
||||
like this:
|
||||
@@ -2951,10 +2964,9 @@ like this:
|
||||
}
|
||||
----
|
||||
|
||||
[[multi-domains-configuration]]
|
||||
|
||||
Multi-domains Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
[[multi-domains-configuration]]
|
||||
=== Multi-domains Configuration
|
||||
|
||||
If you want your installation to isolate two groups of users, you must
|
||||
define a distinct authentication source for each _domain_. Your domain keys
|
||||
@@ -3050,8 +3062,8 @@ Defaults to an empty array, which means domains are isolated from each
|
||||
other.
|
||||
|=======================================================================
|
||||
|
||||
Apache Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Apache Configuration
|
||||
|
||||
The SOGo configuration for Apache is located in
|
||||
`/etc/httpd/conf.d/SOGo.conf`.
|
||||
@@ -3080,8 +3092,8 @@ The default configuration will use `mod_proxy` and `mod_headers` to
|
||||
relay requests to the `sogod` parent process. This is suitable for small
|
||||
to medium deployments.
|
||||
|
||||
Starting Services
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Starting Services
|
||||
|
||||
Once SOGo if fully installed and configured, start the services using
|
||||
the following command:
|
||||
@@ -3097,8 +3109,8 @@ modules and configuration files were added:
|
||||
Finally, you should also make sure that the `memcached` service is
|
||||
started and that it is also automatically started at boot time.
|
||||
|
||||
_Cronjob_ — EMail reminders
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== _Cronjob_ — EMail reminders
|
||||
|
||||
SOGo allows you to set email-based reminders for events and tasks. To
|
||||
enable this, you must enable the `SOGoEnableEMailAlarms` preference and
|
||||
@@ -3125,8 +3137,8 @@ SOGoSMTPMasterUserUsername = "foo";
|
||||
SOGoSMTPMasterUserPassword = "bar";
|
||||
```
|
||||
|
||||
_Cronjob_ — Vacation messages activation and expiration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== _Cronjob_ — Vacation messages activation and expiration
|
||||
|
||||
When vacation messages are enabled (see the parameter
|
||||
_SOGoVacationEnabled_), users can set an activation or expiration date
|
||||
@@ -3147,8 +3159,8 @@ The _cronjob_ should look like this:
|
||||
0 0 * * * sogo /usr/sbin/sogo-tool update-autoreply -p /etc/sogo/sieve.creds
|
||||
----
|
||||
|
||||
_Password_ — Force user password change at login
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== _Password_ — Force user password change at login
|
||||
|
||||
The following commands force user to change his password at login :
|
||||
|
||||
@@ -3162,11 +3174,11 @@ Disable :
|
||||
/usr/sbin/sogo-tool user-preferences unset settings [USER] ForceResetPassword
|
||||
----
|
||||
|
||||
Managing User Accounts
|
||||
----------------------
|
||||
|
||||
Creating the SOGo Administrative Account
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
== Managing User Accounts
|
||||
|
||||
|
||||
=== Creating the SOGo Administrative Account
|
||||
|
||||
First, create the SOGo administrative account in your LDAP server. The
|
||||
following LDIF file (`sogo.ldif`) can be used as an example:
|
||||
@@ -3193,8 +3205,8 @@ administrative account using the following command:
|
||||
|
||||
ldappasswd -h 127.0.0.1 -x -w qwerty -D cn=Manager,dc=acme,dc=com uid=sogo,ou=users,dc=acme,dc=com -s qwerty
|
||||
|
||||
Creating a User Account
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Creating a User Account
|
||||
|
||||
SOGo uses LDAP directories to authenticate users. Use the following LDIF
|
||||
file (`jdoe.ldif`) as an example to create a SOGo user account:
|
||||
@@ -3227,8 +3239,8 @@ easier. These GUI utilities can make use of templates to create and
|
||||
pre-configure typical user accounts or any standardized LDAP record,
|
||||
along with the correct object classes, fields and default values.
|
||||
|
||||
Microsoft Enterprise ActiveSync
|
||||
-------------------------------
|
||||
|
||||
=== Microsoft Enterprise ActiveSync
|
||||
|
||||
SOGo supports the Microsoft ActiveSync protocol.
|
||||
|
||||
@@ -3364,8 +3376,8 @@ and send an email to iplicreq@microsoft.com
|
||||
Alinto provides this software for free, but is not responsible for
|
||||
anything related to its usage.
|
||||
|
||||
Microsoft Enterprise ActiveSync Tuning
|
||||
--------------------------------------
|
||||
|
||||
== Microsoft Enterprise ActiveSync Tuning
|
||||
|
||||
First of all, it is important to know that most EAS devices will keep
|
||||
HTTP connections open to SOGo (and thus, Apache) for a long time. This
|
||||
@@ -3440,8 +3452,8 @@ SOGoMaximumSyncInterval = 3540;
|
||||
SOGoInternalSyncInterval = 60;
|
||||
----
|
||||
|
||||
S/MIME Support in SOGo
|
||||
----------------------
|
||||
|
||||
== S/MIME Support in SOGo
|
||||
|
||||
SOGo supports S/MIME email signing and encryption. When receiving
|
||||
S/MIME signed emails, SOGo automatically extracts the PKCS (Public-Key
|
||||
@@ -3459,11 +3471,10 @@ please have a look at Actalis:
|
||||
https://www.actalis.it/products/certificates-for-secure-electronic-mail.aspx
|
||||
|
||||
|
||||
Using SOGo
|
||||
----------
|
||||
== Using SOGo
|
||||
|
||||
SOGo Web Interface
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== SOGo Web Interface
|
||||
|
||||
To acces the SOGo Web Interface, point your Web browser, which is
|
||||
running from the same server where SOGo was installed, to the following
|
||||
@@ -3472,8 +3483,8 @@ URL: http://127.0.0.1/SOGo.
|
||||
Log in using the "jdoe" user and the "qwerty" password. The underlying
|
||||
database tables will automatically be created by SOGo.
|
||||
|
||||
Mozilla Thunderbird and Lightning
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Mozilla Thunderbird and Lightning
|
||||
|
||||
Alternatively, you can access SOGo with a GroupDAV and a CalDAV client.
|
||||
A typical well-integrated setup is to use Mozilla Thunderbird and
|
||||
@@ -3515,8 +3526,8 @@ To access your personal calendar:
|
||||
`http://127.0.0.1/SOGo/dav/jdoe/Calendar/personal/`
|
||||
* Click on Continue.
|
||||
|
||||
Apple Calendar (macOS, iOS, iPadOS)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Apple Calendar (macOS, iOS, iPadOS)
|
||||
|
||||
Apple Calendar on macOS, iOS, and iPadOS can also be used
|
||||
as a client application for SOGo.
|
||||
@@ -3534,8 +3545,8 @@ You have to add the profile to your device :
|
||||
* Go to Settings / Profiles / Click on + / Continue
|
||||
* Type your SOGo account password and click on install
|
||||
|
||||
Apple AddressBook
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Apple AddressBook
|
||||
|
||||
Since Mac OS X 10.6 (Snow Leopard), Apple AddressBook can be configured
|
||||
to use SOGo.
|
||||
@@ -3583,8 +3594,8 @@ You have to add the profile to your device :
|
||||
* Go to Settings / Profiles / Click on + / Continue
|
||||
* Type your SOGo account password and click on install
|
||||
|
||||
Microsoft ActiveSync
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Microsoft ActiveSync
|
||||
|
||||
You can synchronize contacts, emails, events and tasks from SOGo with
|
||||
any mobile devices that support Microsoft ActiveSync. Microsoft Outlook
|
||||
@@ -3593,8 +3604,9 @@ any mobile devices that support Microsoft ActiveSync. Microsoft Outlook
|
||||
The Microsoft ActiveSync server URL is generally something
|
||||
like: `http://127.0.0.1/Microsoft-Server-ActiveSync`.
|
||||
|
||||
Using sogo-tool
|
||||
---------------
|
||||
|
||||
== Using sogo-tool
|
||||
|
||||
The command _sogo-tool_ allows to do some operations on database and sieve filter. It is included with
|
||||
the sogo package on Debian/Ubuntu but must be installed manually on RHEl/CentOS:
|
||||
|
||||
@@ -3603,8 +3615,8 @@ the sogo package on Debian/Ubuntu but must be installed manually on RHEl/CentOS:
|
||||
*_WARNING_: Use sogo-tool with full awareness of what you are doing. This is an admin tool that can cause loss of data
|
||||
or completely make the webmail unusable by a user.*
|
||||
|
||||
sogo-tool backup/restore
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool backup/restore
|
||||
|
||||
The backup tool saves the information of a user into a file. The information saved are its preferences, its events and its contacts.
|
||||
|
||||
@@ -3685,8 +3697,8 @@ sogo-tool restore -F "Contacts/personal" tmp/backup user1
|
||||
sogo-tool restore -F "Calendar/60C8-65323D80-7-4D9F7D80" tmp/backup user1
|
||||
----
|
||||
|
||||
sogo-tool checkup
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool checkup
|
||||
|
||||
Check the events and contacts data's integrity of a user
|
||||
|
||||
@@ -3717,8 +3729,8 @@ sogo-tool checkup -d user1
|
||||
|
||||
[[sogo-tool-clean-openid-sessions]]
|
||||
|
||||
sogo-tool clean-openid-sessions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool clean-openid-sessions
|
||||
|
||||
Obviously only usefull if you have set SOGo with openId authentication.
|
||||
Will clean all expired openId sessions from the database.
|
||||
@@ -3730,8 +3742,8 @@ Example:
|
||||
sogo-tool clean-openid-sessions
|
||||
----
|
||||
|
||||
sogo-tool cleanup
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool cleanup
|
||||
|
||||
Will purge all user's deleted events and contacts which the deletion is older than a number of days.
|
||||
|
||||
@@ -3755,8 +3767,7 @@ Purged 5 records from folder /Users/user2/Calendar/personal
|
||||
----
|
||||
|
||||
|
||||
sogo-tool create-folder
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== sogo-tool create-folder
|
||||
|
||||
Create a folder (Calendar or Address Book) for a user.
|
||||
|
||||
@@ -3773,8 +3784,31 @@ sogo-tool create-folder user2 Calendar Pro_Calendar
|
||||
----
|
||||
|
||||
|
||||
sogo-tool dump-defaults
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== sogo-tool init-user
|
||||
|
||||
Create the personal calendar and the personal address book of one or more users, and initialize
|
||||
their preferences. Those folders and preferences are otherwise only created upon the user's first
|
||||
login, which prevents any operation on them (setting ACLs or reading the user's preferences from a
|
||||
provisioning tool, for instance) beforehand.
|
||||
|
||||
The resulting preferences are the same as the ones a login through the web interface would produce.
|
||||
|
||||
init-user [-l language] user1 [user2] ...
|
||||
|
||||
* *user* is the name of the user
|
||||
* *language* is the language of the user's preferences, as it would be chosen at login. When
|
||||
omitted, the language of the domain or of the system is used. The categories and labels stored in
|
||||
the preferences are localized accordingly.
|
||||
|
||||
Example:
|
||||
----
|
||||
sogo-tool init-user user1
|
||||
sogo-tool init-user user1 user2
|
||||
sogo-tool init-user -l French user1
|
||||
----
|
||||
|
||||
|
||||
=== sogo-tool dump-defaults
|
||||
|
||||
Output all current defaults value of GNUstep and SOGo (sogo.conf)
|
||||
|
||||
@@ -3791,8 +3825,8 @@ sogo-tool dump-defaults all
|
||||
sogo-tool dump-defaults -f /tmp/foo/conf.xml
|
||||
----
|
||||
|
||||
sogo-tool expire-sessions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool expire-sessions
|
||||
|
||||
Expires user sessions from database without activity for specified number of minutes. When a user log in to sogo for
|
||||
the first time, sogo will create a entry in database's table OCSSessionsFolderURL with the user's information. Sogo will
|
||||
@@ -3811,8 +3845,8 @@ sogo-tool expire-sessions 160 #Will remove session which last activity is ol
|
||||
sogo-tool expire-sessions 0 #Will remove session which last activity is older than 0 minutes.
|
||||
----
|
||||
|
||||
sogo-tool manage-acl
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool manage-acl
|
||||
|
||||
Manage access-control list (ACL) of a user for folders (Calendar and Address Book).
|
||||
|
||||
@@ -3883,8 +3917,8 @@ Example:
|
||||
sogo-tool manage-acl unsubscribe sogo-tests1 Contacts/5E1D-653FC400-1-1A330C40 sogo-tests2
|
||||
----
|
||||
|
||||
sogo-tool manage-eas
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool manage-eas
|
||||
|
||||
Manage EAS folders
|
||||
|
||||
@@ -3914,8 +3948,8 @@ sogo-tool manage-eas mergevcard janedow androidc316986417 YES
|
||||
sogo-tool manage-eas mergevevent janedow androidc316986417 YES
|
||||
----
|
||||
|
||||
sogo-tool remove
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool remove
|
||||
|
||||
Remove all folders (Calendar and Address Book) and Preference settings of a user. The personal Calendar and Address Book
|
||||
will stay but be emptied of all entries. The Preferences will go back to defaults values as for a new user.
|
||||
@@ -3939,8 +3973,8 @@ Deleting /Users/user2/Contacts/B087-65363400-7-374DA380
|
||||
Deleting /Users/user2/Contacts/personal
|
||||
----
|
||||
|
||||
sogo-tool remove-doubles
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool remove-doubles
|
||||
|
||||
remove duplicate contacts from the specified user addressbook
|
||||
|
||||
@@ -3965,8 +3999,8 @@ sogo-tool remove-doubles user1 personal
|
||||
sogo-tool remove-doubles user2 489-65376E80-1-2D2BA000
|
||||
----
|
||||
|
||||
sogo-tool rename-user
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool rename-user
|
||||
|
||||
Update records pertaining to a user after a change of user id. Will change all folders path, subscriptions from others users,
|
||||
all mention of user id in database.
|
||||
@@ -3984,8 +4018,8 @@ Example:
|
||||
sogo-tool rename-user old_username new_username
|
||||
----
|
||||
|
||||
sogo-tool truncate-calendar
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool truncate-calendar
|
||||
|
||||
Remove old calendar entries from the specified user calendar.
|
||||
|
||||
@@ -4015,8 +4049,7 @@ Removing 1 records...
|
||||
Removed 1 records.
|
||||
----
|
||||
|
||||
sogo-tool update-autoreply
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== sogo-tool update-autoreply
|
||||
|
||||
_This command is only useful if your sieve server doesn't have the capabilities *date* or *relational*_
|
||||
In that case this command will check vacation's setting of all the users. If vacation is enabled/disabled,
|
||||
@@ -4036,8 +4069,7 @@ Example:
|
||||
[[sogo-tool-update-secret]]
|
||||
|
||||
|
||||
sogo-tool update-secret
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== sogo-tool update-secret
|
||||
|
||||
_New in 5.10_
|
||||
|
||||
@@ -4063,8 +4095,7 @@ If your data are already encrypted with 'oldSecret' but you want to decrypt them
|
||||
sogo-tool update-secret -o oldSecret
|
||||
----
|
||||
|
||||
sogo-tool user-preferences
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== sogo-tool user-preferences
|
||||
|
||||
Get, set or unset user defaults / settings in the database.
|
||||
|
||||
@@ -4123,8 +4154,7 @@ sogo-tool user-preferences set defaults user1 Forward -f /path/filename -p cred
|
||||
----
|
||||
|
||||
|
||||
API REST
|
||||
--------
|
||||
== API REST
|
||||
|
||||
Starting from 5.12.2, an API with two endpoints is available.
|
||||
All response will be on json format. In case of errors, the message will be:
|
||||
@@ -4133,8 +4163,7 @@ All response will be on json format. In case of errors, the message will be:
|
||||
```
|
||||
with an explicit message
|
||||
|
||||
API server url
|
||||
~~~~~~~~~~~~~~
|
||||
=== API server url
|
||||
|
||||
_<scheme>_://_<domain>_/SOGo/SOGoAPI/_<action>_
|
||||
|
||||
@@ -4142,8 +4171,7 @@ _<scheme>_://_<domain>_/SOGo/SOGoAPI/_<action>_
|
||||
• *domain* : domain or ip:port of SOGo's server
|
||||
• *action* : name of the action. No action does the Version action described below.
|
||||
|
||||
Authentication
|
||||
~~~~~~~~~~~~~~
|
||||
=== Authentication
|
||||
|
||||
Somes actions needs to be authenticated. There is two ways to do so:
|
||||
|
||||
@@ -4165,8 +4193,8 @@ Add a header *Auhtorization* with value:
|
||||
|
||||
*acces_token* is from the https://connect2id.com/products/server/docs/api/token#url[openid protocol]. It has to be fetch with the scope `openid`.
|
||||
|
||||
Action - Version
|
||||
~~~~~~~~~~~~~~~~
|
||||
=== Action - Version
|
||||
|
||||
* *URL*: <scheme>://<domain>/SOGo/SOGoAPI/Version
|
||||
* *Authentication needed*: NO
|
||||
* *HTTP method allowed*: GET
|
||||
@@ -4180,8 +4208,8 @@ Action - Version
|
||||
}
|
||||
```
|
||||
|
||||
Action - UserFolder
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
=== Action - UserFolder
|
||||
|
||||
* *URL*: <scheme>://<domain>/SOGo/SOGoAPI/UserFolder
|
||||
* *Authentication needed*: YES
|
||||
* *HTTP method allowed*: GET
|
||||
@@ -4225,8 +4253,7 @@ A folder info is a dict with:
|
||||
** *name*: Name of the folder.
|
||||
** *url*: Dav link of the folder.
|
||||
|
||||
Errors and messages
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
=== Errors and messages
|
||||
|
||||
Complete http response is `{“error:” : <message>}`.
|
||||
*<action>* is the one used for the request: `<scheme>://<domain>/SOGo/SOGoAPI/<action>`
|
||||
@@ -4273,8 +4300,7 @@ To have more logs you can add `SOGoAPIDebugEnabled = YES;` to your sogo.conf.
|
||||
|
||||
|
||||
|
||||
Upgrading
|
||||
---------
|
||||
== Upgrading
|
||||
|
||||
This section describes what needs to be done when upgrading to the
|
||||
current version of SOGo from the previous release.
|
||||
@@ -4282,6 +4308,9 @@ current version of SOGo from the previous release.
|
||||
[cols="100a"]
|
||||
|=======================================================================
|
||||
|
||||
h|5.12.11
|
||||
|If you enable Password Recovery, new mandatory settings `SOGoPasswordRecoveryBaseURLs`
|
||||
|
||||
h|5.11
|
||||
|Parameters `SOGoGlobalAddressBookFirstEntries` and `SOGoGlobalAddressBookFirstEntriesCount` has been removed. Please use `listRequiresDot` and `globalAddressBookFirstEntriesCount` instead. Signature are now between a div tag to avoid CKEditor changing the content - set `SOGoForceRawHtmlSignature` to `NO` to leave signature (https://bugs.sogo.nu/view.php?id=5920).
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
////
|
||||
|
||||
Additional Information
|
||||
----------------------
|
||||
|
||||
== Additional Information
|
||||
|
||||
For more information, please consult the online FAQs (Frequently Asked
|
||||
Questions) :
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
|
||||
////
|
||||
|
||||
Commercial Support and Contact Information
|
||||
------------------------------------------
|
||||
== Commercial Support and Contact Information
|
||||
|
||||
For any questions or comments, do not hesitate to contact us by writing
|
||||
an email to contact@sogo.nu.
|
||||
|
||||
+1
-1
@@ -380,7 +380,7 @@ static BOOL debugLeaks;
|
||||
|
||||
request = [_ctx request];
|
||||
login = [SOGoUser getDecryptedUsernameIfNeeded: _key request: request];
|
||||
if([login isEqualToString: @"changeLanguage"])
|
||||
if([login isEqualToString: @"changeLanguage"] || [login isEqualToString: @"login"])
|
||||
user = nil;
|
||||
else
|
||||
{
|
||||
|
||||
@@ -32,10 +32,12 @@
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import <GDLAccess/EOAdaptorContext.h>
|
||||
#import <GDLAccess/EOAdaptor.h>
|
||||
#import <NGExtensions/NGResourceLocator.h>
|
||||
|
||||
#import "GCSChannelManager.h"
|
||||
#import "EOAdaptorChannel+GCS.h"
|
||||
#import "EOQualifier+GCS.h"
|
||||
#import "GCSAlarmsFolder.h"
|
||||
#import "GCSAdminFolder.h"
|
||||
#import "GCSOpenIdFolder.h"
|
||||
@@ -383,21 +385,12 @@ static BOOL _singleStoreMode = NO;
|
||||
return [[self channelManager] canConnect:[self folderInfoLocation]];
|
||||
}
|
||||
|
||||
- (NSArray *)performSQL:(NSString *)_sql {
|
||||
EOAdaptorChannel *channel;
|
||||
- (NSArray *)performSQL:(NSString *)_sql withChannel: (EOAdaptorChannel*) channel{
|
||||
NSException *ex;
|
||||
NSMutableArray *rows;
|
||||
NSDictionary *row;
|
||||
NSArray *attrs;
|
||||
|
||||
/* acquire channel */
|
||||
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
if (debugOn) [self debugWithFormat:@"could not acquire channel!"];
|
||||
return nil;
|
||||
}
|
||||
if (debugOn) [self debugWithFormat:@"acquired channel: %@", channel];
|
||||
|
||||
/* run SQL */
|
||||
|
||||
if ((ex = [channel evaluateExpressionX:_sql]) != nil) {
|
||||
@@ -513,9 +506,12 @@ static BOOL _singleStoreMode = NO;
|
||||
|
||||
- (NSString *)generateSQLWhereForInternalNames:(NSArray *)_names
|
||||
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
|
||||
withChannel: (EOAdaptorChannel*) channel
|
||||
{
|
||||
/* generates a WHERE qualifier for matching the "quick" entries */
|
||||
NSMutableString *sql;
|
||||
EOAdaptorContext *adaptorContext;
|
||||
EOAdaptor *adaptor;
|
||||
unsigned i, count;
|
||||
|
||||
if ((count = [_names count]) == 0) {
|
||||
@@ -523,10 +519,13 @@ static BOOL _singleStoreMode = NO;
|
||||
__PRETTY_FUNCTION__];
|
||||
return @"1 = 2";
|
||||
}
|
||||
|
||||
sql = [NSMutableString stringWithCapacity:(count * 8)];
|
||||
|
||||
adaptorContext = [channel adaptorContext];
|
||||
adaptor = [adaptorContext adaptor];
|
||||
sql = [NSMutableString stringWithString:@""];
|
||||
for (i = 0; i < quickPathCount; i++) {
|
||||
NSString *pathColumn;
|
||||
EOQualifier *qualifier;
|
||||
char buf[32];
|
||||
|
||||
sprintf(buf, GCSPathColumnPattern, (i + 1));
|
||||
@@ -537,8 +536,11 @@ static BOOL _singleStoreMode = NO;
|
||||
if (i < count) {
|
||||
/* exact match, regular column */
|
||||
if ([sql length] > 0) [sql appendString:@" AND "];
|
||||
[sql appendString:pathColumn];
|
||||
[sql appendFormat:@" = '%@'", [_names objectAtIndex:i]];
|
||||
|
||||
qualifier = [[EOKeyValueQualifier alloc] initWithKey: pathColumn
|
||||
operatorSelector: EOQualifierOperatorEqual
|
||||
value: [_names objectAtIndex:i]];
|
||||
[qualifier appendSQLToString: sql withAdaptor: adaptor];
|
||||
}
|
||||
else if (_beExact) {
|
||||
/* exact match, ensure that all additional quick-cols are NULL */
|
||||
@@ -569,9 +571,12 @@ static BOOL _singleStoreMode = NO;
|
||||
}
|
||||
|
||||
if (_beExact && (count > quickPathCount)) {
|
||||
[sql appendString:@" AND c_foldername = '"];
|
||||
[sql appendString:[_names lastObject]];
|
||||
[sql appendString:@"'"];
|
||||
EOQualifier *qualifier;
|
||||
[sql appendString:@" AND "];
|
||||
qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_foldername"
|
||||
operatorSelector: EOQualifierOperatorEqual
|
||||
value: [_names lastObject]];
|
||||
[qualifier appendSQLToString: sql withAdaptor: adaptor];
|
||||
}
|
||||
|
||||
return sql;
|
||||
@@ -579,13 +584,15 @@ static BOOL _singleStoreMode = NO;
|
||||
|
||||
- (NSString *)generateSQLPathFetchForInternalNames:(NSArray *)_names
|
||||
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
|
||||
withChannel: (EOAdaptorChannel*) channel
|
||||
{
|
||||
/* fetches the 'path' subset for a given quick-names */
|
||||
NSMutableString *sql;
|
||||
NSString *ws;
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:_names
|
||||
exactMatch:_beExact orDirectSubfolderMatch:_directSubs];
|
||||
exactMatch:_beExact orDirectSubfolderMatch:_directSubs
|
||||
withChannel: channel];
|
||||
if ([ws length] == 0)
|
||||
return nil;
|
||||
|
||||
@@ -600,13 +607,15 @@ static BOOL _singleStoreMode = NO;
|
||||
|
||||
- (NSString *)generateSQLPathAndNameFetchForInternalNames:(NSArray *)_names
|
||||
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
|
||||
withChannel: (EOAdaptorChannel*) channel
|
||||
{
|
||||
/* fetches the 'path' subset for a given quick-names */
|
||||
NSMutableString *sql;
|
||||
NSString *ws;
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:_names
|
||||
exactMatch:_beExact orDirectSubfolderMatch:_directSubs];
|
||||
exactMatch:_beExact orDirectSubfolderMatch:_directSubs
|
||||
withChannel: channel];
|
||||
if ([ws length] == 0)
|
||||
return nil;
|
||||
|
||||
@@ -726,6 +735,7 @@ static BOOL _singleStoreMode = NO;
|
||||
NSString *fname, *sname, *sql;
|
||||
NSArray *fnames, *records;
|
||||
unsigned int count;
|
||||
EOAdaptorChannel* channel;
|
||||
NSDictionary *record;
|
||||
BOOL result;
|
||||
|
||||
@@ -733,36 +743,41 @@ static BOOL _singleStoreMode = NO;
|
||||
|
||||
fnames = [self internalNamesFromPath: _path];
|
||||
if (fnames)
|
||||
{
|
||||
sql = [self generateSQLPathFetchForInternalNames: fnames
|
||||
exactMatch: YES
|
||||
orDirectSubfolderMatch: NO];
|
||||
if ([sql length])
|
||||
{
|
||||
records = [self performSQL: sql];
|
||||
if (records)
|
||||
{
|
||||
count = [records count];
|
||||
if (count)
|
||||
{
|
||||
fname = [self internalNameFromPath: _path];
|
||||
if (count == 1)
|
||||
{
|
||||
record = [records objectAtIndex: 0];
|
||||
sname = [record objectForKey: GCSPathRecordName];
|
||||
result = [fname isEqualToString: sname];
|
||||
}
|
||||
else
|
||||
[self logWithFormat: @"records: %@", records];
|
||||
}
|
||||
}
|
||||
else
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
}
|
||||
else
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
{
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
sql = [self generateSQLPathFetchForInternalNames: fnames
|
||||
exactMatch: YES
|
||||
orDirectSubfolderMatch: NO
|
||||
withChannel: channel];
|
||||
if ([sql length])
|
||||
{
|
||||
records = [self performSQL: sql withChannel: channel];
|
||||
if (records)
|
||||
{
|
||||
count = [records count];
|
||||
if (count)
|
||||
{
|
||||
fname = [self internalNameFromPath: _path];
|
||||
if (count == 1)
|
||||
{
|
||||
record = [records objectAtIndex: 0];
|
||||
sname = [record objectForKey: GCSPathRecordName];
|
||||
result = [fname isEqualToString: sname];
|
||||
}
|
||||
else
|
||||
[self logWithFormat: @"records: %@", records];
|
||||
}
|
||||
}
|
||||
else
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'", __PRETTY_FUNCTION__, sql];
|
||||
}
|
||||
else
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
}
|
||||
else
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
|
||||
@@ -774,21 +789,29 @@ static BOOL _singleStoreMode = NO;
|
||||
NSString *fname;
|
||||
NSArray *fnames, *records;
|
||||
NSString *sql;
|
||||
EOAdaptorChannel *channel;
|
||||
unsigned i, count;
|
||||
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
sql = [self generateSQLPathFetchForInternalNames:fnames
|
||||
exactMatch:NO orDirectSubfolderMatch:(_recursive ? NO : YES)];
|
||||
exactMatch:NO orDirectSubfolderMatch:(_recursive ? NO : YES) withChannel: channel];
|
||||
if ([sql length] == 0) {
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
[self releaseChannel: channel];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
if ((records = [self performSQL:sql withChannel: channel]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return nil;
|
||||
@@ -833,27 +856,37 @@ static BOOL _singleStoreMode = NO;
|
||||
NSArray *fnames, *records;
|
||||
NSString *sql;
|
||||
unsigned i, count;
|
||||
EOAdaptorChannel *channel;
|
||||
|
||||
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
sql = [self generateSQLPathAndNameFetchForInternalNames:fnames
|
||||
exactMatch:NO orDirectSubfolderMatch:(_recursive ? NO : YES)];
|
||||
exactMatch:NO orDirectSubfolderMatch:(_recursive ? NO : YES) withChannel: channel];
|
||||
if ([sql length] == 0) {
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
[self releaseChannel: channel];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
if ((records = [self performSQL:sql withChannel: channel]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((count = [records count]) == 0)
|
||||
if ((count = [records count]) == 0) {
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
result = [NSMutableArray arrayWithCapacity:(count > 128 ? 128 : count)];
|
||||
|
||||
@@ -899,16 +932,23 @@ static BOOL _singleStoreMode = NO;
|
||||
NSArray *fnames, *records;
|
||||
NSString *ws;
|
||||
NSDictionary *record;
|
||||
|
||||
EOAdaptorChannel *channel;
|
||||
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* generate SQL to fetch folder attributes */
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:fnames
|
||||
exactMatch:YES orDirectSubfolderMatch:NO];
|
||||
exactMatch:YES orDirectSubfolderMatch:NO withChannel: channel];
|
||||
|
||||
sql = [NSMutableString stringWithCapacity:256];
|
||||
[sql appendString:@"SELECT "];
|
||||
@@ -925,7 +965,7 @@ static BOOL _singleStoreMode = NO;
|
||||
|
||||
/* fetching */
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
if ((records = [self performSQL:sql withChannel: channel]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return nil;
|
||||
@@ -992,44 +1032,55 @@ static BOOL _singleStoreMode = NO;
|
||||
andChannel: (EOAdaptorChannel *) channel
|
||||
atPath: (NSString *) path
|
||||
{
|
||||
NSString *baseURL, *tableName, *quickTableName, *aclTableName, *createQuery, *sql;
|
||||
NSString *baseURL, *tableName, *quickTableName, *aclTableName, *createQuery, *sql, *safeFolderName, *safePath;
|
||||
GCSSpecialQueries *specialQuery;
|
||||
EOAdaptorContext *aContext;
|
||||
EOAdaptor *adaptor;
|
||||
EOAttribute *attribute;
|
||||
NSMutableArray *paths;
|
||||
NSException *error;
|
||||
NSRange range;
|
||||
|
||||
paths = [NSMutableArray arrayWithArray: [path componentsSeparatedByString: @"/"]];
|
||||
aContext = [channel adaptorContext];
|
||||
[aContext beginTransaction];
|
||||
|
||||
//escape foldername to avoid sql injection
|
||||
adaptor = [aContext adaptor];
|
||||
|
||||
attribute = [EOAttribute new];
|
||||
[attribute autorelease];
|
||||
[attribute setExternalType: @"varchar"];
|
||||
|
||||
safeFolderName = [adaptor formatValue: folderName forAttribute: attribute];
|
||||
safePath = [adaptor formatValue: path forAttribute: attribute];
|
||||
|
||||
|
||||
paths = [NSMutableArray arrayWithArray: [safePath componentsSeparatedByString: @"/"]];
|
||||
|
||||
while ([paths count] < 5)
|
||||
[paths addObject: @"NULL"];
|
||||
|
||||
aContext = [channel adaptorContext];
|
||||
[aContext beginTransaction];
|
||||
|
||||
tableName = [self baseTableNameWithUID: [paths objectAtIndex: 2]];
|
||||
quickTableName = [tableName stringByAppendingString: @"_quick"];
|
||||
aclTableName = [tableName stringByAppendingString: @"_acl"];
|
||||
|
||||
// TBD: fix SQL injection issues.
|
||||
// We no longer call stringByDeletingLastPathComponent since, since GNUstep 1.22,
|
||||
// it'll replace // characters in the URL with /, so mysql:// becomes mysql:/
|
||||
// This is to conform with recent Apple changes.
|
||||
baseURL = [folderInfoLocation absoluteString];
|
||||
range = [baseURL rangeOfString: @"/" options: NSBackwardsSearch];
|
||||
if (range.location != NSNotFound)
|
||||
baseURL = [baseURL substringToIndex: range.location];
|
||||
|
||||
|
||||
|
||||
//Mind the quote, safeFolderName and safePath already have them as they have been escaped, c_path4 already has one at the end
|
||||
sql = [NSString stringWithFormat: @"INSERT INTO %@"
|
||||
@" (c_path, c_path1, c_path2, c_path3, c_path4,"
|
||||
@" c_foldername, c_location, c_quick_location,"
|
||||
@" c_acl_location, c_folder_type)"
|
||||
@" VALUES ('%@', '%@', '%@', '%@', '%@', '%@', '%@/%@',"
|
||||
@" VALUES (%@, '%@', '%@', '%@', '%@, %@, '%@/%@',"
|
||||
@" '%@/%@', '%@/%@', '%@')",
|
||||
[self folderInfoTableName], path,
|
||||
[self folderInfoTableName], safePath,
|
||||
[paths objectAtIndex: 1], [paths objectAtIndex: 2],
|
||||
[paths objectAtIndex: 3], [paths objectAtIndex: 4],
|
||||
[folderName stringByReplacingString: @"'" withString: @"''"],
|
||||
safeFolderName,
|
||||
baseURL, tableName,
|
||||
baseURL, quickTableName,
|
||||
baseURL, aclTableName,
|
||||
@@ -1114,6 +1165,12 @@ static BOOL _singleStoreMode = NO;
|
||||
EOAdaptorChannel *channel;
|
||||
NSException *ex;
|
||||
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
if ((folder = [self folderAtPath:_path]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSMissingFolder"
|
||||
reason:@"missing folder"
|
||||
@@ -1126,15 +1183,11 @@ static BOOL _singleStoreMode = NO;
|
||||
}
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:fnames
|
||||
exactMatch:YES orDirectSubfolderMatch:NO];
|
||||
exactMatch:YES orDirectSubfolderMatch:NO withChannel: channel];
|
||||
|
||||
sql = [NSString stringWithFormat: @"DELETE FROM %@ WHERE %@",
|
||||
[self folderInfoTableName], ws];
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
|
||||
[[channel adaptorContext] beginTransaction];
|
||||
|
||||
|
||||
@@ -214,10 +214,10 @@
|
||||
{
|
||||
static NSString *sqlFolderFormat
|
||||
= (@"CREATE TABLE %@ ("
|
||||
@" c_user_session VARCHAR(4096) NOT NULL,"
|
||||
@" c_old_session VARCHAR(4096) NULL,"
|
||||
@" c_user_session TEXT NOT NULL,"
|
||||
@" c_old_session TEXT NULL,"
|
||||
@" c_session_started INT4 NOT NULL,"
|
||||
@" c_refresh_token VARCHAR(4096) NULL,"
|
||||
@" c_refresh_token TEXT NULL,"
|
||||
@" c_access_token_expires_in INT4 NULL,"
|
||||
@" c_refresh_token_expires_in INT4 NULL)");
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
static NSString *sqlFolderFormat
|
||||
= (@"CREATE TABLE %@ ("
|
||||
@" c_id VARCHAR(255) PRIMARY KEY,"
|
||||
@" c_value VARCHAR(4096) NOT NULL,"
|
||||
@" c_value TEXT NOT NULL,"
|
||||
@" c_creationdate INT4 NOT NULL,"
|
||||
@" c_lastseen INT4 NOT NULL)");
|
||||
|
||||
@@ -375,10 +375,10 @@
|
||||
{
|
||||
static NSString *sqlFolderFormat
|
||||
= (@"CREATE TABLE %@ ("
|
||||
@" c_user_session VARCHAR(4096) NOT NULL,"
|
||||
@" c_old_session VARCHAR(4096) NULL,"
|
||||
@" c_user_session TEXT NOT NULL,"
|
||||
@" c_old_session TEXT NULL,"
|
||||
@" c_session_started INT4 NOT NULL,"
|
||||
@" c_refresh_token VARCHAR(4096) NULL,"
|
||||
@" c_refresh_token TEXT NULL,"
|
||||
@" c_access_token_expires_in INT4 NULL,"
|
||||
@" c_refresh_token_expires_in INT4 NULL)");
|
||||
|
||||
@@ -435,7 +435,7 @@
|
||||
static NSString *sqlFolderFormat
|
||||
= (@"CREATE TABLE %@ ("
|
||||
@" c_id VARCHAR(255) PRIMARY KEY,"
|
||||
@" c_value VARCHAR(4096) NOT NULL,"
|
||||
@" c_value TEXT NOT NULL,"
|
||||
@" c_creationdate INT NOT NULL,"
|
||||
@" c_lastseen INT NOT NULL)");
|
||||
|
||||
@@ -536,10 +536,10 @@
|
||||
{
|
||||
static NSString *sqlFolderFormat
|
||||
= (@"CREATE TABLE %@ ("
|
||||
@" c_user_session VARCHAR2(4096) NOT NULL,"
|
||||
@" c_old_session VARCHAR2(4096) NULL,"
|
||||
@" c_user_session VARCHAR2(8192) NOT NULL,"
|
||||
@" c_old_session VARCHAR2(8192) NULL,"
|
||||
@" c_session_started INTEGER NOT NULL,"
|
||||
@" c_refresh_token VARCHAR2(4096) NULL,"
|
||||
@" c_refresh_token VARCHAR2(8192) NULL,"
|
||||
@" c_access_token_expires_in INTEGER NULL,"
|
||||
@" c_refresh_token_expires_in INTEGER NULL)");
|
||||
|
||||
@@ -595,7 +595,7 @@
|
||||
static NSString *sqlFolderFormat
|
||||
= (@"CREATE TABLE %@ ("
|
||||
@" c_id VARCHAR2(255) PRIMARY KEY,"
|
||||
@" c_value VARCHAR2(4096) NOT NULL,"
|
||||
@" c_value VARCHAR2(8192) NOT NULL,"
|
||||
@" c_creationdate INTEGER NOT NULL,"
|
||||
@" c_lastseen INTEGER NOT NULL)");
|
||||
|
||||
|
||||
@@ -86,8 +86,13 @@
|
||||
tzId = [self value: 0 ofAttribute: @"tzid"];
|
||||
if ([tzId length])
|
||||
{
|
||||
calendar = (iCalCalendar *) [self searchParentOfClass: [iCalCalendar class]];
|
||||
timeZone = [calendar timeZoneWithId: tzId];
|
||||
//Hack, get timezone inf from sogo and not from the event VTIMEZONE as it can be incorrect/incomplete
|
||||
timeZone = [iCalTimeZone timeZoneForName: tzId];
|
||||
if(!timeZone)
|
||||
{
|
||||
calendar = (iCalCalendar *) [self searchParentOfClass: [iCalCalendar class]];
|
||||
timeZone = [calendar timeZoneWithId: tzId];
|
||||
}
|
||||
//if (!timeZone)
|
||||
//[self logWithFormat: @"timezone '%@' not found in calendar", tzId];
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ CREATE TABLE sogo_quick_contact (
|
||||
|
||||
CREATE TABLE sogo_sessions_folder (
|
||||
c_id varchar(255) NOT NULL,
|
||||
c_value varchar(4096) NOT NULL,
|
||||
c_value text NOT NULL,
|
||||
c_creationdate int(11) NOT NULL,
|
||||
c_lastseen int(11) NOT NULL,
|
||||
PRIMARY KEY (c_id)
|
||||
@@ -166,10 +166,10 @@ CREATE TABLE sogo_admin (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE sogo_opend_id (
|
||||
c_user_session varchar(4096) NOT NULL,
|
||||
c_old_session varchar(4096) DEFAULT '',
|
||||
c_user_session text NOT NULL,
|
||||
c_old_session text DEFAULT '',
|
||||
c_session_started int(11) NOT NULL,
|
||||
c_refresh_token varchar(4096) DEFAULT '',
|
||||
c_refresh_token text DEFAULT '',
|
||||
c_access_token_expires_in int(11) DEFAULT '',
|
||||
c_refresh_token_expires_in int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (c_user_session)
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
"Inviting the following persons is prohibited:" = "Inviting the following persons is prohibited:";
|
||||
"Personal Calendar" = "Personal Calendar";
|
||||
vevent_class0 = "(Public event)";
|
||||
vevent_class1 = "(Private event)";
|
||||
vevent_class2 = "(Confidential event)";
|
||||
|
||||
vtodo_class0 = "(Public task)";
|
||||
vtodo_class1 = "(Private task)";
|
||||
vtodo_class2 = "(Confidential task)";
|
||||
|
||||
/* Receipts */
|
||||
"The event \"%{Summary}\" was created" = "The event \"%{Summary}\" was created";
|
||||
"The event \"%{Summary}\" was deleted" = "The event \"%{Summary}\" was deleted";
|
||||
"The event \"%{Summary}\" was updated" = "The event \"%{Summary}\" was updated";
|
||||
"The task \"%{Summary}\" was created" = "The task \"%{Summary}\" was created";
|
||||
"The task \"%{Summary}\" was deleted" = "The task \"%{Summary}\" was deleted";
|
||||
"The task \"%{Summary}\" was updated" = "The task \"%{Summary}\" was updated";
|
||||
"The following attendees(s) were notified" = "The following attendee(s) were notified";
|
||||
"The following attendees(s) were added" = "The following attendee(s) were added";
|
||||
"The following attendees(s) were removed" = "The following attendee(s) were removed";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "Calendar";
|
||||
"startDate_label" = "Start";
|
||||
"endDate_label" = "End";
|
||||
"time_label" = "Time";
|
||||
"to_label" = "to";
|
||||
"due_label" = "Due Date";
|
||||
"location_label" = "Location";
|
||||
"summary_label" = "Summary";
|
||||
"comment_label" = "Comment";
|
||||
"organizer_label" = "Organizer";
|
||||
"attendee_label" = "Attendee";
|
||||
|
||||
/* Invitation */
|
||||
"Event Invitation: \"%{Summary}\"" = "Event Invitation: \"%{Summary}\"";
|
||||
"(sent by %{SentBy}) " = "(sent by %{SentBy}) ";
|
||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}";
|
||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}";
|
||||
|
||||
/* Deletion */
|
||||
"Event Cancelled: \"%{Summary}\"" = "Event Cancelled: \"%{Summary}\"";
|
||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
|
||||
= "%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}";
|
||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
|
||||
= "%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}";
|
||||
|
||||
/* Update */
|
||||
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
|
||||
= "The appointment \"%{Summary}\" for the %{OldStartDate} has changed";
|
||||
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
|
||||
= "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed";
|
||||
"The following parameters have changed in the \"%{Summary}\" meeting:"
|
||||
= "The following parameters have changed in the \"%{Summary}\" meeting:";
|
||||
"Please accept or decline those changes."
|
||||
= "Please accept or decline those changes.";
|
||||
|
||||
/* Reply */
|
||||
"Accepted invitation: \"%{Summary}\"" = "Accepted invitation: \"%{Summary}\"";
|
||||
"Declined invitation: \"%{Summary}\"" = "Declined invitation: \"%{Summary}\"";
|
||||
"Delegated invitation: \"%{Summary}\"" = "Delegated invitation: \"%{Summary}\"";
|
||||
"Not yet decided on invitation: \"%{Summary}\"" = "Not yet decided on invitation: \"%{Summary}\"";
|
||||
"%{Attendee} %{SentByText}has accepted your event invitation."
|
||||
= "%{Attendee} %{SentByText}has accepted your event invitation.";
|
||||
"%{Attendee} %{SentByText}has declined your event invitation."
|
||||
= "%{Attendee} %{SentByText}has declined your event invitation.";
|
||||
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
|
||||
= "%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}.";
|
||||
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
|
||||
= "%{Attendee} %{SentByText}has not yet decided upon your event invitation.";
|
||||
|
||||
/* Reminder */
|
||||
"Reminder: \"%{Summary}\" - %{StartDate}" = "Reminder: \"%{Summary}\" - %{StartDate}";
|
||||
|
||||
/* Resources */
|
||||
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "Cannot access resource: \"%{Cn} %{SystemEmail}\"";
|
||||
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}.";
|
||||
|
||||
/* Participation role */
|
||||
"Your participation is required to this event" = "Your participation is required to this event";
|
||||
"Your participation is optional to this event" = "Your participation is optional to this event";
|
||||
"Your participation is not required to this event" = "Your participation is not required to this event";
|
||||
@@ -26,7 +26,7 @@ vtodo_class2 = "(Bizalmas feladat)";
|
||||
"time_label" = "Idő";
|
||||
"to_label" = "-";
|
||||
"due_label" = "Lejárat napja:";
|
||||
"location_label" = "Hely";
|
||||
"location_label" = "Helyszín";
|
||||
"summary_label" = "Összegzés:";
|
||||
"comment_label" = "Megjegyzés:";
|
||||
"organizer_label" = "Szervező";
|
||||
|
||||
@@ -1133,8 +1133,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
recordIndex = [self _indexOfRecordMatchingDate: recurrenceId inArray: ma];
|
||||
if ([dateRange doesIntersectWithDateRange: recurrenceIdRange] && recordIndex == -1) {
|
||||
[self warnWithFormat:
|
||||
@"missing exception record for recurrence-id %@ (uid %@), ma = %@, dr = %@, rir = %@",
|
||||
recurrenceId, [component uid], ma, dateRange, recurrenceIdRange];
|
||||
@"missing exception record for recurrence-id %@ (uid %@), dr = %@, rir = %@",
|
||||
recurrenceId, [component uid], dateRange, recurrenceIdRange];
|
||||
}
|
||||
if ([dateRange doesIntersectWithDateRange: recurrenceIdRange] && recordIndex != -1)
|
||||
{
|
||||
@@ -3521,6 +3521,15 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
timezone = nil;
|
||||
element = [components objectAtIndex: i];
|
||||
|
||||
//remove all attenddees, change organisator and change uid
|
||||
//If we do not clean up, any user could impersonate someone by importing a malicious .ics
|
||||
//and send notificaitons to attenddes or remove their event (as SOGo think the user has the rights to do so)
|
||||
[element removeAllAttendees];
|
||||
[element setOrganizer: nil];
|
||||
[element setUid: [self globallyUniqueObjectId]];
|
||||
|
||||
|
||||
|
||||
if ([element isKindOfClass: iCalEventK])
|
||||
{
|
||||
event = (iCalEvent *)element;
|
||||
|
||||
@@ -65,6 +65,9 @@
|
||||
#import "iCalRepeatableEntityObject+SOGo.h"
|
||||
#import "SOGoCalendarComponent.h"
|
||||
|
||||
|
||||
static NSArray *allowed_tags = nil;
|
||||
|
||||
@implementation SOGoCalendarComponent
|
||||
|
||||
+ (SOGoWebDAVAclManager *) webdavAclManager
|
||||
@@ -210,7 +213,6 @@
|
||||
SOGoUser *calendarOwner;
|
||||
NSEnumerator *children;
|
||||
CardElement *element;
|
||||
NSArray *tags;
|
||||
|
||||
int classification;
|
||||
|
||||
@@ -231,22 +233,25 @@
|
||||
summary = [self labelForKey: [NSString stringWithFormat: @"%@_class%d",
|
||||
type, classification]
|
||||
inContext: context];
|
||||
|
||||
tags = [NSArray arrayWithObjects: @"DTSTAMP", @"DTSTART", @"DTEND", @"DUE", @"EXDATE", @"EXRULE", @"RRULE", @"RECURRENCE-ID", nil];
|
||||
if(!allowed_tags)
|
||||
allowed_tags = [[NSArray arrayWithObjects: @"DTSTAMP", @"DTSTART", @"DTEND", @"DUE", @"EXDATE", @"EXRULE", @"RRULE", @"RECURRENCE-ID", nil] retain];
|
||||
uid = [[component uid] asCryptedPassUsingScheme: @"ssha256"
|
||||
withSalt: [[settings userPublicSalt] dataUsingEncoding: NSASCIIStringEncoding]
|
||||
andEncoding: encHex
|
||||
keyPath: nil];
|
||||
|
||||
children = [[[[component children] copy] autorelease] objectEnumerator];
|
||||
|
||||
children = [[component children] objectEnumerator];
|
||||
NSMutableArray *to_remove = [NSMutableArray arrayWithCapacity: 8];
|
||||
|
||||
while ((element = [children nextObject]))
|
||||
{
|
||||
tag = [element tag];
|
||||
if (![tags containsObject: [tag uppercaseString]])
|
||||
[component removeChild: element];
|
||||
if (![allowed_tags containsObject: [tag uppercaseString]])
|
||||
[to_remove addObject: element];
|
||||
}
|
||||
|
||||
[component removeChildren: to_remove];
|
||||
|
||||
[component setSummary: summary];
|
||||
[component setUid: uid];
|
||||
}
|
||||
@@ -885,7 +890,7 @@
|
||||
mailDate = [[NSCalendarDate date] rfc822DateString];
|
||||
[headerMap setObject: mailDate forKey: @"date"];
|
||||
[headerMap setObject: subject forKey: @"subject"];
|
||||
[headerMap setObject: [NSString generateMessageID] forKey: @"message-id"];
|
||||
[headerMap setObject: [NSString generateMessageID: senderEmail] forKey: @"message-id"];
|
||||
if ([msgType length] > 0)
|
||||
[headerMap setObject: msgType forKey: @"x-sogo-message-type"];
|
||||
msg = [NGMimeMessage messageWithHeader: headerMap];
|
||||
@@ -974,7 +979,7 @@
|
||||
[headerMap setObject: mailDate forKey: @"date"];
|
||||
[headerMap setObject: [[p getSubject] asQPSubjectString: @"UTF-8"]
|
||||
forKey: @"subject"];
|
||||
[headerMap setObject: [NSString generateMessageID] forKey: @"message-id"];
|
||||
[headerMap setObject: [NSString generateMessageID: [[attendee mailAddress] pureEMailAddress]] forKey: @"message-id"];
|
||||
[headerMap setObject: @"1.0" forKey: @"MIME-Version"];
|
||||
|
||||
if (textOnly)
|
||||
@@ -1163,7 +1168,7 @@
|
||||
mailDate = [[NSCalendarDate date] rfc822DateString];
|
||||
[headerMap setObject: mailDate forKey: @"date"];
|
||||
[headerMap setObject: [page getSubject] forKey: @"subject"];
|
||||
[headerMap setObject: [NSString generateMessageID] forKey: @"message-id"];
|
||||
[headerMap setObject: [NSString generateMessageID: senderEmail] forKey: @"message-id"];
|
||||
[headerMap setObject: @"1.0" forKey: @"MIME-Version"];
|
||||
[headerMap setObject: @"text/html; charset=utf-8"
|
||||
forKey: @"content-type"];
|
||||
|
||||
@@ -184,6 +184,10 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
else
|
||||
[result setObject: @"invalid-calendar-content" forKey: @"error"];
|
||||
}
|
||||
else if (status == 401)
|
||||
{
|
||||
[result setObject: @"need-auth" forKey: @"error"];
|
||||
}
|
||||
else
|
||||
[result setObject: @"http-error" forKey: @"error"];
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ vtodo_class2 = "(งานลับ)";
|
||||
"The task \"%{Summary}\" was created" = "งาน \"%{Summary}\" ถูกสร้างขี้น";
|
||||
"The task \"%{Summary}\" was deleted" = "งาน \"%{Summary}\" ถูกลบ";
|
||||
"The task \"%{Summary}\" was updated" = "งาน \"%{Summary}\" ถูกอัพเดต";
|
||||
"The following attendees(s) were notified" = "แจ้งผู้เข้าร่วมดังต่อไปนี้";
|
||||
"The following attendees(s) were notified" = "ผู้เข้าร่วมต่อไปนี้ได้รับการแจ้งแล้ว";
|
||||
"The following attendees(s) were added" = "ผู้เข้าร่วมต่อไปนี้ถูกเพิ่มเข้ามา";
|
||||
"The following attendees(s) were removed" = "ผู้เข้าร่วมต่อไปนี้ถูกลบออก";
|
||||
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
BOOL isAllDayStartDate, isAllDayDueDate;
|
||||
NSCalendarDate *startDate, *dueDate, *completedDate;
|
||||
NSInteger percent;
|
||||
NSString *owner;
|
||||
SOGoUserDefaults *ud;
|
||||
iCalDateTime *todoStartDate, *todoDueDate;
|
||||
iCalTimeZone *tz;
|
||||
@@ -230,6 +231,15 @@
|
||||
}
|
||||
else
|
||||
[self setPercentComplete: @""];
|
||||
|
||||
//To make an ics conforme with outlook live (bouh), valarm must be the last element of vevent
|
||||
//Try to set it here
|
||||
o = [data objectForKey: @"alarm"];
|
||||
if ([o isKindOfClass: [NSDictionary class]])
|
||||
{
|
||||
owner = [data objectForKey: @"owner"];
|
||||
[self _setAlarm: o forOwner: owner];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) quickRecordFromContent: (NSString *) theContent
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
"Personal Address Book" = "Personal Address Book";
|
||||
"Collected Address Book" = "Collected Address Book";
|
||||
@@ -0,0 +1,5 @@
|
||||
"OtherUsersFolderName" = "Other Users";
|
||||
"SharedFoldersName" = "Shared Folders";
|
||||
|
||||
"Report: Marked messages as junk" = "Report: Marked messages as junk";
|
||||
"Report: Marked messages as not junk" = "Report: Marked messages as not junk";
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
@interface NSString (SOGoExtension)
|
||||
|
||||
+ (NSString *) generateMessageID;
|
||||
+ (NSString *) generateMessageID: (NSString *) mailOrDomain;
|
||||
- (NSString *) htmlToText;
|
||||
- (NSString *) htmlByExtractingImages: (NSMutableArray *) theImages;
|
||||
- (NSString *) stringByConvertingCRLNToHTML;
|
||||
|
||||
@@ -560,15 +560,27 @@
|
||||
|
||||
@implementation NSString (SOGoExtension)
|
||||
|
||||
+ (NSString *) generateMessageID
|
||||
+ (NSString *) generateMessageID: (NSString *) mailOrDomain
|
||||
{
|
||||
NSMutableString *messageID;
|
||||
NSString *pGUID;
|
||||
NSString *_domain;
|
||||
NSRange r;
|
||||
|
||||
messageID = [NSMutableString string];
|
||||
[messageID appendFormat: @"<%@", [SOGoObject globallyUniqueObjectId]];
|
||||
pGUID = [[NSProcessInfo processInfo] globallyUniqueString];
|
||||
[messageID appendFormat: @"@%u>", (unsigned int)[pGUID hash]];
|
||||
[messageID appendFormat: @"<%@", [SOGoObject mailUniqueMessageId]];
|
||||
if(mailOrDomain)
|
||||
{
|
||||
r = [mailOrDomain rangeOfString: @"@" options: NSBackwardsSearch];
|
||||
if (r.location != NSNotFound)
|
||||
{
|
||||
//Its the full email not a domain
|
||||
_domain = [mailOrDomain substringFromIndex: (r.location + r.length)];
|
||||
}
|
||||
else
|
||||
_domain = mailOrDomain;
|
||||
[messageID appendFormat: @"@%@>", _domain];
|
||||
}
|
||||
|
||||
|
||||
return [messageID lowercaseString];
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ static NSString *userAgent = nil;
|
||||
messageID = [headers objectForKey: @"message-id"];
|
||||
if (!messageID)
|
||||
{
|
||||
messageID = [NSString generateMessageID];
|
||||
messageID = [NSString generateMessageID: [[newHeaders objectForKey: @"from"] pureEMailAddress]];
|
||||
[headers setObject: messageID forKey: @"message-id"];
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ static NSString *userAgent = nil;
|
||||
|
||||
- (void) setText: (NSString *) newText
|
||||
{
|
||||
ASSIGN (text, [newText stringWithoutHTMLInjection: NO]);
|
||||
ASSIGN (text, [newText stringWithoutHTMLInjection: NO stripAngular: NO]);
|
||||
}
|
||||
|
||||
- (NSString *) text
|
||||
|
||||
@@ -142,6 +142,10 @@
|
||||
else
|
||||
imapAuthMech = nil;
|
||||
|
||||
//If ActiveSync, force the plain mech
|
||||
if([[[[self context] request] requestHandlerKey] isEqualToString:@"Microsoft-Server-ActiveSync"])
|
||||
imapAuthMech = @"plain";
|
||||
|
||||
return [NGImap4ConnectionManager defaultConnectionManager: imapAuthMech];
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,9 @@
|
||||
@interface SOGoMailGermanForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
@interface SOGoMailGreekForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
@interface SOGoMailHebrewForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
NSString *rc;
|
||||
|
||||
if (htmlComposition)
|
||||
rc = [NSString stringWithFormat: @"%@<br/>", [self _headerField: @"organization"]];
|
||||
rc = [NSString stringWithFormat: @"%@<br/>", [[self _headerField: @"organization"] stringByEscapingHTMLString]];
|
||||
else
|
||||
rc = [NSString stringWithFormat: @"%@\n", [self _headerField: @"organization"]];
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
NSString *rc;
|
||||
|
||||
if (htmlComposition)
|
||||
rc = [NSString stringWithFormat: @"%@<br/>", [self _headerField: @"newsgroups"]];
|
||||
rc = [NSString stringWithFormat: @"%@<br/>", [[self _headerField: @"newsgroups"] stringByEscapingHTMLString]];
|
||||
else
|
||||
rc = [NSString stringWithFormat: @"%@\n", [self _headerField: @"newsgroups"]];
|
||||
|
||||
@@ -222,7 +222,7 @@
|
||||
NSString *rc;
|
||||
|
||||
if (htmlComposition)
|
||||
rc = [NSString stringWithFormat: @"%@<br/>", [self _headerField: @"references"]];
|
||||
rc = [NSString stringWithFormat: @"%@<br/>", [[self _headerField: @"references"] stringByEscapingHTMLString]];
|
||||
else
|
||||
rc = [NSString stringWithFormat: @"%@\n", [self _headerField: @"references"]];
|
||||
|
||||
@@ -345,6 +345,9 @@
|
||||
@implementation SOGoMailGermanForward
|
||||
@end
|
||||
|
||||
@implementation SOGoMailGreekForward
|
||||
@end
|
||||
|
||||
@implementation SOGoMailHebrewForward
|
||||
@end
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<#newLine/><#newLine
|
||||
/><#signaturePlacementOnTop><#signature/><#newLine/><#newLine/></#signaturePlacementOnTop
|
||||
>-------- Αρχικό Μήνυμα --------<#newLine
|
||||
/>Θέμα: <#subject/><#newLine
|
||||
/>Ημερομηνία: <#date/><#newLine
|
||||
/>Από: <#from/><#newLine
|
||||
/><#hasReplyTo>Απάντηση-Προς: <#replyTo/><#newLine/></#hasReplyTo
|
||||
><#hasOrganization>Οργανισμός: <#organization/><#newLine/></#hasOrganization
|
||||
>Προς: <#to/><#newLine
|
||||
/><#hasCc>Κοιν.: <#cc/><#newLine/></#hasCc
|
||||
><#hasNewsGroups>Ομάδες ειδήσεων: <#newsgroups/><#newLine/></#hasNewsGroups
|
||||
><#hasReferences>Αναφορές: <#references/><#newLine/></#hasReferences
|
||||
><#newLine/><#newLine
|
||||
/><#messageBody
|
||||
/><#signaturePlacementOnBottom><#newLine/><#newLine/><#signature/></#signaturePlacementOnBottom>
|
||||
@@ -0,0 +1,88 @@
|
||||
subject: WOString {
|
||||
value = subject;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
date: WOString {
|
||||
value = date;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
from: WOString {
|
||||
value = from;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
newLine: WOString {
|
||||
value = newLine;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReplyTo: WOConditional {
|
||||
condition = hasReplyTo;
|
||||
}
|
||||
|
||||
replyTo: WOString {
|
||||
value = replyTo;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasOrganization: WOConditional {
|
||||
condition = hasOrganization;
|
||||
}
|
||||
|
||||
organization: WOString {
|
||||
value = organization;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
to: WOString {
|
||||
value = to;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasCc: WOConditional {
|
||||
condition = hasCc;
|
||||
}
|
||||
|
||||
cc: WOString {
|
||||
value = cc;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasNewsGroups: WOConditional {
|
||||
condition = hasNewsGroups;
|
||||
}
|
||||
|
||||
newsgroups: WOString {
|
||||
value = newsgroups;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReferences: WOConditional {
|
||||
condition = hasReferences;
|
||||
}
|
||||
|
||||
references: WOString {
|
||||
value = references;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
messageBody: WOString {
|
||||
value = messageBody;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signature: WOString {
|
||||
value = signature;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signaturePlacementOnTop: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
}
|
||||
|
||||
signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<#replyPlacementOnTop><#newLine/><#newLine/></#replyPlacementOnTop
|
||||
><#signaturePlacementOnTop><#signature/><#newLine/><#newLine/></#signaturePlacementOnTop
|
||||
><#outlookMode
|
||||
>-------- Αρχικό Μήνυμα --------<#newLine
|
||||
/>Θέμα: <#subject/><#newLine
|
||||
/>Ημερομηνία: <#date/><#newLine
|
||||
/>Από: <#from/><#newLine
|
||||
/><#hasReplyTo>Απάντηση-Προς: <#replyTo/><#newLine/></#hasReplyTo
|
||||
><#hasOrganization>Οργανισμός: <#organization/><#newLine/></#hasOrganization
|
||||
>Προς: <#to/><#newLine
|
||||
/><#hasCc>Κοιν.: <#cc/><#newLine/></#hasCc
|
||||
><#hasNewsGroups>Ομάδες ειδήσεων: <#newsgroups/><#newLine/></#hasNewsGroups
|
||||
><#hasReferences>Αναφορές: <#references/><#newLine/></#hasReferences
|
||||
></#outlookMode
|
||||
><#standardMode>Στις <#date/>, ο/η <#from/> έγραψε:</#standardMode
|
||||
><#newLine/><#newLine/><#messageBody
|
||||
/><#replyPlacementOnBottom><#newLine/><#newLine/></#replyPlacementOnBottom
|
||||
><#signaturePlacementOnBottom><#newLine/><#signature/></#signaturePlacementOnBottom>
|
||||
@@ -0,0 +1,106 @@
|
||||
outlookMode: WOConditional {
|
||||
condition = outlookMode;
|
||||
}
|
||||
|
||||
standardMode: WOConditional {
|
||||
condition = outlookMode;
|
||||
negate = YES;
|
||||
}
|
||||
|
||||
subject: WOString {
|
||||
value = subject;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
date: WOString {
|
||||
value = date;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
from: WOString {
|
||||
value = from;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
newLine: WOString {
|
||||
value = newLine;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReplyTo: WOConditional {
|
||||
condition = hasReplyTo;
|
||||
}
|
||||
|
||||
replyTo: WOString {
|
||||
value = replyTo;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasOrganization: WOConditional {
|
||||
condition = hasOrganization;
|
||||
}
|
||||
|
||||
organization: WOString {
|
||||
value = organization;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
to: WOString {
|
||||
value = to;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasCc: WOConditional {
|
||||
condition = hasCc;
|
||||
}
|
||||
|
||||
cc: WOString {
|
||||
value = cc;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasNewsGroups: WOConditional {
|
||||
condition = hasNewsGroups;
|
||||
}
|
||||
|
||||
newsgroups: WOString {
|
||||
value = newsgroups;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReferences: WOConditional {
|
||||
condition = hasReferences;
|
||||
}
|
||||
|
||||
references: WOString {
|
||||
value = references;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
messageBody: WOString {
|
||||
value = messageBody;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signature: WOString {
|
||||
value = signature;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
replyPlacementOnTop: WOConditional {
|
||||
condition = replyPlacementOnTop;
|
||||
}
|
||||
|
||||
replyPlacementOnBottom: WOConditional {
|
||||
condition = replyPlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
|
||||
signaturePlacementOnTop: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
}
|
||||
|
||||
signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
@class NSArray;
|
||||
@class NSString;
|
||||
@class WOContext;
|
||||
@class NSNull;
|
||||
|
||||
@interface NSObject (SOGoObjectUtilities)
|
||||
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
|
||||
#import "NSObject+Utilities.h"
|
||||
|
||||
static NSMutableDictionary *translationCache = nil;
|
||||
|
||||
|
||||
@implementation NSObject (SOGoObjectUtilities)
|
||||
|
||||
- (NSString *) jsonRepresentation
|
||||
@@ -101,19 +104,28 @@
|
||||
if (!bundle)
|
||||
bundle = [NSBundle mainBundle];
|
||||
languages = [[self _languagesForLabelsInContext: context] objectEnumerator];
|
||||
|
||||
if(!translationCache)
|
||||
translationCache = [NSMutableDictionary new];
|
||||
|
||||
while (!label && (language = [languages nextObject]))
|
||||
{
|
||||
paths = [bundle pathsForResourcesOfType: @"strings"
|
||||
inDirectory: [NSString stringWithFormat: @"%@.lproj",
|
||||
language]
|
||||
if (![translationCache objectForKey: language] || [[translationCache objectForKey: language] objectForKey: key] != [NSNull null]) {
|
||||
paths = [bundle pathsForResourcesOfType: @"strings"
|
||||
inDirectory: [NSString stringWithFormat: @"%@.lproj",
|
||||
language]
|
||||
forLocalization: language];
|
||||
if ([paths count] > 0)
|
||||
{
|
||||
strings = [NSDictionary
|
||||
dictionaryFromStringsFile: [paths objectAtIndex: 0]];
|
||||
label = [strings objectForKey: key];
|
||||
}
|
||||
if ([paths count] > 0)
|
||||
{
|
||||
strings = [NSDictionary
|
||||
dictionaryFromStringsFile: [paths objectAtIndex: 0]];
|
||||
[translationCache setObject: strings forKey: language];
|
||||
label = [strings objectForKey: key];
|
||||
}
|
||||
} else {
|
||||
strings = [translationCache objectForKey: language];
|
||||
label = [strings objectForKey: key];
|
||||
}
|
||||
}
|
||||
if (!label)
|
||||
label = key;
|
||||
|
||||
@@ -78,7 +78,8 @@
|
||||
|
||||
/* XSS protection */
|
||||
- (NSString *) removeHTMLTagsExceptAnchorTags;
|
||||
- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode;
|
||||
- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode
|
||||
stripAngular: (BOOL)stripAngular;
|
||||
|
||||
#ifndef GNUSTEP_BASE_LIBRARY
|
||||
- (BOOL) boolValue;
|
||||
|
||||
@@ -184,6 +184,9 @@ static int cssEscapingCount;
|
||||
{
|
||||
rangePtr->location += offset;
|
||||
urlText = [selfCopy substringFromRange: *rangePtr];
|
||||
//If we try to detect mail, check if the first char is @, meaning this is not an email
|
||||
if([prefix isEqualToString: @"mailto:"] && [urlText characterAtIndex: 0] == '@')
|
||||
continue;
|
||||
newUrlText = [NSString stringWithFormat: @"<a rel=\"noopener\" href=\"%@%@\">%@</a>",
|
||||
([urlText hasPrefix: prefix]? @"" : prefix),
|
||||
urlText, urlText];
|
||||
@@ -933,18 +936,19 @@ static int cssEscapingCount;
|
||||
* @param stripHTMLCode Remove all HTML code from content
|
||||
* @return A safe string
|
||||
*/
|
||||
- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode
|
||||
- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode stripAngular: (BOOL)stripAngular
|
||||
{
|
||||
NSString *result, *text, *newResult;
|
||||
NSScanner *theScanner;
|
||||
NSError *error;
|
||||
NSUInteger numberOfMatches;
|
||||
NSRegularExpression *regex;
|
||||
NSRegularExpression *regex, *importRegex;
|
||||
|
||||
text = nil;
|
||||
error = nil;
|
||||
result = [NSString stringWithString: self];
|
||||
regex = nil;
|
||||
importRegex = nil;
|
||||
|
||||
NS_DURING
|
||||
{
|
||||
@@ -983,20 +987,28 @@ static int cssEscapingCount;
|
||||
// Remove javascript:
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"j[\\s\\u200B	

\\\\0]*a[\\s\\u200B	

\\\\0]*v[\\s\\u200B	

\\\\0]*a[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*c[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*:"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
// loop until stable: a single pass lets nested tokens reconstruct
|
||||
// the scheme, e.g. "javajavascript:script:" -> "javascript:"
|
||||
while ([regex numberOfMatchesInString:result options:0 range:NSMakeRange(0, [result length])] > 0) {
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
}
|
||||
|
||||
// Remove vbscript:
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"v[\\s\\u200B	

\\\\0]*b[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*c[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*:"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
while ([regex numberOfMatchesInString:result options:0 range:NSMakeRange(0, [result length])] > 0) {
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
}
|
||||
|
||||
// Remove livescript:
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"l[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*v[\\s\\u200B	

\\\\0]*e[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*c[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*:"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
while ([regex numberOfMatchesInString:result options:0 range:NSMakeRange(0, [result length])] > 0) {
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
}
|
||||
|
||||
// Remove <script
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"<[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*c[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*t"
|
||||
@@ -1028,24 +1040,41 @@ static int cssEscapingCount;
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"</for*"];
|
||||
result = [NSString stringWithString: newResult];
|
||||
|
||||
// Remove onload
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"onload="
|
||||
// Remove ANY inline event handler (on...=) in one rule instead of an
|
||||
// incomplete allow list. This also covers obfuscation by whitespace
|
||||
// before the '=' ("onerror =") and handler names that were not listed
|
||||
// before (onfocus, onbegin, onanimationstart, ...). With onfocus gone,
|
||||
// a lone "autofocus" has no handler left to trigger.
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"\\bon(click|error|focus|load|mouseover|animationstart)[\\s\\u200B	

\\r\\n\\t]*="
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onl***="];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"data-blocked="];
|
||||
result = [NSString stringWithString: newResult];
|
||||
|
||||
// Remove onmouseover
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"onmouseover="
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onmouseo***="];
|
||||
result = [NSString stringWithString: newResult];
|
||||
|
||||
|
||||
// Remove @import css (in style tags)
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"(<[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*y[\\s\\u200B	

\\\\0]*l[\\s\\u200B	

\\\\0]*e.*)([\\s\\u200B	

\\\\0]*@[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*m[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*o[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*t)(.*<[\\s\\u200B	

\\\\0]*\\/[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*y[\\s\\u200B	

\\\\0]*l[\\s\\u200B	

\\\\0]*e[\\s\\u200B	

\\\\0]*>)"
|
||||
importRegex = [NSRegularExpression regularExpressionWithPattern:@"(<[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*y[\\s\\u200B	

\\\\0]*l[\\s\\u200B	

\\\\0]*e.*)([\\s\\u200B	

\\\\0]*@[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*m[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*o[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*t)(.*<[\\s\\u200B	

\\\\0]*\\/[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*y[\\s\\u200B	

\\\\0]*l[\\s\\u200B	

\\\\0]*e[\\s\\u200B	

\\\\0]*>)"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [importRegex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"$1@im****$3"];
|
||||
result = [NSString stringWithString: newResult];
|
||||
|
||||
|
||||
if(stripAngular) {
|
||||
// Remove {{ and }} as they are interprated by angularJS with no way of escaping.
|
||||
// Cover the literal form, the hex entity ({) AND the decimal entity
|
||||
// ({), both with optional leading zeros, since the browser decodes
|
||||
// any of them back to a brace before AngularJS parses the node.
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"(\\{\\{)|(�*7b;�*7b;)|(�*123;�*123;)"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"{\\\\{"];
|
||||
result = [NSString stringWithString: newResult];
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"(\\}\\})|(�*7d;�*7d;)|(�*125;�*125;)"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"}/}"];
|
||||
result = [NSString stringWithString: newResult];
|
||||
}
|
||||
|
||||
newResult = result;
|
||||
while([regex numberOfMatchesInString:newResult options:0 range:NSMakeRange(0, [newResult length])] > 0) {
|
||||
newResult = [regex stringByReplacingMatchesInString:newResult options:0 range:NSMakeRange(0, [newResult length]) withTemplate:@"$1@im****$3"];
|
||||
while([importRegex numberOfMatchesInString:newResult options:0 range:NSMakeRange(0, [newResult length])] > 0) {
|
||||
newResult = [importRegex stringByReplacingMatchesInString:newResult options:0 range:NSMakeRange(0, [newResult length]) withTemplate:@"$1@im****$3"];
|
||||
}
|
||||
result = [NSString stringWithString: newResult];
|
||||
}
|
||||
@@ -1060,14 +1089,75 @@ static int cssEscapingCount;
|
||||
}
|
||||
|
||||
- (NSString *) cleanInvalidHTMLTags {
|
||||
// Clean HTML invalid tags as reported in https://bugs.sogo.nu/view.php?id=5755
|
||||
NSString *s;
|
||||
|
||||
s = [NSString stringWithString: self];
|
||||
s = [s stringByReplacingOccurrencesOfString:@"<!-->" withString:@""];
|
||||
s = [s stringByReplacingOccurrencesOfString:@"<!--<!" withString:@"<!--"];
|
||||
// Clean HTML invalid tags as reported in https://bugs.sogo.nu/view.php?id=5755 and https://bugs.sogo.nu/view.php?id=6167
|
||||
// libxml2 (HTML4) sees a standalone empty comment (<!--> or <!--->) as an
|
||||
// unterminated comment and drops the rest of the document, so remove it.
|
||||
// Only do it outside of comments: the Outlook "downlevel-revealed" pattern
|
||||
// <!--[if !mso]><!--> ... <!--<![endif]--> ends its first comment with
|
||||
// "<!-->", and removing it would hide the content in between.
|
||||
NSString *result;
|
||||
unichar *in, *out;
|
||||
NSUInteger len, i, j, o;
|
||||
|
||||
return s;
|
||||
len = [self length];
|
||||
if (len == 0)
|
||||
return [NSString string];
|
||||
|
||||
// Work on raw buffers: linear time, bounded memory (no per-comment objects)
|
||||
in = NSZoneMalloc (NULL, len * sizeof (unichar));
|
||||
out = NSZoneMalloc (NULL, len * sizeof (unichar));
|
||||
[self getCharacters: in];
|
||||
i = o = 0;
|
||||
|
||||
while (i < len)
|
||||
{
|
||||
if (i + 3 < len
|
||||
&& in[i] == '<' && in[i+1] == '!' && in[i+2] == '-' && in[i+3] == '-')
|
||||
{
|
||||
j = i + 4;
|
||||
if (j < len && in[j] == '>')
|
||||
{
|
||||
// <!-->
|
||||
i = j + 1;
|
||||
continue;
|
||||
}
|
||||
if (j + 1 < len && in[j] == '-' && in[j+1] == '>')
|
||||
{
|
||||
// <!--->
|
||||
i = j + 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Regular comment: keep it untouched up to its end ("-->" or "--!>",
|
||||
// as libxml2 accepts both), or up to the end if unterminated
|
||||
while (j < len)
|
||||
{
|
||||
if (j + 2 < len && in[j] == '-' && in[j+1] == '-' && in[j+2] == '>')
|
||||
{
|
||||
j += 3;
|
||||
break;
|
||||
}
|
||||
if (j + 3 < len && in[j] == '-' && in[j+1] == '-'
|
||||
&& in[j+2] == '!' && in[j+3] == '>')
|
||||
{
|
||||
j += 4;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
memcpy (out + o, in + i, (j - i) * sizeof (unichar));
|
||||
o += j - i;
|
||||
i = j;
|
||||
}
|
||||
else
|
||||
out[o++] = in[i++];
|
||||
}
|
||||
|
||||
result = [NSString stringWithCharacters: out length: o];
|
||||
NSZoneFree (NULL, in);
|
||||
NSZoneFree (NULL, out);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -93,7 +93,7 @@ static const NSString *kCacheMotdKey = @"admin-motd";
|
||||
NSException *error;
|
||||
NSString *safeMotd;
|
||||
|
||||
safeMotd = [motd stringWithoutHTMLInjection: NO];
|
||||
safeMotd = [motd stringWithoutHTMLInjection: NO stripAngular: NO];
|
||||
error = [[[GCSFolderManager defaultFolderManager] adminFolder] writeMotd: safeMotd];
|
||||
if (!error) {
|
||||
[[SOGoCache sharedCache] setValue:safeMotd forKey:kCacheMotdKey];
|
||||
|
||||
@@ -289,7 +289,7 @@ static memcached_st *handle = NULL;
|
||||
NSData *keyData, *valueData;
|
||||
memcached_return error;
|
||||
|
||||
// [self logWithFormat: @"setValue: '%@' forKey: '%@'", value, key];
|
||||
//[self logWithFormat: @"setValue: '%@' forKey: '%@'", value, key];
|
||||
if (handle)
|
||||
{
|
||||
keyData = [key dataUsingEncoding: NSUTF8StringEncoding];
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
SOGoLDAPContactInfoAttribute = "description";
|
||||
|
||||
SOGoMailingMechanism = "sendmail";
|
||||
SOGoMailingMechanism = "smtp";
|
||||
SOGoSMTPServer = "smtp://localhost";
|
||||
SOGoMailSpoolPath = "/var/spool/sogo";
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
"French",
|
||||
"Galician",
|
||||
"German",
|
||||
"Greek",
|
||||
"Hebrew",
|
||||
"Hungarian",
|
||||
"Icelandic",
|
||||
@@ -129,6 +130,7 @@
|
||||
SOGoMailDisplayFullEmail = NO;
|
||||
SOGoMailDisplayRemoteInlineImages = "never";
|
||||
SOGoMailCertificateEnabled = YES;
|
||||
SOGoMailDisplayAttachmentAbove = NO;
|
||||
|
||||
SOGoMailAutoMarkAsReadDelay = "0";
|
||||
SOGoMailAutoSave = "5";
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
- (BOOL) notifyOnExternalModifications;
|
||||
|
||||
- (NSDictionary *) mailJunkSettings;
|
||||
- (NSString *) mailJunkIcon;
|
||||
|
||||
- (BOOL) createIdentitiesDisabled;
|
||||
|
||||
|
||||
@@ -304,11 +304,10 @@
|
||||
NSString *mailingMechanism;
|
||||
|
||||
mailingMechanism = [self stringForKey: @"SOGoMailingMechanism"];
|
||||
if (!([mailingMechanism isEqualToString: @"sendmail"]
|
||||
|| [mailingMechanism isEqualToString: @"smtp"]))
|
||||
if (![mailingMechanism isEqualToString: @"smtp"])
|
||||
{
|
||||
[self logWithFormat: @"mechanism '%@' is invalid and"
|
||||
@" should be set to 'sendmail' or 'smtp' instead",
|
||||
@" should be set to 'smtp' instead",
|
||||
mailingMechanism];
|
||||
mailingMechanism = nil;
|
||||
}
|
||||
@@ -462,7 +461,9 @@
|
||||
|
||||
- (int) searchMinimumWordLength
|
||||
{
|
||||
return [self integerForKey: @"SOGoSearchMinimumWordLength"];
|
||||
int min = [self integerForKey: @"SOGoSearchMinimumWordLength"];
|
||||
if(min<1) min=1;
|
||||
return min;
|
||||
}
|
||||
|
||||
- (BOOL) notifyOnPersonalModifications
|
||||
@@ -480,6 +481,29 @@
|
||||
return [self objectForKey: @"SOGoMailJunkSettings"];
|
||||
}
|
||||
|
||||
- (NSString *) mailJunkIcon
|
||||
{
|
||||
NSArray *iconsList;
|
||||
NSString *icon;
|
||||
|
||||
iconsList = [NSArray arrayWithObjects: @"thumb_down",
|
||||
@"gpp_bad",
|
||||
@"local_fire_department",
|
||||
@"bug_report",
|
||||
@"error",
|
||||
@"warning",
|
||||
@"dangerous",
|
||||
@"report_gmailerrorred",
|
||||
nil];
|
||||
icon = [self objectForKey: @"mailJunkIcon"];
|
||||
if (([icon length] && ![iconsList containsObject:icon]) || ![icon length])
|
||||
{
|
||||
icon = @"thumb_down";
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
- (BOOL) createIdentitiesDisabled
|
||||
{
|
||||
return [self boolForKey: @"SOGoCreateIdentitiesDisabled"];
|
||||
|
||||
@@ -1859,27 +1859,76 @@ static NSArray *childRecordFields = nil;
|
||||
EOAdaptorChannel *channel;
|
||||
GCSFolder *folder;
|
||||
NSEnumerator *userRoles;
|
||||
NSString *SQL, *currentRole;
|
||||
NSString *SQL, *currentRole, *sqlstr;
|
||||
NSString *fieldName, *value;
|
||||
EOAdaptorContext *adaptorCtx;
|
||||
EOAdaptor *adaptor;
|
||||
EOAttribute *attribute;
|
||||
|
||||
folder = [self ocsFolder];
|
||||
channel = [folder acquireAclChannel];
|
||||
[[channel adaptorContext] beginTransaction];
|
||||
adaptorCtx = [channel adaptorContext];
|
||||
|
||||
[adaptorCtx beginTransaction];
|
||||
userRoles = [roles objectEnumerator];
|
||||
objectPath = [NSString stringWithFormat: @"/%@", objectPath];
|
||||
while ((currentRole = [userRoles nextObject]))
|
||||
{
|
||||
int i = 0;
|
||||
int count = 0;
|
||||
adaptor = [adaptorCtx adaptor];
|
||||
attribute = [EOAttribute new];
|
||||
[attribute autorelease];
|
||||
if ([GCSFolderManager singleStoreMode])
|
||||
SQL = [NSString stringWithFormat: @"INSERT INTO %@"
|
||||
@" (c_object, c_uid, c_role, c_folder_id)"
|
||||
@" VALUES ('/%@', '%@', '%@', %@)",
|
||||
[folder aclTableName],
|
||||
objectPath, uid, currentRole, [folder folderId]];
|
||||
{
|
||||
sqlstr = [NSMutableString stringWithFormat: @"INSERT INTO %@"
|
||||
@" (c_object, c_uid, c_role, c_folder_id)"
|
||||
@" VALUES (",
|
||||
[folder aclTableName]];
|
||||
NSArray *keys = [NSArray arrayWithObjects: @"c_object", @"c_uid", @"c_role", @"c_folder_id", nil];
|
||||
NSArray *values = [NSArray arrayWithObjects: objectPath, uid, currentRole, [folder folderId], nil];
|
||||
|
||||
for (i = 0, count = [keys count]; i < count; i++) {
|
||||
fieldName = [keys objectAtIndex: i];
|
||||
if(i < 3)
|
||||
[attribute setExternalType: @"varchar"];
|
||||
else
|
||||
[attribute setExternalType: @"int"];
|
||||
value = [values objectAtIndex: i];
|
||||
if (attribute)
|
||||
{
|
||||
value = [adaptor formatValue: value forAttribute: attribute];
|
||||
[sqlstr appendString: value];
|
||||
if(i < 3)
|
||||
[sqlstr appendString:@", "];
|
||||
}
|
||||
}
|
||||
[sqlstr appendString:@")"];
|
||||
}
|
||||
else
|
||||
SQL = [NSString stringWithFormat: @"INSERT INTO %@"
|
||||
@" (c_object, c_uid, c_role)"
|
||||
@" VALUES ('/%@', '%@', '%@')",
|
||||
[folder aclTableName],
|
||||
objectPath, uid, currentRole];
|
||||
[channel evaluateExpressionX: SQL];
|
||||
{
|
||||
sqlstr = [NSMutableString stringWithFormat: @"INSERT INTO %@"
|
||||
@" (c_object, c_uid, c_role)"
|
||||
@" VALUES (",
|
||||
[folder aclTableName]];
|
||||
NSArray *keys = [NSArray arrayWithObjects: @"c_object", @"c_uid", @"c_role", nil];
|
||||
NSArray *values = [NSArray arrayWithObjects: objectPath, uid, currentRole, nil];
|
||||
|
||||
for (i = 0, count = [keys count]; i < count; i++) {
|
||||
fieldName = [keys objectAtIndex: i];
|
||||
[attribute setExternalType: @"varchar"];
|
||||
value = [values objectAtIndex: i];
|
||||
if (attribute)
|
||||
{
|
||||
value = [adaptor formatValue: value forAttribute: attribute];
|
||||
[sqlstr appendString: value];
|
||||
if(i < 2)
|
||||
[sqlstr appendString:@", "];
|
||||
}
|
||||
}
|
||||
[sqlstr appendString:@")"];
|
||||
}
|
||||
[channel evaluateExpressionX: sqlstr];
|
||||
}
|
||||
|
||||
[[channel adaptorContext] commitTransaction];
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
@class NSException;
|
||||
@class NSTimeZone;
|
||||
@class NSURL;
|
||||
@class NSUUID;
|
||||
|
||||
@class WOContext;
|
||||
@class WORequest;
|
||||
@@ -74,6 +75,9 @@
|
||||
+ (NSString *) globallyUniqueObjectId;
|
||||
- (NSString *) globallyUniqueObjectId;
|
||||
|
||||
+ (NSString *) mailUniqueMessageId;
|
||||
- (NSString *) mailUniqueMessageId;
|
||||
|
||||
+ (id) objectWithName: (NSString *)_name inContainer:(id)_container;
|
||||
|
||||
- (id) initWithName: (NSString *) _name inContainer:(id)_container;
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#import <unistd.h>
|
||||
|
||||
|
||||
#import <NGObjWeb/SoClass.h>
|
||||
#import <NGObjWeb/SoObject+SoDAV.h>
|
||||
#import <NGObjWeb/WOApplication.h>
|
||||
@@ -111,11 +110,28 @@
|
||||
pid, (int) f, sequence++, (int) rndm];
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) globallyUniqueObjectId
|
||||
{
|
||||
return [[self class] globallyUniqueObjectId];
|
||||
}
|
||||
|
||||
+ (NSString *) mailUniqueMessageId
|
||||
{
|
||||
/*
|
||||
843F8180-4E33-7B0B-6F1B-9847CAD3E6EB
|
||||
*/
|
||||
return [[NSUUID UUID] UUIDString];
|
||||
}
|
||||
|
||||
- (NSString *) mailUniqueMessageId
|
||||
{
|
||||
/*
|
||||
843F8180-4E33-7B0B-6F1B-9847CAD3E6EB
|
||||
*/
|
||||
return [[self class] mailUniqueMessageId];
|
||||
}
|
||||
|
||||
/* containment */
|
||||
|
||||
+ (id) objectWithName: (NSString *)_name inContainer:(id)_container
|
||||
|
||||
@@ -66,7 +66,6 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer);
|
||||
NSString *openIdClient;
|
||||
NSString *openIdClientSecret;
|
||||
NSString *openIdEmailParam;
|
||||
NSString *openIdHttpVersion;
|
||||
BOOL openIdEnableRefreshToken;
|
||||
BOOL sendDomainInfo;
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
@implementation SimpleOpenIdResponse
|
||||
|
||||
- (id)init {
|
||||
@@ -152,7 +151,7 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
- (void) initializeWithConfig: (NSDictionary *) _config
|
||||
{
|
||||
SOGoSystemDefaults *sd;
|
||||
id refreshTokenBool, domainInfo;
|
||||
id refreshTokenBool, domainInfo, intForKey;
|
||||
|
||||
if([_config objectForKey: @"SOGoOpenIdConfigUrl"] &&
|
||||
[_config objectForKey: @"SOGoOpenIdScope"] &&
|
||||
@@ -164,7 +163,6 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
openIdClient = [_config objectForKey: @"SOGoOpenIdClient"];
|
||||
openIdClientSecret = [_config objectForKey: @"SOGoOpenIdClientSecret"];
|
||||
openIdEmailParam = [_config objectForKey: @"SOGoOpenIdEmailParam"];
|
||||
openIdHttpVersion = [_config objectForKey: @"SOGoOpenIdHttpVersion"];
|
||||
|
||||
openIdEnableRefreshToken = NO;
|
||||
refreshTokenBool = [_config objectForKey: @"SOGoOpenIdEnableRefreshToken"];
|
||||
@@ -176,8 +174,12 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
if (domainInfo && [domainInfo respondsToSelector: @selector (boolValue)])
|
||||
sendDomainInfo = [domainInfo boolValue];
|
||||
|
||||
|
||||
userTokenInterval = [_config objectForKey: @"SOGoOpenIdTokenCheckInterval"];
|
||||
intForKey = [_config objectForKey: @"SOGoOpenIdTokenCheckInterval"];
|
||||
if (intForKey && [intForKey respondsToSelector: @selector (intValue)])
|
||||
userTokenInterval = [intForKey intValue];
|
||||
else
|
||||
userTokenInterval = 0;
|
||||
|
||||
[self _loadSessionFromCache: forDomain];
|
||||
|
||||
if(cacheUpdateNeeded)
|
||||
@@ -223,7 +225,6 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
openIdClient = [sd openIdClient];
|
||||
openIdClientSecret = [sd openIdClientSecret];
|
||||
openIdEmailParam = [sd openIdEmailParam];
|
||||
openIdHttpVersion = [sd openIdHttpVersion];
|
||||
openIdEnableRefreshToken = [sd openIdEnableRefreshToken];
|
||||
userTokenInterval = [sd openIdTokenCheckInterval];
|
||||
sendDomainInfo = [sd openIdSendDomainInfo];
|
||||
@@ -352,16 +353,19 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
NSLog(@"OpenId perform request: response is: %@", response);
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
return [response autorelease];
|
||||
}
|
||||
else if (status == 404)
|
||||
{
|
||||
[self errorWithFormat: @"OpenID endpoint not found (404): %@", endpoint];
|
||||
curl_easy_cleanup(curl);
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"OpenID server internal error during %@: %@", endpoint, response];
|
||||
curl_easy_cleanup(curl);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
@@ -370,7 +374,7 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
[self errorWithFormat: @"CURL error while accessing %@ (%d): %@", endpoint, rc,
|
||||
[NSString stringWithCString: strlen(error) ? error : curl_easy_strerror(rc)]];
|
||||
}
|
||||
curl_easy_cleanup (curl);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -819,13 +823,16 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
- (NSMutableDictionary *) fetchUserInfo
|
||||
{
|
||||
NSString *location, *auth, *content;
|
||||
SOGoSystemDefaults *sd;
|
||||
SimpleOpenIdResponse *response;
|
||||
// WOResponse *response;
|
||||
NSUInteger status;
|
||||
NSMutableDictionary *result;
|
||||
NSDictionary *profile, *headers;
|
||||
NSURL *url;
|
||||
NSString *email;
|
||||
NSString *email, *type, *user_domain;
|
||||
NSRange r;
|
||||
NSArray *domainsAllowed;
|
||||
|
||||
result = [NSMutableDictionary dictionary];
|
||||
[result setObject: @"ok" forKey: @"error"];
|
||||
@@ -867,6 +874,36 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
"email":"myuser@user.com"}*/
|
||||
if (email = [profile objectForKey: self->openIdEmailParam])
|
||||
{
|
||||
//Check the mail domain is ok
|
||||
|
||||
r = [email rangeOfString: @"@"];
|
||||
if (r.location != NSNotFound)
|
||||
user_domain = [email substringFromIndex: r.location+1];
|
||||
else
|
||||
{
|
||||
[self logWithFormat: @"Error mail from userInfo not a mail %@", email];
|
||||
[result setObject: @"mail-error" forKey: @"error"];
|
||||
return result;
|
||||
}
|
||||
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
if(self->forDomain != nil && [sd doesLoginTypeByDomain])
|
||||
{
|
||||
type = [sd getLoginTypeForDomain: self->forDomain];
|
||||
if(type != nil && [type isEqualToString: @"openid"] && ![user_domain isEqualToString: self->forDomain])
|
||||
{
|
||||
[self errorWithFormat: @"Openid userinfo email is not the right domain. Excpected: %@, Got %@", self->forDomain, user_domain];
|
||||
[result setObject: @"mail-error" forKey: @"error"];
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if(((domainsAllowed = [sd domainsAllowed]) && [domainsAllowed count] > 0) && ![domainsAllowed containsObject: user_domain])
|
||||
{
|
||||
[self errorWithFormat: @"Openid userinfo email domain is not allowed. Got %@", user_domain];
|
||||
[result setObject: @"mail-error" forKey: @"error"];
|
||||
return result;
|
||||
}
|
||||
|
||||
if(self->userTokenInterval > 0)
|
||||
[self _saveUserToCache: email];
|
||||
[result setObject: email forKey: @"login"];
|
||||
@@ -945,7 +982,7 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
}
|
||||
}
|
||||
|
||||
//The acces token hasn't work, delete the session in database if needed
|
||||
//The access token hasn't work, delete the session in database if needed
|
||||
if(self->accessToken)
|
||||
{
|
||||
[[[GCSFolderManager defaultFolderManager] openIdFolder] deleteOpenIdSessionFor: self->accessToken];
|
||||
@@ -958,6 +995,12 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
//remove old session
|
||||
[[[GCSFolderManager defaultFolderManager] openIdFolder] deleteOpenIdSessionFor: self->accessToken];
|
||||
}
|
||||
if([[resultUserInfo objectForKey: @"error"] isEqualToString: @"mail-error"])
|
||||
{
|
||||
//Means there is a problem with the mail get from userInfo (logs wil explained)
|
||||
//To avoid infinite loop -> openid -> redirect sogo -> useinfo fail -> rediretc to sogo index -> redirect to openid...
|
||||
return nil;
|
||||
}
|
||||
|
||||
return @"anonymous";
|
||||
}
|
||||
|
||||
@@ -790,10 +790,10 @@ static NSString *sieveScriptName = @"sogo";
|
||||
imapAuthMech = nil;
|
||||
if([sd doesLoginTypeByDomain])
|
||||
{
|
||||
r = [theUsername rangeOfString: @"@"];
|
||||
r = [authname rangeOfString: @"@"];
|
||||
if (r.location != NSNotFound)
|
||||
{
|
||||
userDomain = [theUsername substringFromIndex: r.location+1];
|
||||
userDomain = [authname substringFromIndex: r.location+1];
|
||||
imapAuthMech = [sd getImapAuthMechForDomain: userDomain];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,6 @@ NSComparisonResult languageSort(id el1, id el2, void *context);
|
||||
- (NSString *) openIdClient;
|
||||
- (NSString *) openIdClientSecret;
|
||||
- (NSString *) openIdEmailParam;
|
||||
- (NSString *) openIdHttpVersion;
|
||||
- (BOOL) openIdEnableRefreshToken;
|
||||
- (BOOL) openIdLogoutEnabled: (NSString *) _domain;
|
||||
- (int) openIdTokenCheckInterval;
|
||||
@@ -150,6 +149,7 @@ NSComparisonResult languageSort(id el1, id el2, void *context);
|
||||
- (BOOL) isEasUIDisabled;
|
||||
|
||||
- (BOOL)isPasswordRecoveryEnabled;
|
||||
- (NSArray *) passwordRecoveryBaseURLs;
|
||||
- (NSArray *) passwordRecoveryDomains;
|
||||
- (NSString *) JWTSecret;
|
||||
|
||||
|
||||
@@ -784,15 +784,6 @@ NSComparisonResult languageSort(id el1, id el2, void *context)
|
||||
return emailParam;
|
||||
}
|
||||
|
||||
- (NSString *) openIdHttpVersion
|
||||
{
|
||||
NSString *httpVersion;
|
||||
httpVersion = [self stringForKey: @"SOGoOpenIdHttpVersion"];
|
||||
if(!httpVersion)
|
||||
httpVersion = @"HTTP/1.1";
|
||||
return httpVersion;
|
||||
}
|
||||
|
||||
- (BOOL) openIdLogoutEnabled: (NSString *) _domain
|
||||
{
|
||||
if(_domain && [self doesLoginTypeByDomain])
|
||||
@@ -1091,6 +1082,11 @@ NSComparisonResult languageSort(id el1, id el2, void *context)
|
||||
return [self boolForKey: @"SOGoPasswordRecoveryEnabled"];
|
||||
}
|
||||
|
||||
- (NSArray *) passwordRecoveryBaseURLs
|
||||
{
|
||||
return [self stringArrayForKey: @"SOGoPasswordRecoveryBaseURLs"];
|
||||
}
|
||||
|
||||
- (NSArray *) passwordRecoveryDomains
|
||||
{
|
||||
static NSArray *passwordRecoveryDomains = nil;
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
|
||||
- (BOOL) isSuperUser;
|
||||
- (BOOL) canAuthenticate;
|
||||
- (NSString *) totpKey;
|
||||
- (NSString *) totpKey: (bool) isCheck;
|
||||
- (NSString *) oldtotpKey;
|
||||
|
||||
/* resource */
|
||||
- (BOOL) isResource;
|
||||
|
||||
+135
-81
@@ -47,7 +47,6 @@
|
||||
|
||||
#import "SOGoUser.h"
|
||||
|
||||
static const NSString *kEncryptedUserNamePrefix = @"uenc";
|
||||
|
||||
@implementation SoUser (SOGoExtension)
|
||||
|
||||
@@ -145,92 +144,91 @@ static const NSString *kEncryptedUserNamePrefix = @"uenc";
|
||||
realUID = nil;
|
||||
domain = nil;
|
||||
|
||||
if ([newLogin isEqualToString: @"anonymous"]
|
||||
|| [newLogin isEqualToString: @"freebusy"])
|
||||
if ([newLogin isEqualToString: @"anonymous"] || [newLogin isEqualToString: @"freebusy"])
|
||||
realUID = newLogin;
|
||||
else
|
||||
{
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
if ([sd enableDomainBasedUID] || [[sd loginDomains] count] > 0)
|
||||
{
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
if ([sd enableDomainBasedUID] || [[sd loginDomains] count] > 0)
|
||||
{
|
||||
r = [newLogin rangeOfString: @"@" options: NSBackwardsSearch];
|
||||
if (r.location != NSNotFound)
|
||||
{
|
||||
// The domain is probably appended to the username;
|
||||
// make sure it is defined as a domain in the configuration.
|
||||
domain = [newLogin substringFromIndex: (r.location + r.length)];
|
||||
if ([[SOGoUserManager sharedUserManager] isDomainDefined: domain] &&
|
||||
![sd enableDomainBasedUID])
|
||||
newLogin = [newLogin substringToIndex: r.location];
|
||||
r = [newLogin rangeOfString: @"@" options: NSBackwardsSearch];
|
||||
if (r.location != NSNotFound)
|
||||
{
|
||||
// The domain is probably appended to the username;
|
||||
// make sure it is defined as a domain in the configuration.
|
||||
domain = [newLogin substringFromIndex: (r.location + r.length)];
|
||||
if ([[SOGoUserManager sharedUserManager] isDomainDefined: domain] &&
|
||||
![sd enableDomainBasedUID])
|
||||
newLogin = [newLogin substringToIndex: r.location];
|
||||
|
||||
if (domain != nil && ![sd enableDomainBasedUID])
|
||||
// Login domains are enabled (SOGoLoginDomains) but not
|
||||
// domain-based UID (SOGoEnableDomainBasedUID).
|
||||
// Drop the domain from the login name.
|
||||
domain = nil;
|
||||
}
|
||||
}
|
||||
|
||||
newLogin = [newLogin stringByReplacingString: @"%40"
|
||||
withString: @"@"];
|
||||
if (b)
|
||||
realUID = newLogin;
|
||||
else
|
||||
{
|
||||
um = [SOGoUserManager sharedUserManager];
|
||||
contactInfos = [um contactInfosForUserWithUIDorEmail: newLogin
|
||||
inDomain: domain];
|
||||
realUID = [contactInfos objectForKey: @"c_uid"];
|
||||
if (domain == nil && [sd enableDomainBasedUID])
|
||||
domain = [contactInfos objectForKey: @"c_domain"];
|
||||
}
|
||||
|
||||
if ([realUID length] && [domain length])
|
||||
{
|
||||
// When the user is associated to a domain, the [SOGoUser login]
|
||||
// method returns the combination login@domain while
|
||||
// [SOGoUser loginInDomain] only returns the login.
|
||||
r = [realUID rangeOfString: domain options: NSBackwardsSearch|NSCaseInsensitiveSearch];
|
||||
|
||||
// Do NOT strip @domain.com if SOGoEnableDomainBasedUID is enabled since
|
||||
// the real login most likely is the email address.
|
||||
if (r.location != NSNotFound && ![sd enableDomainBasedUID])
|
||||
uid = [realUID substringToIndex: r.location-1];
|
||||
// If we don't have the domain in the UID but SOGoEnableDomainBasedUID is
|
||||
// enabled, let's add it internally so so it becomes unique across
|
||||
// all potential domains.
|
||||
else if (r.location == NSNotFound && [sd enableDomainBasedUID])
|
||||
{
|
||||
uid = [NSString stringWithString: realUID];
|
||||
realUID = [NSString stringWithFormat: @"%@@%@", realUID, domain];
|
||||
}
|
||||
// We found the domain and SOGoEnableDomainBasedUID is enabled,
|
||||
// we keep realUID.. This would happen for example if the user
|
||||
// authenticates with foo@bar.com and the UIDFieldName is also foo@bar.com
|
||||
else if ([sd enableDomainBasedUID])
|
||||
uid = [NSString stringWithString: realUID];
|
||||
}
|
||||
if (domain != nil && ![sd enableDomainBasedUID])
|
||||
// Login domains are enabled (SOGoLoginDomains) but not
|
||||
// domain-based UID (SOGoEnableDomainBasedUID).
|
||||
// Drop the domain from the login name.
|
||||
domain = nil;
|
||||
}
|
||||
}
|
||||
|
||||
newLogin = [newLogin stringByReplacingString: @"%40"
|
||||
withString: @"@"];
|
||||
if (b)
|
||||
realUID = newLogin;
|
||||
else
|
||||
{
|
||||
um = [SOGoUserManager sharedUserManager];
|
||||
contactInfos = [um contactInfosForUserWithUIDorEmail: newLogin
|
||||
inDomain: domain];
|
||||
realUID = [contactInfos objectForKey: @"c_uid"];
|
||||
if (domain == nil && [sd enableDomainBasedUID])
|
||||
domain = [contactInfos objectForKey: @"c_domain"];
|
||||
}
|
||||
|
||||
if ([realUID length] && [domain length])
|
||||
{
|
||||
// When the user is associated to a domain, the [SOGoUser login]
|
||||
// method returns the combination login@domain while
|
||||
// [SOGoUser loginInDomain] only returns the login.
|
||||
r = [realUID rangeOfString: domain options: NSBackwardsSearch|NSCaseInsensitiveSearch];
|
||||
|
||||
// Do NOT strip @domain.com if SOGoEnableDomainBasedUID is enabled since
|
||||
// the real login most likely is the email address.
|
||||
if (r.location != NSNotFound && ![sd enableDomainBasedUID])
|
||||
uid = [realUID substringToIndex: r.location-1];
|
||||
// If we don't have the domain in the UID but SOGoEnableDomainBasedUID is
|
||||
// enabled, let's add it internally so so it becomes unique across
|
||||
// all potential domains.
|
||||
else if (r.location == NSNotFound && [sd enableDomainBasedUID])
|
||||
{
|
||||
uid = [NSString stringWithString: realUID];
|
||||
realUID = [NSString stringWithFormat: @"%@@%@", realUID, domain];
|
||||
}
|
||||
// We found the domain and SOGoEnableDomainBasedUID is enabled,
|
||||
// we keep realUID.. This would happen for example if the user
|
||||
// authenticates with foo@bar.com and the UIDFieldName is also foo@bar.com
|
||||
else if ([sd enableDomainBasedUID])
|
||||
uid = [NSString stringWithString: realUID];
|
||||
}
|
||||
}
|
||||
|
||||
if ([realUID length])
|
||||
{
|
||||
if ((self = [super initWithLogin: realUID roles: newRoles]))
|
||||
{
|
||||
if ((self = [super initWithLogin: realUID roles: newRoles]))
|
||||
{
|
||||
allEmails = nil;
|
||||
currentPassword = nil;
|
||||
cn = nil;
|
||||
ASSIGN (loginInDomain, (uid ? uid : realUID));
|
||||
_defaults = nil;
|
||||
_domainDefaults = nil;
|
||||
_settings = nil;
|
||||
mailAccounts = nil;
|
||||
}
|
||||
allEmails = nil;
|
||||
currentPassword = nil;
|
||||
cn = nil;
|
||||
ASSIGN (loginInDomain, (uid ? uid : realUID));
|
||||
_defaults = nil;
|
||||
_domainDefaults = nil;
|
||||
_settings = nil;
|
||||
mailAccounts = nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
{
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -265,6 +263,14 @@ static const NSString *kEncryptedUserNamePrefix = @"uenc";
|
||||
|
||||
- (NSString *) loginInDomain
|
||||
{
|
||||
SOGoSystemDefaults *sd;
|
||||
NSString *_domain, *realLoginInDomain;
|
||||
NSRange r;
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
if ([sd enableDomainBasedUID] || [[sd loginDomains] count] > 0)
|
||||
{
|
||||
return self->login;
|
||||
}
|
||||
return loginInDomain;
|
||||
}
|
||||
|
||||
@@ -1292,7 +1298,7 @@ static const NSString *kEncryptedUserNamePrefix = @"uenc";
|
||||
return [authValue boolValue];
|
||||
}
|
||||
|
||||
- (NSString *) totpKey
|
||||
- (NSString *) totpKey: (bool) isCheck
|
||||
{
|
||||
#if defined(MFA_CONFIG)
|
||||
NSString *key, *result;
|
||||
@@ -1301,6 +1307,51 @@ static const NSString *kEncryptedUserNamePrefix = @"uenc";
|
||||
|
||||
size_t s_len, secret_len;
|
||||
|
||||
//Until 5.12.4, SOGo had two problems with totp:
|
||||
// * It was not renew after a user disable it/renable it.
|
||||
// * The length was too small: 12 instead of the recommanded 20
|
||||
|
||||
if(![_defaults totpEnabled])
|
||||
{
|
||||
//Totp was not enabled
|
||||
//Only renew if this is not a check (happen when the user enable it for the first time and save its preferences
|
||||
//the saveAction will check the totp code but [_defaults totpEnabled] is still False )
|
||||
key = [[self userSettings] userCurrentTotpKey: !isCheck];
|
||||
}
|
||||
else
|
||||
{
|
||||
//Totp currently enabled
|
||||
key = [[self userSettings] userCurrentTotpKey: NO];
|
||||
}
|
||||
|
||||
s = [key UTF8String];
|
||||
s_len = strlen(s);
|
||||
|
||||
oath_init();
|
||||
oath_base32_encode(s,s_len, &secret, &secret_len);
|
||||
oath_done();
|
||||
|
||||
result = [[NSString alloc] initWithBytesNoCopy: secret
|
||||
length: secret_len
|
||||
encoding: NSASCIIStringEncoding
|
||||
freeWhenDone: YES];
|
||||
|
||||
return [result autorelease];
|
||||
#else
|
||||
return nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (NSString *) oldtotpKey
|
||||
{
|
||||
#if defined(MFA_CONFIG)
|
||||
//Was used before 5.12.5, is to not make obsolete totp profile set before
|
||||
NSString *key, *result;
|
||||
const char *s;
|
||||
char *secret;
|
||||
|
||||
size_t s_len, secret_len;
|
||||
|
||||
key = [[[self userSettings] userPrivateSalt] substringToIndex: 12];
|
||||
s = [key UTF8String];
|
||||
s_len = strlen(s);
|
||||
@@ -1364,7 +1415,7 @@ static const NSString *kEncryptedUserNamePrefix = @"uenc";
|
||||
return username;
|
||||
|
||||
cache = [SOGoCache sharedCache];
|
||||
cacheKey = [NSString stringWithFormat: @"%@_%@", kEncryptedUserNamePrefix, username];
|
||||
cacheKey = [NSString stringWithFormat: @"encrypted_%@",username];
|
||||
|
||||
exception = nil;
|
||||
tmp = nil;
|
||||
@@ -1395,11 +1446,14 @@ static const NSString *kEncryptedUserNamePrefix = @"uenc";
|
||||
NSString *tmp, *cacheKey;
|
||||
SOGoCache *cache;
|
||||
|
||||
if (![[SOGoSystemDefaults sharedSystemDefaults] isURLEncryptionEnabled] || [username isEqualToString: @"anonymous"] || [[request requestHandlerKey] isEqualToString:@"dav"])
|
||||
if (![[SOGoSystemDefaults sharedSystemDefaults] isURLEncryptionEnabled] ||
|
||||
[username isEqualToString: @"anonymous"] ||
|
||||
[[request requestHandlerKey] isEqualToString:@"dav"] ||
|
||||
[[request requestHandlerPath] hasSuffix: @"freebusy.ifb/ajaxRead"])
|
||||
return username;
|
||||
|
||||
cache = [SOGoCache sharedCache];
|
||||
cacheKey = [NSString stringWithFormat: @"%@_%@", kEncryptedUserNamePrefix, username];
|
||||
cacheKey = [NSString stringWithFormat: @"decrypted_%@", username];
|
||||
exception = nil;
|
||||
tmp = nil;
|
||||
|
||||
|
||||
@@ -156,12 +156,14 @@ extern NSString *SOGoPasswordRecoverySecondaryEmail;
|
||||
- (void) setMailComposeFontSize: (int) newValue;
|
||||
- (int) mailComposeFontSize;
|
||||
|
||||
- (void) setMailDisplayFullEmail: (BOOL *) newValue;
|
||||
- (BOOL *) mailDisplayFullEmail;
|
||||
- (void) setMailDisplayFullEmail: (BOOL) newValue;
|
||||
- (BOOL) mailDisplayFullEmail;
|
||||
|
||||
- (void) setMailDisplayRemoteInlineImages: (NSString *) newValue;
|
||||
- (NSString *) mailDisplayRemoteInlineImages;
|
||||
|
||||
- (void) setMailDisplayAttachmentAbove: (BOOL) newValue;
|
||||
- (BOOL) mailDisplayAttachmentAbove;
|
||||
|
||||
- (void) setMailAutoMarkAsReadDelay: (int) newValue;
|
||||
- (int) mailAutoMarkAsReadDelay;
|
||||
|
||||
@@ -152,7 +152,7 @@ NSString *SOGoPasswordRecoverySecondaryEmail = @"SecondaryEmail";
|
||||
rc = NO;
|
||||
|
||||
if ([fullName length])
|
||||
[identity setObject: [fullName stringWithoutHTMLInjection: YES] forKey: @"fullName"];
|
||||
[identity setObject: [fullName stringWithoutHTMLInjection: YES stripAngular:NO] forKey: @"fullName"];
|
||||
if ([email length])
|
||||
[identity setObject: email forKey: @"email"];
|
||||
if ([replyTo length])
|
||||
@@ -634,12 +634,12 @@ NSString *SOGoPasswordRecoverySecondaryEmail = @"SecondaryEmail";
|
||||
return [self integerForKey: @"SOGoMailComposeFontSize"];
|
||||
}
|
||||
|
||||
- (void) setMailDisplayFullEmail: (BOOL *) newValue
|
||||
- (void) setMailDisplayFullEmail: (BOOL) newValue
|
||||
{
|
||||
[self setBool: newValue forKey: @"SOGoMailDisplayFullEmail"];
|
||||
}
|
||||
|
||||
- (BOOL *) mailDisplayFullEmail;
|
||||
- (BOOL) mailDisplayFullEmail;
|
||||
{
|
||||
return [self boolForKey: @"SOGoMailDisplayFullEmail"];
|
||||
}
|
||||
@@ -654,6 +654,16 @@ NSString *SOGoPasswordRecoverySecondaryEmail = @"SecondaryEmail";
|
||||
return [self stringForKey: @"SOGoMailDisplayRemoteInlineImages"];
|
||||
}
|
||||
|
||||
- (void) setMailDisplayAttachmentAbove: (BOOL) newValue
|
||||
{
|
||||
[self setBool: newValue forKey: @"SOGoMailDisplayAttachmentAbove"];
|
||||
}
|
||||
|
||||
- (BOOL) mailDisplayAttachmentAbove;
|
||||
{
|
||||
return [self boolForKey: @"SOGoMailDisplayAttachmentAbove"];
|
||||
}
|
||||
|
||||
- (void) setMailAutoMarkAsReadDelay: (int) newValue
|
||||
{
|
||||
[self setInteger: newValue forKey: @"SOGoMailAutoMarkAsReadDelay"];
|
||||
@@ -854,7 +864,7 @@ NSString *SOGoPasswordRecoverySecondaryEmail = @"SecondaryEmail";
|
||||
if (mailIdentity && [mailIdentity objectForKey: @"fullName"]) {
|
||||
fullName = [NSString stringWithString: [mailIdentity objectForKey: @"fullName"]];
|
||||
if (fullName) {
|
||||
[mailIdentity setObject: [fullName stringWithoutHTMLInjection: YES] forKey: @"fullName"];
|
||||
[mailIdentity setObject: [fullName stringWithoutHTMLInjection: YES stripAngular:NO] forKey: @"fullName"];
|
||||
[mailIdentities setObject: mailIdentity atIndexedSubscript: i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
- (NSArray *) subscribedCalendars;
|
||||
- (NSArray *) subscribedAddressBooks;
|
||||
- (NSString *) userPrivateSalt;
|
||||
- (NSString *) userCurrentTotpKey: (bool) renew;
|
||||
- (void) setTotpKey: (NSString* ) newKey;
|
||||
- (NSString *) userPublicSalt;
|
||||
- (void)enableForceResetPassword;
|
||||
- (void)disableForceResetPassword;
|
||||
|
||||
@@ -116,6 +116,42 @@ static Class SOGoUserProfileKlass = Nil;
|
||||
return salt;
|
||||
}
|
||||
|
||||
- (NSString *) userCurrentTotpKey: (bool) renew
|
||||
{
|
||||
NSMutableDictionary *values;
|
||||
NSString *key;
|
||||
|
||||
key = [[self dictionaryForKey: @"General"] objectForKey: @"totpKey"];
|
||||
|
||||
if (!key || renew)
|
||||
{
|
||||
key = [[[[NSProcessInfo processInfo] globallyUniqueString] asSHA1String] substringToIndex: 20];
|
||||
values = [self objectForKey: @"General"];
|
||||
|
||||
if (!values)
|
||||
values = [NSMutableDictionary dictionary];
|
||||
|
||||
[values setObject: key forKey: @"totpKey"];
|
||||
[self setObject: values forKey: @"General"];
|
||||
[self synchronize];
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
- (void) setTotpKey: (NSString* ) newKey
|
||||
{
|
||||
NSMutableDictionary *values;
|
||||
values = [self objectForKey: @"General"];
|
||||
|
||||
if (!values)
|
||||
values = [NSMutableDictionary dictionary];
|
||||
|
||||
[values setObject: newKey forKey: @"totpKey"];
|
||||
[self setObject: values forKey: @"General"];
|
||||
[self synchronize];
|
||||
}
|
||||
|
||||
- (void) enableForceResetPassword
|
||||
{
|
||||
[self setObject: [NSNumber numberWithInt:1] forKey: @"ForceResetPassword"];
|
||||
|
||||
+42
-22
@@ -225,7 +225,7 @@
|
||||
*/
|
||||
- (NSString *) _encryptPassword: (NSString *) plainPassword
|
||||
{
|
||||
NSString *pass;
|
||||
NSString *pass, *passwordScheme;
|
||||
NSString* result;
|
||||
|
||||
pass = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm
|
||||
@@ -254,7 +254,7 @@
|
||||
return [self checkLogin: _login
|
||||
password: _pwd
|
||||
perr: _perr
|
||||
expire: _perr
|
||||
expire: _expire
|
||||
grace: _grace
|
||||
disablepasswordPolicyCheck: NO];
|
||||
}
|
||||
@@ -272,6 +272,7 @@
|
||||
grace: (int *) _grace
|
||||
disablepasswordPolicyCheck: (BOOL) _disablepasswordPolicyCheck
|
||||
{
|
||||
EOAdaptor *adaptor;
|
||||
EOAdaptorChannel *channel;
|
||||
EOQualifier *qualifier;
|
||||
GCSChannelManager *cm;
|
||||
@@ -281,11 +282,13 @@
|
||||
|
||||
rc = NO;
|
||||
|
||||
_login = [_login stringByReplacingString: @"'" withString: @"''"];
|
||||
cm = [GCSChannelManager defaultChannelManager];
|
||||
channel = [cm acquireOpenChannelForURL: _viewURL];
|
||||
if (channel)
|
||||
{
|
||||
EOAdaptorContext *adaptorCtx;
|
||||
adaptorCtx = [channel adaptorContext];
|
||||
adaptor = [adaptorCtx adaptor];
|
||||
if (_loginFields)
|
||||
{
|
||||
NSMutableArray *qualifiers;
|
||||
@@ -324,7 +327,8 @@
|
||||
nil];
|
||||
[qualifier autorelease];
|
||||
}
|
||||
[qualifier appendSQLToString: sql];
|
||||
[qualifier appendSQLToString: sql
|
||||
withAdaptor: adaptor];
|
||||
|
||||
ex = [channel evaluateExpressionX: sql];
|
||||
if (!ex)
|
||||
@@ -430,9 +434,11 @@
|
||||
{
|
||||
BOOL didChange, isOldPwdOk, isPolicyOk;
|
||||
EOAdaptorChannel *channel;
|
||||
EOAdaptor *adaptor;
|
||||
EOQualifier *qualifier_login, *qualifier_pwd;
|
||||
GCSChannelManager *cm;
|
||||
NSException *ex;
|
||||
NSString *sqlstr;
|
||||
NSMutableString *sqlstr;
|
||||
|
||||
*perr = -1;
|
||||
isOldPwdOk = NO;
|
||||
@@ -455,16 +461,27 @@
|
||||
return NO;
|
||||
|
||||
// Save new password
|
||||
login = [login stringByReplacingString: @"'" withString: @"''"];
|
||||
cm = [GCSChannelManager defaultChannelManager];
|
||||
channel = [cm acquireOpenChannelForURL: _viewURL];
|
||||
if (channel)
|
||||
{
|
||||
sqlstr = [NSString stringWithFormat: (@"UPDATE %@"
|
||||
@" SET c_password = '%@'"
|
||||
@" WHERE c_uid = '%@'"),
|
||||
[_viewURL gcsTableName], encryptedPassword, login];
|
||||
|
||||
EOAdaptorContext *adaptorCtx;
|
||||
adaptorCtx = [channel adaptorContext];
|
||||
adaptor = [adaptorCtx adaptor];
|
||||
sqlstr = [NSMutableString stringWithFormat: @"UPDATE %@ SET ",
|
||||
[_viewURL gcsTableName]];
|
||||
|
||||
qualifier_pwd = [[EOKeyValueQualifier alloc] initWithKey: @"c_password"
|
||||
operatorSelector: EOQualifierOperatorEqual
|
||||
value: encryptedPassword];
|
||||
[qualifier_pwd appendSQLToString: sqlstr
|
||||
withAdaptor: adaptor];
|
||||
[sqlstr appendString: @" WHERE "];
|
||||
qualifier_login = [[EOKeyValueQualifier alloc] initWithKey: @"c_uid"
|
||||
operatorSelector: EOQualifierOperatorEqual
|
||||
value: login];
|
||||
[qualifier_login appendSQLToString: sqlstr
|
||||
withAdaptor: adaptor];
|
||||
ex = [channel evaluateExpressionX: sqlstr];
|
||||
if (!ex)
|
||||
{
|
||||
@@ -998,7 +1015,9 @@
|
||||
inDomain: (NSString *)domain
|
||||
limit: (int)limit
|
||||
{
|
||||
EOAdaptor *adaptor;
|
||||
EOAdaptorChannel *channel;
|
||||
EOQualifier *qualifier;
|
||||
NSEnumerator *criteriaList;
|
||||
NSMutableArray *fields, *results;
|
||||
GCSChannelManager *cm;
|
||||
@@ -1014,12 +1033,14 @@
|
||||
channel = [cm acquireOpenChannelForURL: _viewURL];
|
||||
if (channel)
|
||||
{
|
||||
EOAdaptorContext *adaptorCtx;
|
||||
adaptorCtx = [channel adaptorContext];
|
||||
adaptor = [adaptorCtx adaptor];
|
||||
fields = [NSMutableArray array];
|
||||
if ([filter length])
|
||||
{
|
||||
lowerFilter = [filter lowercaseString];
|
||||
lowerFilter = [lowerFilter asSafeSQLLikeString];
|
||||
filterFormat = [NSString stringWithFormat: @"LOWER(%%@) LIKE '%%%%%@%%%%'", lowerFilter];
|
||||
filter = [[filter asSafeSQLString] stringByReplacingString: @"\%" withString: @"%%"];
|
||||
filterFormat = [NSString stringWithFormat: @"(%%@ isCaseInsensitiveLike: '*%@*')", filter];
|
||||
if (criteria)
|
||||
criteriaList = [criteria objectEnumerator];
|
||||
else
|
||||
@@ -1044,7 +1065,9 @@
|
||||
if ([fields count])
|
||||
{
|
||||
qs = [[[fields uniqueObjects] stringsWithFormat: filterFormat] componentsJoinedByString: @" OR "];
|
||||
[sql appendString: qs];
|
||||
qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
|
||||
[qualifier appendSQLToString: sql
|
||||
withAdaptor: adaptor];
|
||||
}
|
||||
else
|
||||
[sql appendString: @"1 = 1"];
|
||||
@@ -1108,7 +1131,7 @@
|
||||
andSortOrdering: (EOSortOrdering *) ordering
|
||||
inDomain: (NSString *) domain
|
||||
{
|
||||
static EOAdaptor *adaptor = nil;
|
||||
EOAdaptor *adaptor;
|
||||
NSException *ex;
|
||||
NSMutableArray *results;
|
||||
NSMutableString *sql;
|
||||
@@ -1123,12 +1146,9 @@
|
||||
channel = [cm acquireOpenChannelForURL: _viewURL];
|
||||
if (channel)
|
||||
{
|
||||
if (!adaptor)
|
||||
{
|
||||
EOAdaptorContext *adaptorCtx;
|
||||
adaptorCtx = [channel adaptorContext];
|
||||
adaptor = [adaptorCtx adaptor];
|
||||
}
|
||||
EOAdaptorContext *adaptorCtx;
|
||||
adaptorCtx = [channel adaptorContext];
|
||||
adaptor = [adaptorCtx adaptor];
|
||||
sql = [NSMutableString stringWithFormat: @"SELECT c_name FROM %@ WHERE (", [_viewURL gcsTableName]];
|
||||
|
||||
if (qualifier)
|
||||
|
||||
@@ -99,23 +99,43 @@
|
||||
|
||||
- (void) test_stringWithoutHTMLInjection
|
||||
{
|
||||
testEquals([[NSString stringWithString:@"<a href=\"\">foo</a>bar"] stringWithoutHTMLInjection: YES], @" foo bar");
|
||||
testEquals([[NSString stringWithString:@"fb <foo@bar.com>"] stringWithoutHTMLInjection: YES], @"fb <foo@bar.com>");
|
||||
testEquals([[NSString stringWithString:@"Test\n<script>alert(\"foobar\");"] stringWithoutHTMLInjection: NO], @"Test\n<scr***>alert(\"foobar\");");
|
||||
testEquals([[NSString stringWithString:@"<img vbscript:test"] stringWithoutHTMLInjection: NO], @"<img test");
|
||||
testEquals([[NSString stringWithString:@"<img javascript:test"] stringWithoutHTMLInjection: NO], @"<img test");
|
||||
testEquals([[NSString stringWithString:@"<img livescript:test"] stringWithoutHTMLInjection: NO], @"<img test");
|
||||
testEquals([[NSString stringWithString:@"foobar <form action=\"\">bar</form>"] stringWithoutHTMLInjection: NO], @"foobar <for* action=\"\">bar</for*>");
|
||||
testEquals([[NSString stringWithString:@"foobar <iframe src=\"\">bar</iframe>"] stringWithoutHTMLInjection: NO], @"foobar <ifr*** src=\"\">bar</iframe>");
|
||||
testEquals([[NSString stringWithString:@"foobar <img onload=foo bar"] stringWithoutHTMLInjection: NO], @"foobar <img onl***=foo bar");
|
||||
testEquals([[NSString stringWithString:@"foobar <img onmouseover=foo bar"] stringWithoutHTMLInjection: NO], @"foobar <img onmouseo***=foo bar");
|
||||
testEquals([[NSString stringWithString:@"<!DOCTYPE html><html><head><style>@import url(https://foo.bar/malicious.css);.foo{background-color: red; @import url(https://bar.foo/malicious2.css);</style></head><body><table><tr><td>A</td><td>B</td><td>C</td></tr></table></body></html>"] stringWithoutHTMLInjection: NO], @"<!DOCTYPE html><html><head><style>@im**** url(https://foo.bar/malicious.css);.foo{background-color: red; @im**** url(https://bar.foo/malicious2.css);</style></head><body><table><tr><td>A</td><td>B</td><td>C</td></tr></table></body></html>");
|
||||
testEquals([[NSString stringWithString:@"<a href=\"\">foo</a>bar"] stringWithoutHTMLInjection: YES stripAngular: NO], @" foo bar");
|
||||
testEquals([[NSString stringWithString:@"fb <foo@bar.com>"] stringWithoutHTMLInjection: YES stripAngular: NO], @"fb <foo@bar.com>");
|
||||
testEquals([[NSString stringWithString:@"Test\n<script>alert(\"foobar\");"] stringWithoutHTMLInjection: NO stripAngular: NO], @"Test\n<scr***>alert(\"foobar\");");
|
||||
testEquals([[NSString stringWithString:@"<img vbscript:test"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<img test");
|
||||
testEquals([[NSString stringWithString:@"<img javascript:test"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<img test");
|
||||
testEquals([[NSString stringWithString:@"<img livescript:test"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<img test");
|
||||
testEquals([[NSString stringWithString:@"foobar <form action=\"\">bar</form>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <for* action=\"\">bar</for*>");
|
||||
testEquals([[NSString stringWithString:@"foobar <iframe src=\"\">bar</iframe>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <ifr*** src=\"\">bar</iframe>");
|
||||
testEquals([[NSString stringWithString:@"foobar <img onload=foo bar"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <img data-blocked=foo bar");
|
||||
testEquals([[NSString stringWithString:@"foobar <img onmouseover=foo bar"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <img data-blocked=foo bar");
|
||||
// any on...= handler is neutralised, including whitespace before '=' and names
|
||||
// that were never in the old list
|
||||
testEquals([[NSString stringWithString:@"<img src=x onerror =alert(1)>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<img src=x data-blocked=alert(1)>");
|
||||
testEquals([[NSString stringWithString:@"<input autofocus onfocus=alert(1)>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<input autofocus data-blocked=alert(1)>");
|
||||
// deletion filters loop until stable, so nesting cannot rebuild the scheme
|
||||
testEquals([[NSString stringWithString:@"javajavascript:script:"] stringWithoutHTMLInjection: NO stripAngular: NO], @"");
|
||||
testEquals([[NSString stringWithString:@"<!DOCTYPE html><html><head><style>@import url(https://foo.bar/malicious.css);.foo{background-color: red; @import url(https://bar.foo/malicious2.css);</style></head><body><table><tr><td>A</td><td>B</td><td>C</td></tr></table></body></html>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<!DOCTYPE html><html><head><style>@im**** url(https://foo.bar/malicious.css);.foo{background-color: red; @im**** url(https://bar.foo/malicious2.css);</style></head><body><table><tr><td>A</td><td>B</td><td>C</td></tr></table></body></html>");
|
||||
// the @import cleanup must still run when angular interpolation is stripped as well
|
||||
testEquals([[NSString stringWithString:@"<style>@import url(https://foo.bar/malicious.css);</style>"] stringWithoutHTMLInjection: NO stripAngular: YES], @"<style>@im**** url(https://foo.bar/malicious.css);</style>");
|
||||
// literal braces are rewritten so AngularJS cannot interpolate them
|
||||
testEquals([[NSString stringWithString:@"{{1337*1337}}"] stringWithoutHTMLInjection: NO stripAngular: YES], @"{\\{1337*1337}/}");
|
||||
// ... and so are the decimal HTML entities the browser would decode back to braces
|
||||
testEquals([[NSString stringWithString:@"{{1337*1337}}"] stringWithoutHTMLInjection: NO stripAngular: YES], @"{\\{1337*1337}/}");
|
||||
}
|
||||
|
||||
- (void) test_stringCleanInvalidHTMLTags
|
||||
{
|
||||
testEquals([[NSString stringWithString:@"<div>Test<!--></div>"] cleanInvalidHTMLTags], @"<div>Test</div>");
|
||||
testEquals([[NSString stringWithString:@"<div><!--[if !mso]><span>Test</span><!--<![endif]--></div>"] cleanInvalidHTMLTags], @"<div><!--[if !mso]><span>Test</span><!--[endif]--></div>");
|
||||
testEquals([[NSString stringWithString:@"<div>Test<!---></div>"] cleanInvalidHTMLTags], @"<div>Test</div>");
|
||||
testEquals([[NSString stringWithString:@"<div>A<!-->B<!-- c -->C<!-->D</div>"] cleanInvalidHTMLTags], @"<div>AB<!-- c -->CD</div>");
|
||||
testEquals([[NSString stringWithString:@"<div><!--[if !mso]><span>Test</span><!--<![endif]--></div>"] cleanInvalidHTMLTags], @"<div><!--[if !mso]><span>Test</span><!--<![endif]--></div>");
|
||||
// Outlook "downlevel-revealed" conditional comment: content must stay visible
|
||||
testEquals([[NSString stringWithString:@"<a><!--[if !mso]><!--> <div><img src=\"x\"/></div> <!--<![endif]--><!--[if mso]><v:fill/><![endif]--></a>"] cleanInvalidHTMLTags], @"<a><!--[if !mso]><!--> <div><img src=\"x\"/></div> <!--<![endif]--><!--[if mso]><v:fill/><![endif]--></a>");
|
||||
// libxml2 also ends a comment with "--!>"
|
||||
testEquals([[NSString stringWithString:@"A<!-- x --!>B<!-->C"] cleanInvalidHTMLTags], @"A<!-- x --!>BC");
|
||||
// unterminated comment is left as is
|
||||
testEquals([[NSString stringWithString:@"<div>A<!-- B</div>"] cleanInvalidHTMLTags], @"<div>A<!-- B</div>");
|
||||
}
|
||||
|
||||
- (void) test_stringRemoveHTMLTagsExceptAnchorTags
|
||||
|
||||
@@ -25,6 +25,7 @@ $(SOGO_TOOL)_OBJC_FILES += \
|
||||
SOGoToolCleanupUser.m \
|
||||
SOGoToolRestore.m \
|
||||
SOGoToolCreateFolder.m \
|
||||
SOGoToolInitUser.m \
|
||||
SOGoToolUserPreferences.m \
|
||||
SOGoToolManageACL.m \
|
||||
SOGoToolManageEAS.m \
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
/* SOGoToolInitUser.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2026 Alinto
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSUserDefaults.h>
|
||||
|
||||
#import <NGObjWeb/WOApplication.h>
|
||||
#import <NGObjWeb/WOComponent.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
|
||||
#import <SOGo/SOGoGCSFolder.h>
|
||||
#import <SOGo/SOGoParentFolder.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
|
||||
#import "SOGoToolRestore.h"
|
||||
|
||||
|
||||
@interface NSObject (UIxJSONPreferences)
|
||||
|
||||
- (NSString *) jsonDefaults;
|
||||
|
||||
@end
|
||||
|
||||
@interface SOGoToolInitUser : SOGoToolRestore
|
||||
{
|
||||
NSArray *usersToInit;
|
||||
NSString *language;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation SOGoToolInitUser
|
||||
|
||||
+ (NSString *) command
|
||||
{
|
||||
return @"init-user";
|
||||
}
|
||||
|
||||
+ (NSString *) description
|
||||
{
|
||||
return @"create the personal folders and preferences of user(s) without requiring a login";
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
usersToInit = nil;
|
||||
language = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[usersToInit release];
|
||||
[language release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) usage
|
||||
{
|
||||
fprintf (stderr, "init-user [-l language] user1 [user2] ...\n\n"
|
||||
" user the user whose personal folders must be created\n"
|
||||
" language the language of the user's preferences, as chosen\n"
|
||||
" at login (defaults to the domain or system one)\n\n"
|
||||
"Creates the personal calendar and the personal address book of the\n"
|
||||
"user(s) and initializes their preferences, as it would otherwise only\n"
|
||||
"happen upon their first login.\n\n"
|
||||
"Example: sogo-tool init-user jdoe\n"
|
||||
" sogo-tool init-user -l French jdoe jsmith\n");
|
||||
}
|
||||
|
||||
- (BOOL) parseArguments
|
||||
{
|
||||
NSArray *supportedLanguages;
|
||||
NSString *requestedLanguage;
|
||||
|
||||
if ([sanitizedArguments count] < 1)
|
||||
{
|
||||
[self usage];
|
||||
return NO;
|
||||
}
|
||||
|
||||
requestedLanguage = [[NSUserDefaults standardUserDefaults] stringForKey: @"l"];
|
||||
if ([requestedLanguage length])
|
||||
{
|
||||
supportedLanguages = [[SOGoSystemDefaults sharedSystemDefaults]
|
||||
supportedLanguages];
|
||||
if (![supportedLanguages containsObject: requestedLanguage])
|
||||
{
|
||||
fprintf (stderr, "Unsupported language: %s\n",
|
||||
[requestedLanguage UTF8String]);
|
||||
return NO;
|
||||
}
|
||||
ASSIGN (language, requestedLanguage);
|
||||
}
|
||||
|
||||
ASSIGN (usersToInit, sanitizedArguments);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/* The lookup of the "personal" folder triggers its creation when it does not
|
||||
exist yet, provided the active user is the owner of the folder. */
|
||||
- (BOOL) _initFolderOfType: (NSString *) folderType
|
||||
withUserFolder: (SOGoUserFolder *) userFolder
|
||||
inContext: (WOContext *) localContext
|
||||
{
|
||||
SOGoParentFolder *parentFolder;
|
||||
id folder;
|
||||
|
||||
parentFolder = [userFolder lookupName: folderType
|
||||
inContext: localContext
|
||||
acquire: NO];
|
||||
if (![parentFolder isKindOfClass: [SOGoParentFolder class]])
|
||||
{
|
||||
NSLog (@"module '%@' is not available for user '%@'", folderType, userID);
|
||||
return NO;
|
||||
}
|
||||
[parentFolder setContext: localContext];
|
||||
|
||||
folder = [parentFolder lookupPersonalFolder: @"personal"
|
||||
ignoringRights: YES];
|
||||
if (![folder isKindOfClass: [SOGoGCSFolder class]])
|
||||
{
|
||||
NSLog (@"personal folder of module '%@' could not be created for user"
|
||||
@" '%@'", folderType, userID);
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
NSLog (@"personal folder of module '%@' is ready for user '%@'",
|
||||
folderType, userID);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/* Upon the first login, the c_defaults of the user are materialized when the
|
||||
web interface loads: -[UIxJSONPreferences jsonDefaults] resolves every
|
||||
default through the domain and system defaults, writes them into the user's
|
||||
profile and synchronizes it. We invoke that very method so that an
|
||||
initialized user is indistinguishable from a user who has logged in. */
|
||||
- (BOOL) _initDefaultsOfUser: (SOGoUser *) user
|
||||
inContext: (WOContext *) localContext
|
||||
{
|
||||
WOComponent *jsonPreferences;
|
||||
Class jsonPreferencesKlass;
|
||||
|
||||
/* The language must be set before the component is built: -jsonDefaults only
|
||||
materializes the defaults that are missing, and the labels it localizes
|
||||
(the calendar and contacts categories) are looked up in the languages of
|
||||
the context, which are those of the user. */
|
||||
if (language)
|
||||
[[user userDefaults] setLanguage: language];
|
||||
|
||||
if (![WOApplication application])
|
||||
[[WOApplication alloc] init];
|
||||
|
||||
jsonPreferencesKlass = NSClassFromString (@"UIxJSONPreferences");
|
||||
if (!jsonPreferencesKlass)
|
||||
{
|
||||
NSLog (@"class 'UIxJSONPreferences' is unavailable, defaults of user"
|
||||
@" '%@' cannot be initialized", userID);
|
||||
return NO;
|
||||
}
|
||||
|
||||
jsonPreferences = [[[jsonPreferencesKlass alloc]
|
||||
initWithContext: localContext] autorelease];
|
||||
|
||||
if (![jsonPreferences jsonDefaults])
|
||||
{
|
||||
NSLog (@"defaults of user '%@' could not be initialized", userID);
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
NSLog (@"defaults of user '%@' are ready", userID);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL) _initUser
|
||||
{
|
||||
SOGoUserFolder *userFolder;
|
||||
WOContext *localContext;
|
||||
SOGoUser *user;
|
||||
BOOL rc;
|
||||
|
||||
user = [SOGoUser userWithLogin: userID];
|
||||
if (!user)
|
||||
{
|
||||
NSLog (@"user '%@' could not be instantiated", userID);
|
||||
return NO;
|
||||
}
|
||||
|
||||
localContext = [WOContext context];
|
||||
[localContext setActiveUser: user];
|
||||
|
||||
rc = [self _initDefaultsOfUser: user inContext: localContext];
|
||||
|
||||
userFolder = [SOGoUserFolder objectWithName: userID inContainer: nil];
|
||||
[userFolder setContext: localContext];
|
||||
|
||||
rc = [self _initFolderOfType: @"Calendar"
|
||||
withUserFolder: userFolder
|
||||
inContext: localContext] && rc;
|
||||
rc = [self _initFolderOfType: @"Contacts"
|
||||
withUserFolder: userFolder
|
||||
inContext: localContext] && rc;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
- (BOOL) proceed
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
NSString *identifier;
|
||||
NSUInteger count, max;
|
||||
BOOL rc;
|
||||
|
||||
rc = YES;
|
||||
max = [usersToInit count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
pool = [NSAutoreleasePool new];
|
||||
identifier = [usersToInit objectAtIndex: count];
|
||||
if ([self fetchUserID: identifier])
|
||||
{
|
||||
if (![self _initUser])
|
||||
rc = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Invalid user: %s\n", [identifier UTF8String]);
|
||||
rc = NO;
|
||||
}
|
||||
[pool release];
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
- (BOOL) run
|
||||
{
|
||||
return ([self parseArguments] && [self proceed]);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -172,6 +172,9 @@
|
||||
EOAdaptorContext *ac;
|
||||
EOAdaptorChannel *fc;
|
||||
NSString *profileURL, *sql, *sqlFromUserID, *sqlToUserID;
|
||||
NSString *old_c_default, *old_c_settings, *new_c_default, *new_c_settings;
|
||||
NSArray *attrs;
|
||||
NSDictionary *row;
|
||||
NSException *sqlError;
|
||||
SOGoSystemDefaults *sd;
|
||||
|
||||
@@ -188,9 +191,22 @@
|
||||
|
||||
[ac beginTransaction];
|
||||
|
||||
sql = [NSString stringWithFormat: @"UPDATE %@ SET c_uid = '%@'"
|
||||
sql = [NSString stringWithFormat: @"SELECT c_defaults, c_settings FROM %@"
|
||||
@" WHERE c_uid = '%@'",
|
||||
[profileLocation gcsTableName], sqlToUserID, sqlFromUserID];
|
||||
[profileLocation gcsTableName], sqlFromUserID];
|
||||
sqlError = [fc evaluateExpressionX: sql];
|
||||
attrs = [fc describeResults: NO];
|
||||
while ((row = [fc fetchAttributes: attrs withZone: NULL]))
|
||||
{
|
||||
old_c_default = [row objectForKey: @"c_defaults"];
|
||||
old_c_settings = [row objectForKey: @"c_settings"];
|
||||
new_c_default = [old_c_default stringByReplacingOccurrencesOfString:fromUserID withString:toUserID];
|
||||
new_c_settings = [old_c_settings stringByReplacingOccurrencesOfString:fromUserID withString:toUserID];
|
||||
}
|
||||
|
||||
sql = [NSString stringWithFormat: @"UPDATE %@ SET c_uid = '%@', c_defaults = '%@', "
|
||||
@"c_settings = '%@' WHERE c_uid = '%@'",
|
||||
[profileLocation gcsTableName], sqlToUserID, new_c_default, new_c_settings, sqlFromUserID];
|
||||
sqlError = [fc evaluateExpressionX: sql];
|
||||
if (sqlError)
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"No resource" = "Cap recurs";
|
||||
"Any Authenticated User" = "Qualsevol usuari autenticat";
|
||||
"Public Access" = "Accés públic";
|
||||
"Save" = "Save";
|
||||
"Clear" = "Clear";
|
||||
"Message of the day" = "Message of the day";
|
||||
"Message of the day has been saved" = "Message of the day has been saved";
|
||||
"Save" = "Desar";
|
||||
"Clear" = "Esborrar";
|
||||
"Message of the day" = "Missatge del dia";
|
||||
"Message of the day has been saved" = "El missatge del dia s'ha desat";
|
||||
@@ -4,7 +4,7 @@
|
||||
"Close" = "Schließen";
|
||||
"Modules" = "Module";
|
||||
/* Modules short names */
|
||||
"ACLs" = "ACLs";
|
||||
"ACLs" = "Zugriffsrechte";
|
||||
/* Modules titles */
|
||||
"ACLs_title" = "Benutzerordner ACL-Management";
|
||||
/* Modules descriptions */
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/* this file is in UTF-8 format! */
|
||||
|
||||
"Help" = "Help";
|
||||
"Close" = "Close";
|
||||
"Modules" = "Modules";
|
||||
/* Modules short names */
|
||||
"ACLs" = "ACLs";
|
||||
/* Modules titles */
|
||||
"ACLs_title" = "Users folders ACLs management";
|
||||
/* Modules descriptions */
|
||||
"ACLs_description" = "<p>The Access Control Lists administration module allows to change the ACLs of each user's Calendars and Address books.</p><p>To modify the ACLs of a user's folder, type the name of the user in the search field at the top of the window and double-click on the desired folder.</p>";
|
||||
"Name or Email" = "Name or Email";
|
||||
"ACLs saved" = "ACLs saved";
|
||||
/* Rights module: initial search message */
|
||||
"Start a search to edit the rights" = "Start a search to edit the rights";
|
||||
/* Rights module: Empty search result */
|
||||
"No matching user" = "No matching user";
|
||||
/* Rights module: no selection */
|
||||
"No resource selected" = "No resource selected";
|
||||
"Add User" = "Add User";
|
||||
"Subscribe User" = "Subscribe User";
|
||||
"Rights" = "Rights";
|
||||
"Search Users" = "Search Users";
|
||||
"users found" = "users found";
|
||||
"No resource" = "No resource";
|
||||
"Any Authenticated User" = "Any Authenticated User";
|
||||
"Public Access" = "Public Access";
|
||||
"Save" = "Save";
|
||||
"Clear" = "Clear";
|
||||
"Message of the day" = "Message of the day";
|
||||
"Message of the day has been saved" = "Message of the day has been saved";
|
||||
@@ -25,7 +25,7 @@
|
||||
"No resource" = "Nincs erőforrás";
|
||||
"Any Authenticated User" = "Bármely azonosított felhasználó";
|
||||
"Public Access" = "Nyilvános hozzáférés";
|
||||
"Save" = "Save";
|
||||
"Clear" = "Clear";
|
||||
"Message of the day" = "Message of the day";
|
||||
"Message of the day has been saved" = "Message of the day has been saved";
|
||||
"Save" = "Mentés";
|
||||
"Clear" = "Törlés";
|
||||
"Message of the day" = "A nap üzenete";
|
||||
"Message of the day has been saved" = "A nap üzenete mentésre került";
|
||||
@@ -41,11 +41,11 @@
|
||||
= "Qualsevol usuari amb un compte en el sistema tindrà accés a la seua llibreta d'adreces \"%{0}\". Està segur de voler donar accés a qualsevol usuari en el sistema? ";
|
||||
"Give Access" = "Donar accés";
|
||||
"Keep Private" = "Mantenir en privat";
|
||||
"Expand" = "Expand";
|
||||
"Reduce" = "Reduce";
|
||||
"Expand" = "Expandir";
|
||||
"Reduce" = "Reduir";
|
||||
|
||||
/* tooltip */
|
||||
"Refresh" = "Refresh";
|
||||
"Refresh" = "Actualitzar";
|
||||
|
||||
/* generic.js */
|
||||
"Unable to subscribe to that folder!"
|
||||
@@ -109,7 +109,7 @@
|
||||
"Personal" = "Personal";
|
||||
"To Do" = "Per fer";
|
||||
"Later" = "Més tard";
|
||||
"Forwarded" = "Forwarded";
|
||||
"Forwarded" = "Reenviat";
|
||||
"Return Receipt Sent" = "Justificant de recepció enviat";
|
||||
"a2_Sunday" = "dg";
|
||||
"a2_Monday" = "dl";
|
||||
@@ -128,15 +128,15 @@
|
||||
"S/MIME Certificate" = "Certificat S/MIME";
|
||||
"Subject Name" = "Nom del subjecte";
|
||||
"Issuer" = "Emissor";
|
||||
"streetAddress" = "Street";
|
||||
"stateOrProvinceName" = "State or Province";
|
||||
"localityName" = "Locality";
|
||||
"streetAddress" = "Carrer";
|
||||
"stateOrProvinceName" = "Estat o Província";
|
||||
"localityName" = "Localitat";
|
||||
"countryName" = "País";
|
||||
"organizationName" = "Organització";
|
||||
"organizationalUnitName" = "Unitat organitzativa";
|
||||
"commonName" = "Nom comú";
|
||||
"surname" = "Surname";
|
||||
"givenName" = "Given Name";
|
||||
"surname" = "Cognoms";
|
||||
"givenName" = "Nom de pila";
|
||||
"emailAddress" = "Correu electrònic";
|
||||
|
||||
|
||||
@@ -227,16 +227,16 @@
|
||||
"Move forward" = "Avançar";
|
||||
|
||||
/* Password Recovery */
|
||||
"passwordRecovery_Disabled" = "Disabled";
|
||||
"passwordRecovery_SecretQuestion" = "Secret question";
|
||||
"passwordRecovery_SecretQuestion1" = "What is the name of your first pet ?";
|
||||
"passwordRecovery_SecretQuestion2" = "What was your first car ?";
|
||||
"passwordRecovery_SecretQuestion3" = "What is your favorite movie ?";
|
||||
"passwordRecovery_SecondaryEmail" = "Secondary E-mail";
|
||||
"passwordRecovery_Disabled" = "Desactivat";
|
||||
"passwordRecovery_SecretQuestion" = "Pregunta secreta";
|
||||
"passwordRecovery_SecretQuestion1" = "Quin és el nom de la teva primera mascota?";
|
||||
"passwordRecovery_SecretQuestion2" = "Quin va ser el teu primer cotxe?";
|
||||
"passwordRecovery_SecretQuestion3" = "Quina és la teva pel·lícula preferida?";
|
||||
"passwordRecovery_SecondaryEmail" = "Correu electrònic secundari";
|
||||
|
||||
/* Password */
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Minimum of %{0} lowercase letter";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Minimum of %{0} uppercase letter";
|
||||
"POLICY_MIN_DIGIT" = "Minimum of %{0} digit";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Minimum of %{0} special symbols";
|
||||
"POLICY_MIN_LENGTH" = "Minimum length of %{0} characters";
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Mínim de %{0} lletra minúscula";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Mínim de %{0} lletra majúscula";
|
||||
"POLICY_MIN_DIGIT" = "Mínim de %{0} dígit";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Mínim de %{0} símbols especials";
|
||||
"POLICY_MIN_LENGTH" = "Longitud mínima de %{0} caràcters";
|
||||
@@ -235,8 +235,8 @@
|
||||
"passwordRecovery_SecondaryEmail" = "Sekundární e-mail";
|
||||
|
||||
/* Password */
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Minimum of %{0} lowercase letter";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Minimum of %{0} uppercase letter";
|
||||
"POLICY_MIN_DIGIT" = "Minimum of %{0} digit";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Minimum of %{0} special symbols";
|
||||
"POLICY_MIN_LENGTH" = "Minimum length of %{0} characters";
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Minimum je %{0} malých znaků";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Minimum je %{0} velkých písmen";
|
||||
"POLICY_MIN_DIGIT" = "Minimum je %{0} číslic";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Minimum je %{0} speciálních znaků";
|
||||
"POLICY_MIN_LENGTH" = "Minimální délka je %{0} znaků";
|
||||
@@ -9,7 +9,7 @@
|
||||
"Address Book" = "Adressbuch";
|
||||
"Mail" = "E-Mail";
|
||||
"Preferences" = "Einstellungen";
|
||||
"Administration" = "Administration";
|
||||
"Administration" = "Verwaltung";
|
||||
"Disconnect" = "Beenden";
|
||||
"Toggle Menu" = "Menü umschalten";
|
||||
"Right Administration" = "Rechteadministration";
|
||||
@@ -197,10 +197,10 @@
|
||||
"key_right" = "→";
|
||||
|
||||
/* Shift and up arrow combo keys */
|
||||
"key_shift+up" = "shift + ↑";
|
||||
"key_shift+up" = "Umschalt + ↑";
|
||||
|
||||
/* Shift and down arrow combo keys */
|
||||
"key_shift+down" = "shift + ↓";
|
||||
"key_shift+down" = "Umschalt + ↓";
|
||||
|
||||
/* Backspace key */
|
||||
"key_backspace" = "⌫";
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
/* this file is in UTF-8 format! */
|
||||
|
||||
/* toolbars */
|
||||
"Save" = "Αποθήκευση";
|
||||
"Close" = "Κλείσιμο";
|
||||
"Edit User Rights" = "Επεξεργασία Δικαιωμάτων Χρήστη";
|
||||
"Home" = "Αρχική";
|
||||
"Calendar" = "Ημερολόγιο";
|
||||
"Address Book" = "Επαφές";
|
||||
"Mail" = "Αλληλογραφία";
|
||||
"Preferences" = "Ρυθμίσεις";
|
||||
"Administration" = "Διαχείριση";
|
||||
"Disconnect" = "Αποσύνδεση";
|
||||
"Toggle Menu" = "Εναλλαγή Μενού";
|
||||
"Right Administration" = "Διαχείριση Δικαιωμάτων";
|
||||
"Log Console (dev.)" = "Κονσόλα Καταγραφής (dev.)";
|
||||
"User" = "Χρήστης";
|
||||
"Vacation message is enabled" = "Το μήνυμα απουσίας είναι ενεργοποιημένο";
|
||||
"Help" = "Βοήθεια";
|
||||
"noJavascriptError" = "Το SOGo απαιτεί JavaScript για να λειτουργήσει. Βεβαιωθείτε ότι αυτή η επιλογή είναι διαθέσιμη και ενεργοποιημένη στις ρυθμίσεις του προγράμματος περιήγησής σας.";
|
||||
"noJavascriptRetry" = "Επανάληψη";
|
||||
"Owner" = "Ιδιοκτήτης";
|
||||
"Publish the Free/Busy information" = "Δημοσίευση πληροφοριών Ελεύθερος/Απασχολημένος";
|
||||
"Add..." = "Προσθήκη...";
|
||||
"Remove" = "Αφαίρεση";
|
||||
"Subscribe User" = "Εγγραφή Χρήστη";
|
||||
"Any Authenticated User" = "Οποιοσδήποτε Πιστοποιημένος Χρήστης";
|
||||
"Public Access" = "Δημόσια Πρόσβαση";
|
||||
"Any user not listed above" = "Οποιοσδήποτε χρήστης δεν αναφέρεται παραπάνω";
|
||||
"Anybody accessing this resource from the public area" = "Οποιοσδήποτε που έχει πρόσβαση σε αυτόν τον πόρο από τη δημόσια περιοχή";
|
||||
"Sorry, the user rights can not be configured for that object." = "Λυπούμαστε, τα δικαιώματα χρήστη δεν μπορούν να ρυθμιστούν για αυτό το αντικείμενο.";
|
||||
"Any user with an account on this system will be able to access your mailbox \"%{0}\". Are you certain you trust them all?"
|
||||
= "Οποιοσδήποτε χρήστης με λογαριασμό σε αυτό το σύστημα θα μπορεί να έχει πρόσβαση στο γραμματοκιβώτιό σας \"%{0}\". Είστε βέβαιοι ότι τους εμπιστεύεστε όλους;";
|
||||
"Any user with an account on this system will be able to access your calendar \"%{0}\". Are you certain you trust them all?"
|
||||
= "Οποιοσδήποτε χρήστης με λογαριασμό σε αυτό το σύστημα θα μπορεί να έχει πρόσβαση στο ημερολόγιό σας \"%{0}\". Είστε βέβαιοι ότι τους εμπιστεύεστε όλους;";
|
||||
"Potentially anyone on the Internet will be able to access your calendar \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?"
|
||||
= "Δυνητικά οποιοσδήποτε στο Διαδίκτυο θα μπορεί να έχει πρόσβαση στο ημερολόγιό σας \"%{0}\", ακόμα και αν δεν έχει λογαριασμό σε αυτό το σύστημα. Είναι αυτές οι πληροφορίες κατάλληλες για δημόσια δημοσίευση στο Διαδίκτυο;";
|
||||
"Any user with an account on this system will be able to access your address book \"%{0}\". Are you certain you trust them all?"
|
||||
= "Οποιοσδήποτε χρήστης με λογαριασμό σε αυτό το σύστημα θα μπορεί να έχει πρόσβαση στο βιβλίο διευθύνσεών σας \"%{0}\". Είστε βέβαιοι ότι τους εμπιστεύεστε όλους;";
|
||||
"Potentially anyone on the Internet will be able to access your address book \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?"
|
||||
= "Δυνητικά οποιοσδήποτε στο Διαδίκτυο θα μπορεί να έχει πρόσβαση στο βιβλίο διευθύνσεών σας \"%{0}\", ακόμα και αν δεν έχει λογαριασμό σε αυτό το σύστημα. Είναι αυτές οι πληροφορίες κατάλληλες για δημόσια δημοσίευση στο Διαδίκτυο;";
|
||||
"Give Access" = "Παροχή Πρόσβασης";
|
||||
"Keep Private" = "Διατήρηση Ιδιωτικότητας";
|
||||
"Expand" = "Επέκταση";
|
||||
"Reduce" = "Σύμπτυξη";
|
||||
|
||||
/* tooltip */
|
||||
"Refresh" = "Ανανέωση";
|
||||
|
||||
/* generic.js */
|
||||
"Unable to subscribe to that folder!"
|
||||
= "Αδυναμία εγγραφής σε αυτόν τον φάκελο!";
|
||||
"You cannot subscribe to a folder that you own!"
|
||||
= "Δεν μπορείτε να εγγραφείτε σε φάκελο που σας ανήκει!";
|
||||
"Unable to unsubscribe from that folder!"
|
||||
= "Αδυναμία κατάργησης εγγραφής από αυτόν τον φάκελο!";
|
||||
"You cannot unsubscribe from a folder that you own!"
|
||||
= "Δεν μπορείτε να καταργήσετε την εγγραφή από φάκελο που σας ανήκει!";
|
||||
"Unable to rename that folder!" = "Αδυναμία μετονομασίας αυτού του φακέλου!";
|
||||
"You have already subscribed to that folder!"
|
||||
= "Έχετε ήδη εγγραφεί σε αυτόν τον φάκελο!";
|
||||
"The user rights cannot be edited for this object!"
|
||||
= "Τα δικαιώματα χρήστη δεν μπορούν να επεξεργαστούν για αυτό το αντικείμενο!";
|
||||
"A folder by that name already exists." = "Ένας φάκελος με αυτό το όνομα υπάρχει ήδη.";
|
||||
"You cannot create a list in a shared address book."
|
||||
= "Δεν μπορείτε να δημιουργήσετε λίστα σε κοινόχρηστο βιβλίο διευθύνσεων.";
|
||||
"Warning" = "Προειδοποίηση";
|
||||
"Can't contact server" = "Προέκυψε σφάλμα κατά την επικοινωνία με τον διακομιστή. Παρακαλούμε δοκιμάστε ξανά αργότερα.";
|
||||
"You are not allowed to access this module or this system. Please contact your system administrator."
|
||||
= "Δεν σας επιτρέπεται η πρόσβαση σε αυτήν την ενότητα ή σε αυτό το σύστημα. Επικοινωνήστε με τον διαχειριστή του συστήματος.";
|
||||
"You don't have the required privileges to perform the operation."
|
||||
= "Δεν έχετε τα απαιτούμενα δικαιώματα για να εκτελέσετε αυτήν την ενέργεια.";
|
||||
"noEmailForDelegation" = "Πρέπει να καθορίσετε τη διεύθυνση στην οποία θέλετε να αναθέσετε την πρόσκλησή σας.";
|
||||
"delegate is organizer" = "Ο αντιπρόσωπος είναι ο διοργανωτής. Παρακαλούμε καθορίστε διαφορετικό αντιπρόσωπο.";
|
||||
"delegate is a participant" = "Ο αντιπρόσωπος είναι ήδη συμμετέχων.";
|
||||
"delegate is a group" = "Η καθορισμένη διεύθυνση αντιστοιχεί σε ομάδα. Μπορείτε να αναθέσετε μόνο σε μοναδικό άτομο.";
|
||||
|
||||
/* common buttons */
|
||||
"OK" = "Εντάξει";
|
||||
"Cancel" = "Άκυρο";
|
||||
"Yes" = "Ναι";
|
||||
"No" = "Όχι";
|
||||
|
||||
/* generic messages */
|
||||
"Error" = "Σφάλμα";
|
||||
"Success" = "Επιτυχία";
|
||||
|
||||
/* confirmation dialog box */
|
||||
"Confirmation" = "Επιβεβαίωση";
|
||||
|
||||
/* alarms */
|
||||
"Reminder" = "Υπενθύμιση";
|
||||
"Start" = "Έναρξη";
|
||||
"Due Date" = "Ημερομηνία Λήξης";
|
||||
"Location" = "Τοποθεσία";
|
||||
"Snooze" = "Αναβολή";
|
||||
"Snooze for " = "Αναβολή για ";
|
||||
"5 minutes" = "5 λεπτά";
|
||||
"10 minutes" = "10 λεπτά";
|
||||
"15 minutes" = "15 λεπτά";
|
||||
"30 minutes" = "30 λεπτά";
|
||||
"45 minutes" = "45 λεπτά";
|
||||
"1 hour" = "1 ώρα";
|
||||
"1 day" = "1 ημέρα";
|
||||
|
||||
/* mail labels */
|
||||
"Important" = "Σημαντικό";
|
||||
"Work" = "Εργασία";
|
||||
"Personal" = "Προσωπικό";
|
||||
"To Do" = "Προς Εκτέλεση";
|
||||
"Later" = "Αργότερα";
|
||||
"Forwarded" = "Προωθήθηκε";
|
||||
"Return Receipt Sent" = "Απεστάλη Απόδειξη Παράδοσης";
|
||||
"a2_Sunday" = "Κυ";
|
||||
"a2_Monday" = "Δε";
|
||||
"a2_Tuesday" = "Τρ";
|
||||
"a2_Wednesday" = "Τε";
|
||||
"a2_Thursday" = "Πέ";
|
||||
"a2_Friday" = "Πα";
|
||||
"a2_Saturday" = "Σά";
|
||||
"Access Rights" = "Δικαιώματα Πρόσβασης";
|
||||
"Add User" = "Προσθήκη Χρήστη";
|
||||
"Loading" = "Φόρτωση";
|
||||
"No such user." = "Δεν υπάρχει τέτοιος χρήστης.";
|
||||
"You cannot (un)subscribe to a folder that you own!" = "Δεν μπορείτε να (απ)εγγραφείτε από φάκελο που σας ανήκει!";
|
||||
|
||||
/* SMIME Certificate field */
|
||||
"S/MIME Certificate" = "Πιστοποιητικό S/MIME";
|
||||
"Subject Name" = "Όνομα Υποκειμένου";
|
||||
"Issuer" = "Εκδότης";
|
||||
"streetAddress" = "Οδός";
|
||||
"stateOrProvinceName" = "Πολιτεία ή Νομός";
|
||||
"localityName" = "Πόλη";
|
||||
"countryName" = "Χώρα";
|
||||
"organizationName" = "Οργανισμός";
|
||||
"organizationalUnitName" = "Μονάδα Οργανισμού";
|
||||
"commonName" = "Κοινό Όνομα";
|
||||
"surname" = "Επίθετο";
|
||||
"givenName" = "Όνομα";
|
||||
"emailAddress" = "Διεύθυνση Email";
|
||||
|
||||
|
||||
/* Authentication username */
|
||||
"Username" = "Όνομα Χρήστη";
|
||||
|
||||
/* Authentication password */
|
||||
"Password" = "Κωδικός Πρόσβασης";
|
||||
|
||||
/* Authentication failed */
|
||||
"Wrong username or password." = "Λανθασμένο όνομα χρήστη ή κωδικός πρόσβασης.";
|
||||
|
||||
/* Error message displayed bellow search field when the search string has less than the required number of characters */
|
||||
"Enter at least %{minimumSearchLength} characters" = "Εισαγάγετε τουλάχιστον %{minimumSearchLength} χαρακτήρες";
|
||||
|
||||
/* Error message displayed when a file upload exceeds WOMaxUploadSize */
|
||||
"File size upload limit reached" = "Ξεπεράστηκε το όριο μεγέθους αρχείου για μεταφόρτωση";
|
||||
|
||||
/* Generic server error */
|
||||
"An error occured, please try again." = "Προέκυψε σφάλμα, παρακαλούμε δοκιμάστε ξανά.";
|
||||
|
||||
/* Open datepicker */
|
||||
"Open Calendar" = "Άνοιγμα Ημερολογίου";
|
||||
|
||||
/* Toggle visibility (ex: mail account in left navigation menu) */
|
||||
"Toggle visibility" = "Εναλλαγή ορατότητας";
|
||||
|
||||
"Keyboard Shortcuts" = "Συντομεύσεις Πληκτρολογίου";
|
||||
|
||||
/* Aria label for avatar button to select and unselect an item */
|
||||
"Toggle item" = "Εναλλαγή στοιχείου";
|
||||
|
||||
/* Toggle multiple items at the same time (hotkeys cheatsheet) */
|
||||
"Toggle range of items" = "Εναλλαγή εύρους στοιχείων";
|
||||
|
||||
/* Question mark shows list of hotkeys */
|
||||
"Show or hide this help" = "Εμφάνιση ή απόκρυψη αυτής της βοήθειας";
|
||||
|
||||
/* Space key */
|
||||
"key_space" = "διάστημα";
|
||||
|
||||
/* Delete key */
|
||||
"key_delete" = "delete";
|
||||
|
||||
/* Shift and space key */
|
||||
"key_shift+space" = "shift + διάστημα";
|
||||
|
||||
/* Up arrow key */
|
||||
"key_up" = "↑";
|
||||
|
||||
/* Down arrow key */
|
||||
"key_down" = "↓";
|
||||
|
||||
/* Left arrow key */
|
||||
"key_left" = "←";
|
||||
|
||||
/* Right arrow key */
|
||||
"key_right" = "→";
|
||||
|
||||
/* Shift and up arrow combo keys */
|
||||
"key_shift+up" = "shift + ↑";
|
||||
|
||||
/* Shift and down arrow combo keys */
|
||||
"key_shift+down" = "shift + ↓";
|
||||
|
||||
/* Backspace key */
|
||||
"key_backspace" = "⌫";
|
||||
|
||||
/* Hotkey to start a search */
|
||||
"hotkey_search" = "s";
|
||||
|
||||
/* Hotkey description to select next list item */
|
||||
"View next item" = "Προβολή επόμενου στοιχείου";
|
||||
|
||||
/* Hotkey description to select previous list item */
|
||||
"View previous item" = "Προβολή προηγούμενου στοιχείου";
|
||||
|
||||
/* Hotkey description to add next list item to selection */
|
||||
"Add next item to selection" = "Προσθήκη επόμενου στοιχείου στην επιλογή";
|
||||
|
||||
/* Hotkey description to add previous list item to selection */
|
||||
"Add previous item to selection" = "Προσθήκη προηγούμενου στοιχείου στην επιλογή";
|
||||
|
||||
/* Hotkey description to move backward in current view */
|
||||
"Move backward" = "Μετακίνηση προς τα πίσω";
|
||||
|
||||
/* Hotkey description to move forward in current view */
|
||||
"Move forward" = "Μετακίνηση προς τα εμπρός";
|
||||
|
||||
/* Password Recovery */
|
||||
"passwordRecovery_Disabled" = "Απενεργοποιημένο";
|
||||
"passwordRecovery_SecretQuestion" = "Μυστική ερώτηση";
|
||||
"passwordRecovery_SecretQuestion1" = "Ποιο είναι το όνομα του πρώτου σας κατοικίδιου;";
|
||||
"passwordRecovery_SecretQuestion2" = "Ποιο ήταν το πρώτο σας αυτοκίνητο;";
|
||||
"passwordRecovery_SecretQuestion3" = "Ποια είναι η αγαπημένη σας ταινία;";
|
||||
"passwordRecovery_SecondaryEmail" = "Δευτερεύον Email";
|
||||
|
||||
/* Password */
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Τουλάχιστον %{0} πεζός χαρακτήρας";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Τουλάχιστον %{0} κεφαλαίος χαρακτήρας";
|
||||
"POLICY_MIN_DIGIT" = "Τουλάχιστον %{0} ψηφίο";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Τουλάχιστον %{0} ειδικός χαρακτήρας";
|
||||
"POLICY_MIN_LENGTH" = "Ελάχιστο μήκος %{0} χαρακτήρες";
|
||||
@@ -176,13 +176,13 @@
|
||||
"Show or hide this help" = "Mutassa vagy elrejtse ezt a súgót";
|
||||
|
||||
/* Space key */
|
||||
"key_space" = "space";
|
||||
"key_space" = "szóköz";
|
||||
|
||||
/* Delete key */
|
||||
"key_delete" = "törlés";
|
||||
|
||||
/* Shift and space key */
|
||||
"key_shift+space" = "shift + space";
|
||||
"key_shift+space" = "shift + szóköz";
|
||||
|
||||
/* Up arrow key */
|
||||
"key_up" = "↑";
|
||||
@@ -235,8 +235,8 @@
|
||||
"passwordRecovery_SecondaryEmail" = "Másodlagos email cím";
|
||||
|
||||
/* Password */
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Minimum of %{0} lowercase letter";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Minimum of %{0} uppercase letter";
|
||||
"POLICY_MIN_DIGIT" = "Minimum of %{0} digit";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Minimum of %{0} special symbols";
|
||||
"POLICY_MIN_LENGTH" = "Minimum length of %{0} characters";
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Legalább %{0} kisbetű";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Legalább %{0} nagybetű";
|
||||
"POLICY_MIN_DIGIT" = "Legalább %{0} szám";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Legalább %{0} különleges karakter";
|
||||
"POLICY_MIN_LENGTH" = "Legalább %{0} karakter";
|
||||
@@ -176,7 +176,7 @@
|
||||
"Show or hide this help" = "Pokaż lub ukryj tę podpowiedź";
|
||||
|
||||
/* Space key */
|
||||
"key_space" = "space";
|
||||
"key_space" = "spacja";
|
||||
|
||||
/* Delete key */
|
||||
"key_delete" = "delete";
|
||||
@@ -235,8 +235,8 @@
|
||||
"passwordRecovery_SecondaryEmail" = "Dodatkowy e-mail";
|
||||
|
||||
/* Password */
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Minimum of %{0} lowercase letter";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Minimum of %{0} uppercase letter";
|
||||
"POLICY_MIN_DIGIT" = "Minimum of %{0} digit";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Minimum of %{0} special symbols";
|
||||
"POLICY_MIN_LENGTH" = "Minimum length of %{0} characters";
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Co najmniej %{0} małych liter";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Co najmniej %{0} dużych liter";
|
||||
"POLICY_MIN_DIGIT" = "Co najmniej %{0} cyfr";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Co najmniej %{0} znaków specjalnych";
|
||||
"POLICY_MIN_LENGTH" = "Długość co najmniej %{0} znaków";
|
||||
@@ -176,13 +176,13 @@
|
||||
"Show or hide this help" = "Mostrar ou ocultar esta ajuda";
|
||||
|
||||
/* Space key */
|
||||
"key_space" = "space";
|
||||
"key_space" = "espaço";
|
||||
|
||||
/* Delete key */
|
||||
"key_delete" = "delete";
|
||||
|
||||
/* Shift and space key */
|
||||
"key_shift+space" = "shift + space";
|
||||
"key_shift+space" = "shift + espaço";
|
||||
|
||||
/* Up arrow key */
|
||||
"key_up" = "↑";
|
||||
|
||||
@@ -235,8 +235,8 @@
|
||||
"passwordRecovery_SecondaryEmail" = "Email secundario";
|
||||
|
||||
/* Password */
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Minimum of %{0} lowercase letter";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Minimum of %{0} uppercase letter";
|
||||
"POLICY_MIN_DIGIT" = "Minimum of %{0} digit";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Minimum of %{0} special symbols";
|
||||
"POLICY_MIN_LENGTH" = "Minimum length of %{0} characters";
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Mínimo de %{0} letra minúscula";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Mínimo de %{0} letra mayúscula";
|
||||
"POLICY_MIN_DIGIT" = "Mínimo de %{0} dígito";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Mínimo de %{0} símbolos especiales";
|
||||
"POLICY_MIN_LENGTH" = "Longitud mínima de %{0} caracteres";
|
||||
@@ -26,6 +26,8 @@
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
|
||||
#import <SoObjects/SOGo/SOGoContentObject.h>
|
||||
|
||||
#import <SOGo/NSDictionary+Utilities.h>
|
||||
@@ -34,6 +36,25 @@
|
||||
|
||||
@implementation UIxObjectActions
|
||||
|
||||
|
||||
- (BOOL) _checkUid: (NSString *) newUID
|
||||
{
|
||||
BOOL response;
|
||||
SOGoUserManager *um;
|
||||
response = NO;
|
||||
|
||||
if ([newUID length] > 0)
|
||||
{
|
||||
um = [SOGoUserManager sharedUserManager];
|
||||
if ([[um getEmailForUID: newUID] length] > 0)
|
||||
{
|
||||
response = YES;
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} /so/:username/:folderPath/addUserInAcls?uid=:uid Add user to ACLs
|
||||
* @apiVersion 1.0.0
|
||||
@@ -49,8 +70,17 @@
|
||||
WOResponse *response;
|
||||
NSString *uid;
|
||||
unsigned int code;
|
||||
NSDictionary *jsonResponse;
|
||||
|
||||
uid = [[context request] formValueForKey: @"uid"];
|
||||
if(![self _checkUid: uid])
|
||||
{
|
||||
jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"No such user."]
|
||||
forKey: @"message"];
|
||||
response = [self responseWithStatus: 403
|
||||
andString: [jsonResponse jsonRepresentation]];
|
||||
return response;
|
||||
}
|
||||
if ([[self clientObject] addUserInAcls: uid])
|
||||
code = 204;
|
||||
else
|
||||
@@ -77,8 +107,17 @@
|
||||
WOResponse *response;
|
||||
NSString *uid;
|
||||
unsigned int code;
|
||||
NSDictionary *jsonResponse;
|
||||
|
||||
uid = [[context request] formValueForKey: @"uid"];
|
||||
if(![self _checkUid: uid])
|
||||
{
|
||||
jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"No such user."]
|
||||
forKey: @"message"];
|
||||
response = [self responseWithStatus: 403
|
||||
andString: [jsonResponse jsonRepresentation]];
|
||||
return response;
|
||||
}
|
||||
if ([[self clientObject] removeUserFromAcls: uid])
|
||||
code = 204;
|
||||
else
|
||||
|
||||
@@ -488,6 +488,14 @@
|
||||
&& [user isSuperUser]);
|
||||
}
|
||||
|
||||
- (BOOL) usesCASAuthentication
|
||||
{
|
||||
SOGoSystemDefaults *sd;
|
||||
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
|
||||
return [[sd authenticationType] isEqualToString: @"cas"];
|
||||
}
|
||||
|
||||
- (BOOL) usesOpenIdAuthentication
|
||||
{
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
request = [context request];
|
||||
params = [[request contentAsString] objectFromJSONString];
|
||||
|
||||
name = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES];
|
||||
name = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES stripAngular:NO];
|
||||
nameInContainer = nil;
|
||||
|
||||
if ([name length] > 0)
|
||||
|
||||
@@ -193,11 +193,11 @@
|
||||
"Work" = "Feina";
|
||||
"Mobile" = "Mòbil";
|
||||
"Pager" = "Cercapersones";
|
||||
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
|
||||
"Download iOS - MacOS configuration profile" = "Descarregar perfil de configuració iOS - MacOS";
|
||||
|
||||
/* categories */
|
||||
"contacts_category_labels" = "Colleague, Competitor, Customer, Friend, Family, Business Partner, Provider, Press, VIP";
|
||||
"New category" = "New category";
|
||||
"contacts_category_labels" = "Col·lega, Competidor, Client, Amic, Família, Soci, Proveïdor, Premsa, VIP";
|
||||
"New category" = "Nova categoria";
|
||||
|
||||
/* adresses */
|
||||
"Title" = "Títol";
|
||||
@@ -222,7 +222,7 @@
|
||||
"New Addressbook..." = "Nova llibreta d'adreces";
|
||||
"Subscribe to an Addressbook..." = "Subscribiure's a una llibreta...";
|
||||
"Remove the selected Addressbook" = "Esborrar la llibreta seleccionada";
|
||||
"Subscribe to a shared contact" = "Subscribe to a shared addressbook";
|
||||
"Subscribe to a shared contact" = "Subscriure's a una llibreta compartida";
|
||||
"Search User" = "Cerca usuari";
|
||||
"Name of the Address Book" = "Nom de la llibreta";
|
||||
"Are you sure you want to delete the selected address book?"
|
||||
@@ -351,7 +351,7 @@
|
||||
"Synchronization" = "Sincronització";
|
||||
"Synchronize" = "Sincronitzar";
|
||||
"Sucessfully subscribed to address book" = "S'ha subscrit correctament a la llibreta d'adreces";
|
||||
"A similar card already exists. Would you like to save it anyway?" = "A similar card already exists. Would you like to save it anyway?";
|
||||
"A similar card already exists. Would you like to save it anyway?" = "Ja existeix un contacte similar. Voleu desar-lo igualment?";
|
||||
|
||||
/* Aria label for scope of search on contacts */
|
||||
"Search scope" = " Abast de la cerca ";
|
||||
|
||||
@@ -285,7 +285,7 @@
|
||||
"Contacts" = "Kontakte";
|
||||
"Add" = "Hinzufügen";
|
||||
"Lists can't be moved or copied." = "Listen können nicht verschoben oder kopiert werden.";
|
||||
"Export" = "Export";
|
||||
"Export" = "Exportieren";
|
||||
"Export Address Book..." = "Adressbuch exportieren...";
|
||||
"View Raw Source" = "Rohen Quelltext anzeigen";
|
||||
|
||||
|
||||
@@ -0,0 +1,366 @@
|
||||
/* this file is in UTF-8 format! */
|
||||
|
||||
"Contact" = "Contact";
|
||||
"Address" = "Address";
|
||||
"Photos" = "Photos";
|
||||
"Other" = "Other";
|
||||
"Address Books" = "Address Books";
|
||||
"Addressbook" = "Addressbook";
|
||||
"Addresses" = "Addresses";
|
||||
"Update" = "Update";
|
||||
"Cancel" = "Cancel";
|
||||
"Common" = "Common";
|
||||
"Contact editor" = "Contact editor";
|
||||
"Contact viewer" = "Contact viewer";
|
||||
"Email" = "Email";
|
||||
"Screen Name" = "Screen Name";
|
||||
"Extended" = "Extended";
|
||||
"Fax" = "Fax";
|
||||
"Firstname" = "Firstname";
|
||||
"Home" = "Home";
|
||||
"HomePhone" = "HomePhone";
|
||||
"Lastname" = "Lastname";
|
||||
"Location" = "Location";
|
||||
"Add a category" = "Add a category";
|
||||
"MobilePhone" = "MobilePhone";
|
||||
"Name" = "Name";
|
||||
"OfficePhone" = "OfficePhone";
|
||||
"Organization" = "Organization";
|
||||
"Work Phone" = "Work Phone";
|
||||
"Cell" = "Cell";
|
||||
"Pager" = "Pager";
|
||||
"Pref" = "Pref";
|
||||
"Phone" = "Phone";
|
||||
"Phones" = "Phones";
|
||||
"Postal" = "Postal";
|
||||
"Save" = "Save";
|
||||
"Internet" = "Internet";
|
||||
"Unit" = "Unit";
|
||||
"delete" = "delete";
|
||||
"edit" = "edit";
|
||||
"invalidemailwarn" = "The specified email is invalid";
|
||||
"new" = "new";
|
||||
"Preferred Phone" = "Preferred Phone";
|
||||
"Move To" = "Move To";
|
||||
"Copy To" = "Copy To";
|
||||
"Add to" = "Add to";
|
||||
"To" = "To";
|
||||
"Carbon Copy (Cc)" = "Carbon Copy (Cc)";
|
||||
"Blind Carbon Copy (Bcc)" = "Blind Carbon Copy (Bcc)";
|
||||
|
||||
/* Search scope: name fields */
|
||||
"name" = "Name";
|
||||
|
||||
/* Search scope: name fields */
|
||||
"c_cn" = "Name";
|
||||
|
||||
/* Search scope: secondary email field */
|
||||
"mozillanickname" = "Secondary email";
|
||||
|
||||
/* Search scope: screen name field */
|
||||
"nsaimid" = "Screen name";
|
||||
|
||||
/* Search scope: mail fields */
|
||||
"mail" = "Mail";
|
||||
|
||||
/* Search scope: mail fields */
|
||||
"c_mail" = "Mail";
|
||||
|
||||
/* Search scope: telephone field */
|
||||
"telephonenumber" = "Telephone";
|
||||
|
||||
/* Search scope: telephone field */
|
||||
"homephone" = "Telephone";
|
||||
|
||||
/* Search scope: mobile field */
|
||||
"mobile" = "Mobile";
|
||||
|
||||
/* Search scope: fax field */
|
||||
"facsimiletelephonenumber" = "Fax";
|
||||
|
||||
/* Search scope: pager field */
|
||||
"pager" = "Pager";
|
||||
|
||||
/* Search scope: categories field */
|
||||
"c_categories" = "Categories";
|
||||
|
||||
/* Search scope: categories field */
|
||||
"vcardcategories" = "Categories";
|
||||
|
||||
/* Search scope: title field */
|
||||
"title" = "Title";
|
||||
|
||||
/* Search scope: organization field */
|
||||
"c_o" = "Organization";
|
||||
|
||||
/* Search scope: organization field */
|
||||
"o" = "Organization";
|
||||
|
||||
/* Search scope: department field */
|
||||
"ou" = "Department";
|
||||
|
||||
/* Search scope: city field */
|
||||
"l" = "City";
|
||||
|
||||
/* Search scope: country field */
|
||||
"c" = "Country";
|
||||
|
||||
/* Search scope: home address field */
|
||||
"mozillahomestreet" = "Home Address";
|
||||
|
||||
/* Search scope: state/province field */
|
||||
"st" = "State/Province";
|
||||
|
||||
/* Search scope: home state/province field */
|
||||
"mozillahomestate" = "Home State/Province";
|
||||
|
||||
/* Search scope: zip/postal code field */
|
||||
"postalCode" = "Zip/Postal Code";
|
||||
|
||||
/* Search scope: home zip/postal code field */
|
||||
"mozillahomepostalcode" = "Zip/Postal Code";
|
||||
|
||||
/* Search scope: home country field */
|
||||
"mozillahomecountryname" = "Home Country";
|
||||
|
||||
/* Search scope: home web page field */
|
||||
"mozillahomeurl" = "Home page";
|
||||
|
||||
/* Search scope: work web page field */
|
||||
"mozillaworkurl" = "Web page";
|
||||
|
||||
/* Search scope: note field */
|
||||
"description" = "Note";
|
||||
|
||||
/* Subheader of empty addressbook */
|
||||
"No contact" = "No contact";
|
||||
|
||||
/* Subheader of system addressbook */
|
||||
"Start a search to browse this address book" = "Start a search to browse this address book";
|
||||
|
||||
/* Number of contacts in addressbook; string is prefixed by number */
|
||||
"contacts" = "contacts";
|
||||
|
||||
/* No contact matching search criteria */
|
||||
"No matching contact" = "No matching contact";
|
||||
|
||||
/* Number of contacts matching search criteria; string is prefixed by number */
|
||||
"matching contacts" = "matching contacts";
|
||||
|
||||
/* Number of selected contacts in list */
|
||||
"selected" = "selected";
|
||||
|
||||
/* Empty right pane */
|
||||
"No contact selected" = "No contact selected";
|
||||
|
||||
/* Tooltips */
|
||||
"Create a new address book card" = "Create a new address book card";
|
||||
"Create a new list" = "Create a new list";
|
||||
"Edit the selected card" = "Edit the selected card";
|
||||
"Send a mail message" = "Send a mail message";
|
||||
"Delete selected card or address book" = "Delete selected card or address book";
|
||||
"Reload all contacts" = "Reload all contacts";
|
||||
"htmlMailFormat_UNKNOWN" = "Unknown";
|
||||
"htmlMailFormat_FALSE" = "Plain Text";
|
||||
"htmlMailFormat_TRUE" = "HTML";
|
||||
"Name or Email" = "Name or Email";
|
||||
"Category" = "Category";
|
||||
"Personal Addressbook" = "Personal Addressbook";
|
||||
"Search in Addressbook" = "Search in Addressbook";
|
||||
"New Card" = "New Card";
|
||||
"New List" = "New List";
|
||||
"Edit" = "Edit";
|
||||
"Properties" = "Properties";
|
||||
"Sharing..." = "Sharing...";
|
||||
"Write" = "Write";
|
||||
"Delete" = "Delete";
|
||||
"Instant Message" = "Instant Message";
|
||||
"Add..." = "Add...";
|
||||
"Remove" = "Remove";
|
||||
"Please wait..." = "Please wait...";
|
||||
"No possible subscription" = "No possible subscription";
|
||||
"Preferred" = "Preferred";
|
||||
"Display" = "Display";
|
||||
"Display Name" = "Display Name";
|
||||
"Additional Email" = "Additional Email";
|
||||
"Phone Number" = "Phone Number";
|
||||
"Prefers to receive messages formatted as" = "Prefers to receive messages formatted as";
|
||||
"Categories" = "Categories";
|
||||
"First" = "First";
|
||||
"Last" = "Last";
|
||||
"Nickname" = "Nickname";
|
||||
"Telephone" = "Telephone";
|
||||
"Work" = "Work";
|
||||
"Mobile" = "Mobile";
|
||||
"Pager" = "Pager";
|
||||
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
|
||||
|
||||
/* categories */
|
||||
"contacts_category_labels" = "Colleague, Competitor, Customer, Friend, Family, Business Partner, Provider, Press, VIP";
|
||||
"New category" = "New category";
|
||||
|
||||
/* adresses */
|
||||
"Title" = "Title";
|
||||
"Service" = "Service";
|
||||
"Company" = "Company";
|
||||
"Department" = "Department";
|
||||
"City" = "City ";
|
||||
"State_Province" = "State/Province";
|
||||
"ZIP_Postal Code" = "ZIP/Postal Code";
|
||||
"Country" = "Country";
|
||||
"Web Page" = "Web Page";
|
||||
"Other Infos" = "Other Infos";
|
||||
"Note" = "Note";
|
||||
"Timezone" = "Timezone";
|
||||
"Birthday" = "Birthday";
|
||||
"Birthday (yyyy-mm-dd)" = "Birthday (yyyy-mm-dd)";
|
||||
"Freebusy URL" = "Freebusy URL";
|
||||
"Add as..." = "Add as...";
|
||||
"Recipient" = "Recipient";
|
||||
"Carbon Copy" = "Carbon Copy";
|
||||
"Blind Carbon Copy" = "Blind Carbon Copy";
|
||||
"New Addressbook..." = "New Addressbook...";
|
||||
"Subscribe to an Addressbook..." = "Subscribe to an Addressbook...";
|
||||
"Remove the selected Addressbook" = "Remove the selected Addressbook";
|
||||
"Subscribe to a shared contact" = "Subscribe to a shared addressbook";
|
||||
"Search User" = "Search User";
|
||||
"Name of the Address Book" = "Name of the Address Book";
|
||||
"Are you sure you want to delete the selected address book?"
|
||||
= "Are you sure you want to delete the selected address book?";
|
||||
"Are you sure you want to delete the addressbook \"%{0}\"?"
|
||||
= "Are you sure you want to delete the addressbook \"%{0}\"?";
|
||||
"You cannot remove nor unsubscribe from a public addressbook."
|
||||
= "You cannot remove nor unsubscribe from a public addressbook.";
|
||||
"You cannot remove nor unsubscribe from your personal addressbook."
|
||||
= "You cannot remove nor unsubscribe from your personal addressbook.";
|
||||
"Are you sure you want to delete the selected contacts?"
|
||||
= "Are you sure you want to delete the selected contacts?";
|
||||
"Are you sure you want to delete the card of %{0}?" = "Are you sure you want to delete the card of %{0}?";
|
||||
"You cannot delete the card of \"%{0}\"."
|
||||
= "You cannot delete the card of \"%{0}\".";
|
||||
"You cannot subscribe to a folder that you own!"
|
||||
= "You cannot subscribe to a folder that you own.";
|
||||
"Unable to subscribe to that folder!"
|
||||
= "Unable to subscribe to that folder.";
|
||||
|
||||
/* security */
|
||||
"Security" = "Security";
|
||||
"Uninstall" = "Uninstall";
|
||||
"Error reading the card certificate." = "Error reading the card certificate.";
|
||||
"No certificate associated to card." = "No certificate associated to card.";
|
||||
|
||||
/* acls */
|
||||
"Access rights to" = "Access rights to";
|
||||
"For user" = "For user";
|
||||
"Any Authenticated User" = "Any Authenticated User";
|
||||
"Public Access" = "Public Access";
|
||||
"This person can add cards to this addressbook."
|
||||
= "This person can add cards to this addressbook.";
|
||||
"This person can edit the cards of this addressbook."
|
||||
= "This person can edit the cards of this addressbook.";
|
||||
"This person can list the content of this addressbook."
|
||||
= "This person can list the content of this addressbook.";
|
||||
"This person can read the cards of this addressbook."
|
||||
= "This person can read the cards of this addressbook.";
|
||||
"This person can erase cards from this addressbook."
|
||||
= "This person can erase cards from this addressbook.";
|
||||
"The selected contact has no email address."
|
||||
= "The selected contact has no email address.";
|
||||
"Please select a contact." = "Please select a contact.";
|
||||
|
||||
/* Messages for move and copy */
|
||||
"%{0} card(s) copied" = "%{0} card(s) copied";
|
||||
"%{0} card(s) moved" = "%{0} card(s) moved";
|
||||
"SoAccessDeniedException" = "You cannot write to this address book.";
|
||||
"Forbidden" = "Forbidden";
|
||||
"Invalid Contact" = "The selected contact no longer exists.";
|
||||
"Unknown Destination Folder" = "The chosen destination address book no longer exists.";
|
||||
|
||||
/* Lists */
|
||||
"List details" = "List details";
|
||||
"List name" = "List name";
|
||||
"List nickname" = "List nickname";
|
||||
"List description" = "List description";
|
||||
"Members" = "Members";
|
||||
"Contacts" = "Contacts";
|
||||
"Add" = "Add";
|
||||
"Lists can't be moved or copied." = "Lists can't be moved or copied.";
|
||||
"Export" = "Export";
|
||||
"Export Address Book..." = "Export Address Book...";
|
||||
"View Raw Source" = "View Raw Source";
|
||||
|
||||
/* Import */
|
||||
"Import Cards" = "Import Cards";
|
||||
"Select a vCard or LDIF file." = "Select a vCard or LDIF file.";
|
||||
"Upload" = "Upload";
|
||||
"Uploading" = "Uploading";
|
||||
"Done" = "Done";
|
||||
"An error occured while importing contacts." = "An error occured while importing contacts.";
|
||||
"No card was imported." = "No card was imported.";
|
||||
"A total of %{0} cards were imported in the addressbook." = "A total of %{0} cards were imported in the addressbook.";
|
||||
"Reload" = "Reload";
|
||||
|
||||
/* Properties window */
|
||||
"Address Book Name" = "Address Book Name";
|
||||
"Links to this Address Book" = "Links to this Address Book";
|
||||
"Authenticated User Access" = "Authenticated User Access";
|
||||
"CardDAV URL" = "CardDAV URL";
|
||||
"Options" = "Options";
|
||||
"Rename" = "Rename";
|
||||
"Subscriptions" = "Subscriptions";
|
||||
"Global Addressbooks" = "Global Addressbooks";
|
||||
"Search" = "Search";
|
||||
"Sort" = "Sort";
|
||||
"Descending Order" = "Descending Order";
|
||||
"Back" = "Back";
|
||||
"Select All" = "Select All";
|
||||
"Copy contacts" = "Copy contacts";
|
||||
"More messages options" = "More messages options";
|
||||
"New Contact" = "New Contact";
|
||||
"Close" = "Close";
|
||||
"More contact options" = "More contact options";
|
||||
"Organization Unit" = "Organization Unit";
|
||||
"Add Organizational Unit" = "Add Organizational Unit";
|
||||
"Type" = "Type";
|
||||
"Email Address" = "Email Address";
|
||||
"New Email Address" = "New Email Address";
|
||||
"New Phone Number" = "New Phone Number";
|
||||
"URL" = "URL";
|
||||
"New URL" = "New URL";
|
||||
"street" = "street";
|
||||
"street (continued)" = "street (continued)";
|
||||
"Postoffice" = "Postoffice";
|
||||
"Region" = "Region";
|
||||
"Postal Code" = "Postal Code";
|
||||
"New Address" = "New Address";
|
||||
"Reset" = "Reset";
|
||||
"Description" = "Description";
|
||||
"Add Member" = "Add Member";
|
||||
"Subscribe" = "Subscribe";
|
||||
"Add Birthday" = "Add Birthday";
|
||||
"Import" = "Import";
|
||||
"More options" = "More options";
|
||||
"Role" = "Role";
|
||||
"Add Screen Name" = "Add Screen Name";
|
||||
"Custom 1" = "Custom 1";
|
||||
"Custom 2" = "Custom 2";
|
||||
"Custom 3" = "Custom 3";
|
||||
"Custom 4" = "Custom 4";
|
||||
"Custom Value" = "Custom Value";
|
||||
"New Custom Value" = "New Custom Value";
|
||||
"Synchronization" = "Synchronization";
|
||||
"Synchronize" = "Synchronize";
|
||||
"Sucessfully subscribed to address book" = "Successfully subscribed to address book";
|
||||
"A similar card already exists. Would you like to save it anyway?" = "A similar card already exists. Would you like to save it anyway?";
|
||||
|
||||
/* Aria label for scope of search on contacts */
|
||||
"Search scope" = "Search scope";
|
||||
|
||||
/* Aria label for avatar button to select and unselect a card */
|
||||
"Toggle item" = "Toggle item";
|
||||
|
||||
/* Hotkey to create a new card */
|
||||
"key_create_card" = "c";
|
||||
|
||||
/* Hotkey to create a new list */
|
||||
"key_create_list" = "l";
|
||||
@@ -12,10 +12,10 @@
|
||||
"Common" = "Közös";
|
||||
"Contact editor" = "Kapcsolatszerkesztő";
|
||||
"Contact viewer" = "Kapcsolat betekintő";
|
||||
"Email" = "Email";
|
||||
"Email" = "Email cím";
|
||||
"Screen Name" = "Megjelenített név";
|
||||
"Extended" = "Kiterjesztett";
|
||||
"Fax" = "Fax";
|
||||
"Fax" = "Telefax";
|
||||
"Firstname" = "Keresztnév";
|
||||
"Home" = "Otthoni";
|
||||
"HomePhone" = "Otthoni telefon";
|
||||
@@ -61,10 +61,10 @@
|
||||
"nsaimid" = "Megjelenített név";
|
||||
|
||||
/* Search scope: mail fields */
|
||||
"mail" = "Mail";
|
||||
"mail" = "Üzenetek";
|
||||
|
||||
/* Search scope: mail fields */
|
||||
"c_mail" = "Mail";
|
||||
"c_mail" = "Üzenetek";
|
||||
|
||||
/* Search scope: telephone field */
|
||||
"telephonenumber" = "Telefon";
|
||||
@@ -76,7 +76,7 @@
|
||||
"mobile" = "Mobiltelefon";
|
||||
|
||||
/* Search scope: fax field */
|
||||
"facsimiletelephonenumber" = "Fax";
|
||||
"facsimiletelephonenumber" = "Telefax";
|
||||
|
||||
/* Search scope: pager field */
|
||||
"pager" = "Személyhívó";
|
||||
@@ -193,7 +193,7 @@
|
||||
"Work" = "Munkahely";
|
||||
"Mobile" = "Mobiltelefon";
|
||||
"Pager" = "Személyhívó";
|
||||
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
|
||||
"Download iOS - MacOS configuration profile" = "iOS - MacOS konfigurációs profil letöltése";
|
||||
|
||||
/* categories */
|
||||
"contacts_category_labels" = "Munkatárs, Versenytárs, Felhasználó, Barát, Család, Üzleti partner, Szolgáltató, Sajtó, VIP";
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
"htmlMailFormat_FALSE" = "czysty tekst";
|
||||
"htmlMailFormat_TRUE" = "HTML";
|
||||
"Name or Email" = "Nazwa lub e-mail";
|
||||
"Category" = "Category";
|
||||
"Category" = "Kategoria";
|
||||
"Personal Addressbook" = "Osobista książka adresowa";
|
||||
"Search in Addressbook" = "Szukaj w książce adresowej";
|
||||
"New Card" = "Nowy kontakt";
|
||||
|
||||
@@ -304,11 +304,11 @@
|
||||
"Address Book Name" = "Nome do livro de endereços";
|
||||
"Links to this Address Book" = "Link para este livro de endereços";
|
||||
"Authenticated User Access" = "Acesso Utilizadores Autenticados";
|
||||
"CardDAV URL" = "CardDAV URL";
|
||||
"CardDAV URL" = "URL CardDAV";
|
||||
"Options" = "Opções";
|
||||
"Rename" = "Alterar nome";
|
||||
"Subscriptions" = "Subscrições";
|
||||
"Global Addressbooks" = "Livro de endereços de global";
|
||||
"Global Addressbooks" = "Livro de endereços global";
|
||||
"Search" = "Procurar";
|
||||
"Sort" = "Ordenar";
|
||||
"Descending Order" = "Ordem decrescente";
|
||||
|
||||
@@ -485,7 +485,7 @@ static Class SOGoContactGCSEntryK = Nil;
|
||||
co = [self clientObject];
|
||||
card = [co vCard];
|
||||
request = [context request];
|
||||
params = [[request contentAsString] objectFromJSONString];
|
||||
params = [[[request contentAsString] stringWithoutHTMLInjection: YES stripAngular:NO] objectFromJSONString];
|
||||
forceSave = [[params objectForKey: @"ignoreDuplicate"] boolValue];
|
||||
|
||||
[self setAttributes: params];
|
||||
|
||||
@@ -78,6 +78,14 @@
|
||||
NSArray *cats, *newCats, *contactCategories;
|
||||
|
||||
ownerLogin = [[self clientObject] ownerInContext: context];
|
||||
//if ownerLogin == @"nobody", meaning the current folder is not the personnal source of the user (it's the global address book)
|
||||
//No need to fetch the user "nobody". Beware that if someone is really called nobody...
|
||||
if([ownerLogin isEqualToString:@"nobody"])
|
||||
{
|
||||
cats = [self _languageContactsCategories];
|
||||
return cats;
|
||||
}
|
||||
|
||||
ud = [[SOGoUser userWithLogin: ownerLogin] userDefaults];
|
||||
cats = [ud contactsCategories];
|
||||
if (!cats)
|
||||
@@ -85,16 +93,16 @@
|
||||
|
||||
contactCategories = [card categories];
|
||||
if (contactCategories)
|
||||
{
|
||||
newCats = [cats mergedArrayWithArray: [contactCategories trimmedComponents]];
|
||||
if ([newCats count] != [cats count])
|
||||
{
|
||||
cats = [newCats sortedArrayUsingSelector:
|
||||
@selector (localizedCaseInsensitiveCompare:)];
|
||||
[ud setContactsCategories: cats];
|
||||
[ud synchronize];
|
||||
}
|
||||
}
|
||||
{
|
||||
newCats = [cats mergedArrayWithArray: [contactCategories trimmedComponents]];
|
||||
if ([newCats count] != [cats count])
|
||||
{
|
||||
cats = [newCats sortedArrayUsingSelector:
|
||||
@selector (localizedCaseInsensitiveCompare:)];
|
||||
[ud setContactsCategories: cats];
|
||||
[ud synchronize];
|
||||
}
|
||||
}
|
||||
|
||||
return cats;
|
||||
}
|
||||
|
||||
@@ -115,12 +115,18 @@
|
||||
{
|
||||
NSMutableDictionary *contactSettings;
|
||||
NSString *ascending, *sort;
|
||||
NSArray *sortValues;
|
||||
SOGoUserSettings *us;
|
||||
|
||||
sort = [[self requestData] objectForKey: @"sort"];
|
||||
ascending = [[self requestData] objectForKey: @"asc"];
|
||||
|
||||
if ([sort length])
|
||||
//Check value of sorting
|
||||
sortValues = [NSArray arrayWithObjects: @"c_cn", @"c_sn",
|
||||
@"c_givenname", @"c_mail", @"c_screenname", @"c_o", @"c_telephonenumber", nil];
|
||||
|
||||
|
||||
if ([sort length] && [sortValues containsObject:sort])
|
||||
{
|
||||
sort = [self sortKey];
|
||||
us = [[context activeUser] userSettings];
|
||||
|
||||
@@ -339,7 +339,7 @@
|
||||
[list retain];
|
||||
|
||||
request = [context request];
|
||||
params = [[request contentAsString] objectFromJSONString];
|
||||
params = [[[request contentAsString] stringWithoutHTMLInjection: YES stripAngular:NO] objectFromJSONString];
|
||||
|
||||
o = [params objectForKey: @"refs"];
|
||||
if (![o isKindOfClass: [NSArray class]])
|
||||
|
||||
@@ -24,7 +24,7 @@ request_info = "vous invite à une réunion.";
|
||||
"Update status" = "Intégrer les modifications";
|
||||
Accept = "Accepter";
|
||||
Decline = "Décliner";
|
||||
Tentative = "Tentatif";
|
||||
Tentative = "Tentative";
|
||||
"Delegate ..." = "Déléguer ...";
|
||||
"Delegated to" = "Délégué à";
|
||||
"Update status in calendar" = "Mettre l'agenda à jour";
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
ACCEPTED = "accepted";
|
||||
COMPLETED = "completed";
|
||||
DECLINED = "declined";
|
||||
DELEGATED = "delegated";
|
||||
"IN-PROCESS" = "in process";
|
||||
"NEEDS-ACTION" = "needs action";
|
||||
TENTATIVE = "tentative";
|
||||
organized_by_you = "organized by you";
|
||||
you_are_an_attendee = "you are an attendee";
|
||||
add_info_text = "iMIP 'ADD' requests are not yet supported by SOGo.";
|
||||
publish_info_text = "The sender informs you of the attached event.";
|
||||
cancel_info_text = "Your invitation or the whole event was canceled.";
|
||||
request_info_no_attendee = "is proposing a meeting to the attendees. You receive this mail as a notification, you are not scheduled as a participant.";
|
||||
Appointment = "Appointment";
|
||||
"Status Update" = "Status Update";
|
||||
was = "was";
|
||||
|
||||
Organizer = "Organizer";
|
||||
Time = "Time";
|
||||
Attendees = "Attendees";
|
||||
request_info = "invites you to participate in a meeting.";
|
||||
"Add to calendar" = "Add to calendar";
|
||||
"Delete from calendar" = "Delete from calendar";
|
||||
"Update status" = "Update status";
|
||||
Accept = "Accept";
|
||||
Decline = "Decline";
|
||||
Tentative = "Tentative";
|
||||
"Delegate ..." = "Delegate ...";
|
||||
"Delegated to" = "Delegated to";
|
||||
"Update status in calendar" = "Update status in calendar";
|
||||
"delegated from" = "delegated from";
|
||||
reply_info_no_attendee = "You received a reply to a scheduling event but the sender of the reply is not a participant.";
|
||||
reply_info = "This is a reply to an event invitation done by you.";
|
||||
"to" = "to";
|
||||
"Untitled" = "Untitled";
|
||||
"Size" = "Size";
|
||||
"Subject" = "Subject";
|
||||
"From" = "From";
|
||||
"Date" = "Date";
|
||||
"To" = "To";
|
||||
"Issuer" = "Issuer";
|
||||
/* Tooltips */
|
||||
"View Attachment" = "View Attachment";
|
||||
"Save Attachment" = "Save Attachment";
|
||||
"CC" = "CC";
|
||||
"Cancel" = "Cancel";
|
||||
"OK" = "OK";
|
||||
"Comment" = "Comment";
|
||||
"Description" = "Description";
|
||||
"Location" = "Location";
|
||||
@@ -44,7 +44,7 @@ reply_info = "Ez egy válasz az ön által kiküldött meghívásra.";
|
||||
"Save Attachment" = "Melléklet mentése";
|
||||
"CC" = "Másolat";
|
||||
"Cancel" = "Mégsem";
|
||||
"OK" = "OK";
|
||||
"OK" = "Rendben";
|
||||
"Comment" = "Megjegyzés:";
|
||||
"Description" = "Leírás";
|
||||
"Location" = "Location";
|
||||
"Location" = "Helyszín";
|
||||
@@ -47,4 +47,4 @@ reply_info = "To jest odpowiedź do utworzonego przez ciebie wydarzenia";
|
||||
"OK" = "OK";
|
||||
"Comment" = "Komentarz";
|
||||
"Description" = "Opis";
|
||||
"Location" = "Location";
|
||||
"Location" = "Położenie";
|
||||
@@ -130,6 +130,13 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
BOOL hasEmbeddedCSS;
|
||||
xmlCharEncoding contentEncoding;
|
||||
BOOL rawContent;
|
||||
// Wrap libxml2-orphaned <a> around the following block element
|
||||
// (HTML5 pattern <a><table>...</table></a> auto-closed by libxml2 HTML4 DTD).
|
||||
NSString *pendingAnchorTag;
|
||||
NSString *anchorWrapTag;
|
||||
NSUInteger anchorWrapDepth;
|
||||
NSString *lastAnchorOpenString;
|
||||
NSUInteger lastAnchorOpenEnd;
|
||||
}
|
||||
|
||||
- (NSString *) result;
|
||||
@@ -175,6 +182,9 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
[result release];
|
||||
[css release];
|
||||
[ignoreTag release];
|
||||
[pendingAnchorTag release];
|
||||
[anchorWrapTag release];
|
||||
[lastAnchorOpenString release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -228,6 +238,15 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
inCSSDeclaration = NO;
|
||||
hasEmbeddedCSS = NO;
|
||||
embeddedCSSLevel = 0;
|
||||
|
||||
[pendingAnchorTag release];
|
||||
[anchorWrapTag release];
|
||||
[lastAnchorOpenString release];
|
||||
pendingAnchorTag = nil;
|
||||
anchorWrapTag = nil;
|
||||
lastAnchorOpenString = nil;
|
||||
anchorWrapDepth = 0;
|
||||
lastAnchorOpenEnd = 0;
|
||||
}
|
||||
|
||||
- (void) endDocument
|
||||
@@ -494,6 +513,32 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
}
|
||||
else
|
||||
{
|
||||
// If a libxml2-orphaned <a> is waiting, re-open it around the next
|
||||
// block element (HTML5 pattern <a><table>...</table></a>).
|
||||
// Skip if the next element is itself <a> (avoids invalid nesting).
|
||||
if (pendingAnchorTag != nil)
|
||||
{
|
||||
if ([lowerName isEqualToString: @"a"])
|
||||
{
|
||||
[pendingAnchorTag release];
|
||||
pendingAnchorTag = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
[result appendString: pendingAnchorTag];
|
||||
[anchorWrapTag release];
|
||||
anchorWrapTag = [lowerName copy];
|
||||
anchorWrapDepth = 1;
|
||||
[pendingAnchorTag release];
|
||||
pendingAnchorTag = nil;
|
||||
}
|
||||
}
|
||||
else if (anchorWrapTag != nil
|
||||
&& [lowerName isEqualToString: anchorWrapTag])
|
||||
{
|
||||
anchorWrapDepth++;
|
||||
}
|
||||
|
||||
resultPart = [NSMutableString string];
|
||||
[resultPart appendFormat: @"<%@", _rawName];
|
||||
|
||||
@@ -599,6 +644,13 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
[resultPart appendString: @"/"];
|
||||
[resultPart appendString: @">"];
|
||||
[result appendString: resultPart];
|
||||
|
||||
if ([lowerName isEqualToString: @"a"])
|
||||
{
|
||||
[lastAnchorOpenString release];
|
||||
lastAnchorOpenString = [resultPart copy];
|
||||
lastAnchorOpenEnd = [result length];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -655,8 +707,42 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Empty <a> auto-closed by libxml2 right after opening:
|
||||
// strip it from result and remember it to wrap the next block.
|
||||
if ([lowerName isEqualToString: @"a"]
|
||||
&& lastAnchorOpenString != nil
|
||||
&& [result length] == lastAnchorOpenEnd)
|
||||
{
|
||||
NSUInteger tagLen = [lastAnchorOpenString length];
|
||||
[result deleteCharactersInRange:
|
||||
NSMakeRange(lastAnchorOpenEnd - tagLen, tagLen)];
|
||||
[pendingAnchorTag release];
|
||||
pendingAnchorTag = lastAnchorOpenString;
|
||||
lastAnchorOpenString = nil;
|
||||
lastAnchorOpenEnd = 0;
|
||||
return;
|
||||
}
|
||||
if ([lowerName isEqualToString: @"a"])
|
||||
{
|
||||
[lastAnchorOpenString release];
|
||||
lastAnchorOpenString = nil;
|
||||
lastAnchorOpenEnd = 0;
|
||||
}
|
||||
|
||||
//NSLog (@"%@", _localName);
|
||||
[result appendFormat: @"</%@>", _localName];
|
||||
|
||||
if (anchorWrapTag != nil
|
||||
&& [lowerName isEqualToString: anchorWrapTag])
|
||||
{
|
||||
anchorWrapDepth--;
|
||||
if (anchorWrapDepth == 0)
|
||||
{
|
||||
[result appendString: @"</a>"];
|
||||
[anchorWrapTag release];
|
||||
anchorWrapTag = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -673,9 +759,17 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
else if (inBody)
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
|
||||
s = [NSString stringWithCharacters: _chars length: _len];
|
||||
|
||||
if (pendingAnchorTag != nil
|
||||
&& [[s stringByTrimmingCharactersInSet:
|
||||
[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] > 0)
|
||||
{
|
||||
[pendingAnchorTag release];
|
||||
pendingAnchorTag = nil;
|
||||
}
|
||||
|
||||
// HACK: This is to avoid appending the useless junk in the <html> tag
|
||||
// that Outlook adds. It seems to confuse the XML parser for
|
||||
// forwarded messages as we get this in the _body_ of the email
|
||||
@@ -938,7 +1032,11 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
|
||||
- (NSString *) cssContent
|
||||
{
|
||||
NSString *cssContent, *css;
|
||||
NSString *cssContent, *css, *newResult;
|
||||
NSRegularExpression *regex;
|
||||
NSError *error;
|
||||
|
||||
error = nil;
|
||||
|
||||
if (!handler)
|
||||
[self _parseContent];
|
||||
@@ -950,6 +1048,19 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
[handler css]];
|
||||
else
|
||||
cssContent = @"";
|
||||
|
||||
if([cssContent length])
|
||||
{
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"margin-left\\s*:\\s*-[^;]+(\\s*!important)?"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:cssContent options:0 range:NSMakeRange(0, [cssContent length]) withTemplate:@"margin-left: 0 !important"];
|
||||
cssContent = [NSString stringWithString: newResult];
|
||||
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"margin-right\\s*:\\s*-[^;]+(\\s*!important)?"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:cssContent options:0 range:NSMakeRange(0, [cssContent length]) withTemplate:@"margin-right: 0 !important"];
|
||||
cssContent = [NSString stringWithString: newResult];
|
||||
}
|
||||
|
||||
return cssContent;
|
||||
}
|
||||
@@ -1093,7 +1204,11 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
|
||||
- (NSString *) cssContent
|
||||
{
|
||||
NSString *cssContent, *css;
|
||||
NSString *cssContent, *css, *newResult;
|
||||
NSRegularExpression *regex;
|
||||
NSError *error;
|
||||
|
||||
error = nil;
|
||||
|
||||
if (!handler)
|
||||
[self _parseContent];
|
||||
@@ -1105,6 +1220,19 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
[handler css]];
|
||||
else
|
||||
cssContent = @"";
|
||||
|
||||
if([cssContent length])
|
||||
{
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"margin-left\\s*:\\s*-[^;]+(\\s*!important)?"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:cssContent options:0 range:NSMakeRange(0, [cssContent length]) withTemplate:@"margin-left: 0 !important"];
|
||||
cssContent = [NSString stringWithString: newResult];
|
||||
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"margin-right\\s*:\\s*-[^;]+(\\s*!important)?"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:cssContent options:0 range:NSMakeRange(0, [cssContent length]) withTemplate:@"margin-right: 0 !important"];
|
||||
cssContent = [NSString stringWithString: newResult];
|
||||
}
|
||||
|
||||
return cssContent;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
- (BOOL) isEndDateOnSameDay;
|
||||
- (BOOL) hasLocation;
|
||||
- (NSString *)location;
|
||||
- (NSString *) organizerHref;
|
||||
- (NSString *) userComment;
|
||||
- (NSString *) eventDescription;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
|
||||
#import <NGImap4/NGImap4EnvelopeAddress.h>
|
||||
|
||||
@@ -44,6 +45,7 @@
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <Appointments/iCalEntityObject+SOGo.h>
|
||||
#import <Appointments/SOGoAppointmentFolder.h>
|
||||
#import <Appointments/SOGoAppointmentFolders.h>
|
||||
@@ -81,8 +83,7 @@
|
||||
{
|
||||
if (!inCalendar)
|
||||
{
|
||||
inCalendar
|
||||
= [iCalCalendar parseSingleFromSource: [self flatContentAsString]];
|
||||
inCalendar = [iCalCalendar parseSingleFromSource: [self flatContentAsString]];
|
||||
[inCalendar retain];
|
||||
}
|
||||
|
||||
@@ -374,6 +375,7 @@
|
||||
- (iCalEvent *) authorativeEvent
|
||||
{
|
||||
iCalEvent *authorativeEvent;
|
||||
NSString *comment, *cleanComment;
|
||||
|
||||
[self storedEvent];
|
||||
if (!storedEvent
|
||||
@@ -382,6 +384,14 @@
|
||||
else
|
||||
authorativeEvent = [self storedEvent];
|
||||
|
||||
//Clean authorative event
|
||||
if ((comment = [authorativeEvent comment])) {
|
||||
cleanComment = [comment stringWithoutHTMLInjection: NO stripAngular:YES];
|
||||
[authorativeEvent setComment: cleanComment];
|
||||
}
|
||||
|
||||
|
||||
|
||||
return authorativeEvent;
|
||||
}
|
||||
|
||||
@@ -408,6 +418,18 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString *) organizerHref
|
||||
{
|
||||
NSString *address;
|
||||
|
||||
address = [[[self inEvent] organizer] rfc822Email];
|
||||
if (![address length])
|
||||
return nil;
|
||||
|
||||
return [[NSString stringWithFormat: @"mailto:%@", address]
|
||||
stringByEscapingHTMLAttributeValue];
|
||||
}
|
||||
|
||||
- (NSString *) organizerDisplayName
|
||||
{
|
||||
iCalPerson *organizer;
|
||||
@@ -583,7 +605,12 @@
|
||||
[[person partStatWithDefault] lowercaseString], @"partstat", nil]];
|
||||
}
|
||||
|
||||
[d setObject: a forKey: @"participants"];
|
||||
[d setObject: a forKey: @"participants"];
|
||||
|
||||
//Sanitise the html content
|
||||
if([d objectForKey:@"content"]){
|
||||
[d setObject: [[d objectForKey:@"content"] stringWithoutHTMLInjection: NO stripAngular:NO] forKey: @"content"];
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
@@ -598,4 +625,14 @@
|
||||
return [[self inEvent] location];
|
||||
}
|
||||
|
||||
- (NSString *) userComment
|
||||
{
|
||||
return [[[self inEvent] userComment] stringByEscapingHTMLString];
|
||||
}
|
||||
|
||||
- (NSString *) eventDescription
|
||||
{
|
||||
return [[[self authorativeEvent] comment] stringByEscapingHTMLString];
|
||||
}
|
||||
|
||||
@end /* UIxMailPartICalViewer */
|
||||
@@ -86,6 +86,7 @@
|
||||
- (NSString *)preferredPathExtension;
|
||||
- (NSString *)filename;
|
||||
- (NSString *)filenameForDisplay;
|
||||
- (NSString *)filenameForTitle;
|
||||
- (NSFormatter *)sizeFormatter;
|
||||
|
||||
/* caches */
|
||||
|
||||
@@ -201,7 +201,7 @@
|
||||
|
||||
|
||||
|
||||
content = [[[self generateResponse] contentAsString] stringWithoutHTMLInjection: NO];
|
||||
content = [[[self generateResponse] contentAsString] stringWithoutHTMLInjection: NO stripAngular:NO];
|
||||
if ([self respondsToSelector:@selector(getException)]) {
|
||||
e = [self getException];
|
||||
}
|
||||
@@ -327,10 +327,12 @@
|
||||
|
||||
- (NSString *) filenameForDisplay
|
||||
{
|
||||
NSString *s;
|
||||
NSString *s, *cleanFilename;
|
||||
|
||||
if ((s = [self filename]) != nil)
|
||||
return s;
|
||||
if ((s = [self filename]) != nil) {
|
||||
cleanFilename = [s stringWithoutHTMLInjection: NO stripAngular:YES];
|
||||
return cleanFilename;
|
||||
}
|
||||
|
||||
s = [partPath componentsJoinedByString:@"-"];
|
||||
return ([s length] > 0)
|
||||
@@ -338,6 +340,14 @@
|
||||
: (id)@"untitled";
|
||||
}
|
||||
|
||||
- (NSString *) filenameForTitle
|
||||
{
|
||||
/* the generic attribute writer escapes & but not the quote, so a quote in the
|
||||
filename would end the title attribute and start a new one */
|
||||
return [[self filenameForDisplay] stringByReplacingOccurrencesOfString: @"\""
|
||||
withString: @""];
|
||||
}
|
||||
|
||||
- (NSFormatter *) sizeFormatter
|
||||
{
|
||||
return [UIxMailSizeFormatter sharedMailSizeFormatter];
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/* Icon's label */
|
||||
"Create" = "Redactar";
|
||||
"Empty Trash" = "Buidar paperera";
|
||||
"Empty Junk Folder" = "Empty Junk Folder";
|
||||
"Empty Junk Folder" = "Buidar carpeta de correu brossa";
|
||||
"Delete" = "Esborrar";
|
||||
"Expunge" = "Compactar";
|
||||
"Forward" = "Reenviar";
|
||||
@@ -79,7 +79,7 @@
|
||||
"Folder compacted" = "carpeta compactada";
|
||||
|
||||
/* Empty Junk Folder success message */
|
||||
"Junk folder emptied" = "Junk folder emptied";
|
||||
"Junk folder emptied" = "S'ha buidat la carpeta de correu brossa";
|
||||
|
||||
/* Empty Trash success message */
|
||||
"Trash emptied" = "S'ha buidat la paperera";
|
||||
@@ -88,7 +88,7 @@
|
||||
"Access rights to" = "Drets d'accés a";
|
||||
"For user" = "Per a l'usuari";
|
||||
"Any Authenticated User" = "Qualsevol usuari autenticat";
|
||||
"View this folder" = "View this folder";
|
||||
"View this folder" = "Veure aquesta carpeta";
|
||||
"Read mails from this folder" = "Llegir corrreu d'aquesta carpeta";
|
||||
"Mark mails read and unread" = "Marcar correus com a llegits o no llegits";
|
||||
"Modify the flags of the mails in this folder" = "Modificar les marques dels correus en aquesta carpeta";
|
||||
@@ -143,23 +143,23 @@
|
||||
"This mail is being sent from an unsecure network!" = "Aquest missatge s'envia des d'una xarxa no segura.";
|
||||
"Address Book" = "Llibreta d'adreces";
|
||||
"Search For" = "Cercar";
|
||||
"Contains" = "Contains";
|
||||
"Does not contains" = "Does not contains";
|
||||
"Advanced search" = "Advanced search";
|
||||
"Anytime" = "Anytime";
|
||||
"Last 7 days" = "Last 7 days";
|
||||
"Last 30 days" = "Last 30 days";
|
||||
"Last 6 month" = "Last 6 month";
|
||||
"Before" = "Before";
|
||||
"After" = "After";
|
||||
"Between" = "Between";
|
||||
"and" = "and";
|
||||
"With attachments" = "With attachments";
|
||||
"In favorites" = "In favorites";
|
||||
"Unseen only" = "Unseen only";
|
||||
"Show more" = "Show more";
|
||||
"Reset" = "Reset";
|
||||
"Message size" = "Message size";
|
||||
"Contains" = "Conté";
|
||||
"Does not contains" = "No conté";
|
||||
"Advanced search" = "Cerca avançada";
|
||||
"Anytime" = "Qualsevol moment";
|
||||
"Last 7 days" = "Últims 7 dies";
|
||||
"Last 30 days" = "Últims 30 dies";
|
||||
"Last 6 month" = "Últims 6 mesos";
|
||||
"Before" = "Abans de";
|
||||
"After" = "Després de";
|
||||
"Between" = "Entre";
|
||||
"and" = "i";
|
||||
"With attachments" = "Amb adjunts";
|
||||
"In favorites" = "Als preferits";
|
||||
"Unseen only" = "Només no llegits";
|
||||
"Show more" = "Mostrar més";
|
||||
"Reset" = "Restablir";
|
||||
"Message size" = "Mida del missatge";
|
||||
|
||||
/* Popup "show" */
|
||||
"all" = "tot";
|
||||
@@ -171,7 +171,7 @@
|
||||
/* MailListView */
|
||||
"Sender" = "Remitent";
|
||||
"Subject or Sender" = "Assumpte o remitent";
|
||||
"Subject or Recipient" = "Subject or Recipient";
|
||||
"Subject or Recipient" = "Assumpte o destinatari";
|
||||
"To or Cc" = "Per a o CC";
|
||||
"Entire Message" = "Missatge complet";
|
||||
"Date" = "Data";
|
||||
@@ -191,13 +191,13 @@
|
||||
"Untitled" = "Sense títol";
|
||||
|
||||
/* Filter option in messages list */
|
||||
"Show unread messages only" = "Show unread messages only";
|
||||
"Show unread messages only" = "Mostrar només missatges no llegits";
|
||||
|
||||
/* Filter option in messages list */
|
||||
"Show flagged messages only" = "Show flagged messages only";
|
||||
"Show flagged messages only" = "Mostrar només missatges marcats";
|
||||
|
||||
/* Aria label for icon of labels */
|
||||
"Filtered by label" = "Filtered by label";
|
||||
"Filtered by label" = "Filtrat per etiqueta";
|
||||
|
||||
/* Tree */
|
||||
"SentFolderName" = "Enviats";
|
||||
@@ -205,7 +205,7 @@
|
||||
"InboxFolderName" = "Safata d'entrada";
|
||||
"DraftsFolderName" = "Esborranys";
|
||||
"JunkFolderName" = "Correu brossa";
|
||||
"TemplatesFolderName" = "Templates";
|
||||
"TemplatesFolderName" = "Plantilles";
|
||||
"SieveFolderName" = "Filtres";
|
||||
"Folders" = "Carpetes"; /* title line */
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
"Save As..." = "Desar com a...";
|
||||
"Print Preview" = "Vista preliminar";
|
||||
"View Message Source" = "Veure format original del missatge";
|
||||
"View raw message" = "View raw message";
|
||||
"View raw message" = "Veure missatge sense format";
|
||||
|
||||
/* Message view "more" menu: create an event from message */
|
||||
"Convert To Event" = "Converteix a esdeveniment";
|
||||
@@ -266,10 +266,10 @@
|
||||
"Convert To Task" = "Converteix a tasca";
|
||||
|
||||
/* Message view "more" menu: download message as an eml file */
|
||||
"Download message" = "Download message";
|
||||
"Download message" = "Descarregar missatge";
|
||||
|
||||
/* Message view "more" menu: download message as a zip archive */
|
||||
"Download message (zip)" = "Download message (zip)";
|
||||
"Download message (zip)" = "Descarregar missatge (zip)";
|
||||
|
||||
/* Message view "more" menu: download all attachments as a zip archive */
|
||||
"Download all attachments" = "Descarrega tots els adjunts";
|
||||
@@ -317,16 +317,16 @@
|
||||
"No certificate associated to account." = "No hi ha cap certificat associat al compte.";
|
||||
|
||||
/* Invalid S/MIME signature */
|
||||
"Digital signature is not valid" = "Digital signature is not valid";
|
||||
"Digital signature is not valid" = "La signatura digital no és vàlida";
|
||||
|
||||
/* Valid S/MIME signature */
|
||||
"Message is signed" = "Message is signed";
|
||||
"Message is signed" = "El missatge està signat";
|
||||
|
||||
/* Valid S/MIME signature but common name not found */
|
||||
"Message is signed but the certificate doesn't match the sender email address" = "Message is signed but the certificate doesn't match the sender email address";
|
||||
"Message is signed but the certificate doesn't match the sender email address" = "El missatge està signat però el certificat no coincideix amb l'adreça de correu del remitent";
|
||||
|
||||
/* Unknown error while validating message signature */
|
||||
"Digital signature is not valid" = "Digital signature is not valid";
|
||||
"Digital signature is not valid" = "La signatura digital no és vàlida";
|
||||
|
||||
"This Folder" = "Aquesta carpeta";
|
||||
|
||||
@@ -410,10 +410,10 @@
|
||||
"Error while saving the draft" = "Error en guardar l'esborrany";
|
||||
|
||||
/* Error when emptying trash */
|
||||
"Unable to empty the trash folder." = "Unable to empty the trash folder.";
|
||||
"Unable to empty the trash folder." = "No s'ha pogut buidar la paperera.";
|
||||
|
||||
/* Error when emptying junk folder */
|
||||
"Unable to empty the junk folder." = "Unable to empty the junk folder.";
|
||||
"Unable to empty the junk folder." = "No s'ha pogut buidar la carpeta de correu brossa.";
|
||||
|
||||
/* Error when uploading a file attachment */
|
||||
"Error while uploading the file \"%{0}\":" = "Error en carregar el fitxer \"%{0}\":";
|
||||
@@ -429,9 +429,9 @@
|
||||
"cannot send message: (smtp) all recipients discarded" = "No s'ha pogut enviar el missatge: tots els destinataris són incorrectes.";
|
||||
"cannot send message (smtp) - recipients discarded" = "No s'ha pogut enviar el missatge. Les següents adreces són incorrectes";
|
||||
"cannot send message: (smtp) error when connecting" = "No s'ha pogut enviar el missatge. Error al connectar amb el servidor SMTP.";
|
||||
"cannot sign email without certificate" = "The message can't be signed because there's no certificate associated to the mail account.";
|
||||
"cannot sign message because the certificate can't be read" = "The message can't be signed becasue the certificate associated to the mail account can't be read.";
|
||||
"cannot sign message because the certificate doesn't include the specified sender address" = "The message can't be signed because the sender address is not included in the certificate associated to the mail account.";
|
||||
"cannot sign email without certificate" = "El missatge no es pot signar perquè no hi ha cap certificat associat al compte de correu.";
|
||||
"cannot sign message because the certificate can't be read" = "El missatge no es pot signar perquè no es pot llegir el certificat associat al compte de correu.";
|
||||
"cannot sign message because the certificate doesn't include the specified sender address" = "El missatge no es pot signar perquè l'adreça del remitent no està inclosa al certificat associat al compte de correu.";
|
||||
|
||||
/* Contacts list in mail editor */
|
||||
"Email" = "Correu electrònic";
|
||||
@@ -452,7 +452,7 @@
|
||||
"Set as Trash" = "Establir com a Paperera";
|
||||
|
||||
/* Set the folder as the one holding the Templates */
|
||||
"Set as Templates" = "Set as Templates";
|
||||
"Set as Templates" = "Establir com a Plantilles";
|
||||
|
||||
/* Set the folder as the one holding Junk mails */
|
||||
"Set as Junk" = "Estableix com a correu brossa";
|
||||
@@ -464,7 +464,7 @@
|
||||
"Copy messages" = "Copiar els missatges";
|
||||
"More messages options" = "Més opcions de missatges";
|
||||
"Flag" = "Afegir estrella";
|
||||
"Unflag" = "Unflag";
|
||||
"Unflag" = "Treure estrella";
|
||||
"Mark as Unread" = "Marca com a no llegit";
|
||||
"Mark as Read" = "Marca com a llegit";
|
||||
"Closing Window ..." = "Tancant la finestra ...";
|
||||
@@ -478,10 +478,10 @@
|
||||
"Your email has been sent" = "El teu email s'ha enviat";
|
||||
"Folder compacted" = "carpeta compactada";
|
||||
|
||||
"More Options" = "More Options";
|
||||
"More Options" = "Més opcions";
|
||||
|
||||
"New draft" = "New draft";
|
||||
"Create new draft with this template" = "Create new draft with this template";
|
||||
"New draft" = "Nou esborrany";
|
||||
"Create new draft with this template" = "Crear nou esborrany amb aquesta plantilla";
|
||||
|
||||
/* Advanced search */
|
||||
"Enter Subject" = "Introduïu l'Assumpte";
|
||||
@@ -517,16 +517,16 @@
|
||||
"hotkey_forward" = "f";
|
||||
|
||||
/* Email deletion */
|
||||
"Clean folder" = "Clean folder";
|
||||
"Clean mailbox" = "Clean mailbox";
|
||||
"Delete permanently (do not use trash)" = "Delete permanently (do not use trash)";
|
||||
"Apply to subfolders" = "Apply to subfolders";
|
||||
"Delete e-mails older than" = "Delete e-mails older than";
|
||||
"3 months" = "3 months";
|
||||
"6 months" = "6 months";
|
||||
"9 months" = "9 months";
|
||||
"1 year" = "1 year";
|
||||
"Custom" = "Custom";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "You are about to permanently delete some messages. Are you sure you want to proceed with this action?";
|
||||
"Apply" = "Apply";
|
||||
"%{0} message(s) deleted" = "%{0} message(s) deleted";
|
||||
"Clean folder" = "Netejar carpeta";
|
||||
"Clean mailbox" = "Netejar bústia";
|
||||
"Delete permanently (do not use trash)" = "Esborrar permanentment (sense paperera)";
|
||||
"Apply to subfolders" = "Aplicar a subcarpetes";
|
||||
"Delete e-mails older than" = "Esborrar correus més antics de";
|
||||
"3 months" = "3 mesos";
|
||||
"6 months" = "6 mesos";
|
||||
"9 months" = "9 mesos";
|
||||
"1 year" = "1 any";
|
||||
"Custom" = "Personalitzat";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "Esteu a punt d'esborrar permanentment alguns missatges. Esteu segur que voleu continuar amb aquesta acció?";
|
||||
"Apply" = "Aplicar";
|
||||
"%{0} message(s) deleted" = "%{0} missatge(s) esborrat(s)";
|
||||
@@ -171,7 +171,7 @@
|
||||
/* MailListView */
|
||||
"Sender" = "Odesílatel";
|
||||
"Subject or Sender" = "Předmět nebo Odesílatel";
|
||||
"Subject or Recipient" = "Subject or Recipient";
|
||||
"Subject or Recipient" = "Předmět nebo Příjemce";
|
||||
"To or Cc" = "Komu nebo Kopie";
|
||||
"Entire Message" = "Celá zpráva";
|
||||
"Date" = "Datum";
|
||||
@@ -517,16 +517,16 @@
|
||||
"hotkey_forward" = "f";
|
||||
|
||||
/* Email deletion */
|
||||
"Clean folder" = "Clean folder";
|
||||
"Clean mailbox" = "Clean mailbox";
|
||||
"Delete permanently (do not use trash)" = "Delete permanently (do not use trash)";
|
||||
"Apply to subfolders" = "Apply to subfolders";
|
||||
"Delete e-mails older than" = "Delete e-mails older than";
|
||||
"3 months" = "3 months";
|
||||
"6 months" = "6 months";
|
||||
"9 months" = "9 months";
|
||||
"1 year" = "1 year";
|
||||
"Custom" = "Custom";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "You are about to permanently delete some messages. Are you sure you want to proceed with this action?";
|
||||
"Apply" = "Apply";
|
||||
"%{0} message(s) deleted" = "%{0} message(s) deleted";
|
||||
"Clean folder" = "Promazat složku";
|
||||
"Clean mailbox" = "Promazat schránku";
|
||||
"Delete permanently (do not use trash)" = "Smazat trvale (přeskočit Koš)";
|
||||
"Apply to subfolders" = "Použít na podsložky";
|
||||
"Delete e-mails older than" = "Smazat maily starší než";
|
||||
"3 months" = "3 měsíce";
|
||||
"6 months" = "6 měsíců";
|
||||
"9 months" = "9 měsíců";
|
||||
"1 year" = "1 rok";
|
||||
"Custom" = "Vlastní...";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "Tǐmto navždy smažete zprávy. Chcete pokračovat?";
|
||||
"Apply" = "Použít";
|
||||
"%{0} message(s) deleted" = "%{0} zpráv smazáno";
|
||||
@@ -5,7 +5,7 @@
|
||||
"Empty Trash" = "Papierkorb leeren";
|
||||
"Empty Junk Folder" = "Spam-Ordner leeren";
|
||||
"Delete" = "Löschen";
|
||||
"Expunge" = "Expunge";
|
||||
"Expunge" = "Komprimieren";
|
||||
"Forward" = "Weiterleiten";
|
||||
"Get Mail" = "Abrufen";
|
||||
"Junk" = "Spam";
|
||||
@@ -360,7 +360,7 @@
|
||||
"Do you really want to move this folder into the trash ?"
|
||||
= "Wollen Sie diesen Ordner wirklich in den Papierkorb verschieben?";
|
||||
"Operation failed" = "Operation fehlgeschlagen.";
|
||||
"Quota" = "Quota:";
|
||||
"Quota" = "Speicherplatz:";
|
||||
"quotasFormat" = "%{0}% von %{1} MB verwendet";
|
||||
"messageQuotasFormat" = "%{0}% von %{1} Nachrichten";
|
||||
"Unable to move/delete folder." = "Kann den Ordner nicht verschieben/löschen.";
|
||||
|
||||
@@ -0,0 +1,532 @@
|
||||
/* this file is in UTF-8 format! */
|
||||
|
||||
/* Icon's label */
|
||||
"Create" = "Create";
|
||||
"Empty Trash" = "Empty Trash";
|
||||
"Empty Junk Folder" = "Empty Junk Folder";
|
||||
"Delete" = "Delete";
|
||||
"Expunge" = "Expunge";
|
||||
"Forward" = "Forward";
|
||||
"Get Mail" = "Get Mail";
|
||||
"Junk" = "Junk";
|
||||
"Not junk" = "Not junk";
|
||||
"Reply" = "Reply";
|
||||
"Reply All" = "Reply All";
|
||||
"Print" = "Print";
|
||||
"Stop" = "Stop";
|
||||
"Write" = "Write";
|
||||
"Search" = "Search";
|
||||
"Send" = "Send";
|
||||
"Contacts" = "Contacts";
|
||||
"Attach" = "Attach";
|
||||
"Save" = "Save";
|
||||
"Options" = "Options";
|
||||
"Close" = "Close";
|
||||
"Size" = "Size";
|
||||
|
||||
/* Tooltips */
|
||||
"Send this message now" = "Send this message now";
|
||||
"Select a recipient from an Address Book" = "Select a recipient from an Address Book";
|
||||
"Include an attachment" = "Include an attachment";
|
||||
"Save this message" = "Save this message";
|
||||
"Get new messages" = "Get new messages";
|
||||
"Create a new message" = "Create a new message";
|
||||
"Go to address book" = "Go to address book";
|
||||
"Reply to the message" = "Reply to the message";
|
||||
"Reply to sender and all recipients" = "Reply to sender and all recipients";
|
||||
"Forward selected message" = "Forward selected message";
|
||||
"Delete selected message or folder" = "Delete selected message or folder";
|
||||
"Print this message" = "Print this message";
|
||||
"Stop the current transfer" = "Stop the current transfer";
|
||||
"Attachment" = "Attachment";
|
||||
"Unread" = "Unread";
|
||||
"Flagged" = "Flagged";
|
||||
"Search multiple mailboxes" = "Search multiple mailboxes";
|
||||
|
||||
/* Main Frame */
|
||||
"Home" = "Home";
|
||||
"Calendar" = "Calendar";
|
||||
"Addressbook" = "Address Book";
|
||||
"Mail" = "Mail";
|
||||
"Right Administration" = "Right Administration";
|
||||
"Help" = "Help";
|
||||
|
||||
/* Mail account main windows */
|
||||
"Welcome to the SOGo Mailer. Use the folder tree on the left to browse your mail accounts!" = "Welcome to the SOGo Mailer. Use the folder tree on the left to browse your mail accounts!";
|
||||
"Read messages" = "Read messages";
|
||||
|
||||
/* Tooltip for fab button */
|
||||
"Write a new message" = "Write a new message";
|
||||
|
||||
/* Tooltip for fab button */
|
||||
"Write a message in new window" = "Write a message in new window";
|
||||
|
||||
"Share" = "Share";
|
||||
"Account" = "Account";
|
||||
"Shared Account" = "Shared Account";
|
||||
|
||||
/* A mailbox is selected, but no message (only shown on large screens) */
|
||||
"No message selected" = "No message selected";
|
||||
|
||||
/* No mailbox is selected (usually resulting from an IMAP connection problem) */
|
||||
"No mailbox selected" = "No mailbox selected";
|
||||
|
||||
"An error occured while communicating with the mail server" = "An error occured while communicating with the mail server";
|
||||
|
||||
/* Mailbox actions */
|
||||
|
||||
/* Compact Folder success message */
|
||||
"Folder compacted" = "Folder compacted";
|
||||
|
||||
/* Empty Junk Folder success message */
|
||||
"Junk folder emptied" = "Junk folder emptied";
|
||||
|
||||
/* Empty Trash success message */
|
||||
"Trash emptied" = "Trash emptied";
|
||||
|
||||
/* acls */
|
||||
"Access rights to" = "Access rights to";
|
||||
"For user" = "For user";
|
||||
"Any Authenticated User" = "Any Authenticated User";
|
||||
"View this folder" = "View this folder";
|
||||
"Read mails from this folder" = "Read mails from this folder";
|
||||
"Mark mails read and unread" = "Mark mails read and unread";
|
||||
"Modify the flags of the mails in this folder" = "Modify the flags of the mails in this folder";
|
||||
"Insert, copy and move mails into this folder" = "Insert, copy and move mails into this folder";
|
||||
"Post mails" = "Post mails";
|
||||
"Add subfolders to this folder" = "Add subfolders to this folder";
|
||||
"Remove this folder" = "Remove this folder";
|
||||
"Erase mails from this folder" = "Erase mails from this folder";
|
||||
"Expunge this folder" = "Expunge this folder";
|
||||
"Export This Folder" = "Export This Folder";
|
||||
"Modify the acl of this folder" = "Modify the acl of this folder";
|
||||
"Saved Messages.zip" = "Saved Messages.zip";
|
||||
"Update" = "Update";
|
||||
"Cancel" = "Cancel";
|
||||
|
||||
/* Mail edition */
|
||||
"From" = "From";
|
||||
"Subject" = "Subject";
|
||||
"To" = "To";
|
||||
"Cc" = "Cc";
|
||||
"Bcc" = "Bcc";
|
||||
"Reply-To" = "Reply-To";
|
||||
"Add address" = "Add address";
|
||||
"Body" = "Body";
|
||||
"Open" = "Open";
|
||||
"Select All" = "Select All";
|
||||
"Select Message" = "Select Message";
|
||||
"Attach Web Page..." = "Attach Web Page...";
|
||||
"file" = "file";
|
||||
"files" = "files";
|
||||
"Save all" = "Save all";
|
||||
"to" = "To";
|
||||
"cc" = "Cc";
|
||||
"bcc" = "Bcc";
|
||||
"Add a recipient" = "Add a recipient";
|
||||
"Edit Draft..." = "Edit Draft...";
|
||||
"Load Images" = "Load Images";
|
||||
"Return Receipt" = "Return Receipt";
|
||||
"Choose which identity to send this message from" = "Choose which identity to send this message from";
|
||||
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "The sender of this message has asked to be notified when you read this message. Do you wish to notify the sender?";
|
||||
"Return Receipt (displayed) - %@"= "Return Receipt (displayed) - %@";
|
||||
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents.";
|
||||
"Security" = "Security";
|
||||
"Sign" = "Sign";
|
||||
"Encrypt" = "Encrypt";
|
||||
"Priority" = "Priority";
|
||||
"highest" = "Highest";
|
||||
"high" = "High";
|
||||
"normal" = "Normal";
|
||||
"low" = "Low";
|
||||
"lowest" = "Lowest";
|
||||
"This mail is being sent from an unsecure network!" = "This mail is being sent from an unsecure network!";
|
||||
"Address Book" = "Address Book";
|
||||
"Search For" = "Search For";
|
||||
"Contains" = "Contains";
|
||||
"Does not contains" = "Does not contains";
|
||||
"Advanced search" = "Advanced search";
|
||||
"Anytime" = "Anytime";
|
||||
"Last 7 days" = "Last 7 days";
|
||||
"Last 30 days" = "Last 30 days";
|
||||
"Last 6 month" = "Last 6 month";
|
||||
"Before" = "Before";
|
||||
"After" = "After";
|
||||
"Between" = "Between";
|
||||
"and" = "and";
|
||||
"With attachments" = "With attachments";
|
||||
"In favorites" = "In favorites";
|
||||
"Unseen only" = "Unseen only";
|
||||
"Show more" = "Show more";
|
||||
"Reset" = "Reset";
|
||||
"Message size" = "Message size";
|
||||
|
||||
/* Popup "show" */
|
||||
"all" = "all";
|
||||
"read" = "read";
|
||||
"unread" = "unread";
|
||||
"deleted" = "deleted";
|
||||
"flagged" = "flagged";
|
||||
|
||||
/* MailListView */
|
||||
"Sender" = "Sender";
|
||||
"Subject or Sender" = "Subject or Sender";
|
||||
"Subject or Recipient" = "Subject or Recipient";
|
||||
"To or Cc" = "To or Cc";
|
||||
"Entire Message" = "Entire Message";
|
||||
"Date" = "Date";
|
||||
"View" = "View";
|
||||
"All" = "All";
|
||||
"No message" = "No message";
|
||||
"messages" = "messages";
|
||||
"Yesterday" = "Yesterday";
|
||||
"first" = "First";
|
||||
"previous" = "Previous";
|
||||
"next" = "Next";
|
||||
"last" = "Last";
|
||||
"msgnumber_to" = "to";
|
||||
"msgnumber_of" = "of";
|
||||
"Mark Unread" = "Mark Unread";
|
||||
"Mark Read" = "Mark Read";
|
||||
"Untitled" = "Untitled";
|
||||
|
||||
/* Filter option in messages list */
|
||||
"Show unread messages only" = "Show unread messages only";
|
||||
|
||||
/* Filter option in messages list */
|
||||
"Show flagged messages only" = "Show flagged messages only";
|
||||
|
||||
/* Aria label for icon of labels */
|
||||
"Filtered by label" = "Filtered by label";
|
||||
|
||||
/* Tree */
|
||||
"SentFolderName" = "Sent";
|
||||
"TrashFolderName" = "Trash";
|
||||
"InboxFolderName" = "Inbox";
|
||||
"DraftsFolderName" = "Drafts";
|
||||
"JunkFolderName" = "Junk";
|
||||
"TemplatesFolderName" = "Templates";
|
||||
"SieveFolderName" = "Filters";
|
||||
"Folders" = "Folders"; /* title line */
|
||||
|
||||
/* MailMoveToPopUp */
|
||||
"MoveTo" = "Move …";
|
||||
|
||||
/* Address Popup menu */
|
||||
"Add to Address Book..." = "Add to Address Book...";
|
||||
"Successfully created card" = "Successfully created card";
|
||||
"Compose Mail To" = "Compose Mail To";
|
||||
"Create Filter From Message..." = "Create Filter From Message...";
|
||||
|
||||
/* Image Popup menu */
|
||||
"Save Image" = "Save Image";
|
||||
"Save Attachment" = "Save Attachment";
|
||||
|
||||
/* Mailbox popup menus */
|
||||
"Open in New Mail Window" = "Open in New Mail Window";
|
||||
"Copy Folder Location" = "Copy Folder Location";
|
||||
"Subscribe..." = "Subscribe...";
|
||||
"Mark Folder Read" = "Mark Folder Read";
|
||||
"New Folder..." = "New Folder...";
|
||||
"Compact This Folder" = "Compact This Folder";
|
||||
"Search Messages..." = "Search Messages...";
|
||||
"Sharing..." = "Sharing...";
|
||||
"New Subfolder..." = "New Subfolder...";
|
||||
"Rename Folder..." = "Rename Folder...";
|
||||
"Delete Folder" = "Delete Folder";
|
||||
"Use This Folder For" = "Use This Folder For";
|
||||
"Get Messages for Account" = "Get Messages for Account";
|
||||
"Properties..." = "Properties...";
|
||||
"Delegation..." = "Delegation...";
|
||||
|
||||
/* Use This Folder menu */
|
||||
"Sent Messages" = "Sent Messages";
|
||||
"Drafts" = "Drafts";
|
||||
"Deleted Messages" = "Deleted Messages";
|
||||
"Junk Messages" = "Junk Messages";
|
||||
|
||||
/* Message list popup menu */
|
||||
"Open Message In New Window" = "Open Message In New Window";
|
||||
"Reply to Sender Only" = "Reply to Sender Only";
|
||||
"Reply to All" = "Reply to All";
|
||||
"Edit As New..." = "Edit As New...";
|
||||
"Move To" = "Move To";
|
||||
"Copy To" = "Copy To";
|
||||
"Label" = "Label";
|
||||
"Mark" = "Mark";
|
||||
"Save As..." = "Save As...";
|
||||
"Print Preview" = "Print Preview";
|
||||
"View Message Source" = "View Message Source";
|
||||
"View raw message" = "View raw message";
|
||||
|
||||
/* Message view "more" menu: create an event from message */
|
||||
"Convert To Event" = "Convert To Event";
|
||||
|
||||
/* Message view "more" menu: create a task from message */
|
||||
"Convert To Task" = "Convert To Task";
|
||||
|
||||
/* Message view "more" menu: download message as an eml file */
|
||||
"Download message" = "Download message";
|
||||
|
||||
/* Message view "more" menu: download message as a zip archive */
|
||||
"Download message (zip)" = "Download message (zip)";
|
||||
|
||||
/* Message view "more" menu: download all attachments as a zip archive */
|
||||
"Download all attachments" = "Download all attachments";
|
||||
|
||||
/* Filename prefix when downloading all attachments as a zip archive */
|
||||
"attachments" = "attachments";
|
||||
|
||||
"Print..." = "Print...";
|
||||
"Delete Message" = "Delete Message";
|
||||
"Delete Selected Messages" = "Delete Selected Messages";
|
||||
"Mark the selected messages as junk" = "Mark the selected messages as junk";
|
||||
"Mark the selected messages as not junk" = "Mark the selected messages as not junk";
|
||||
|
||||
/* Text appended to the recipients list when there are too many recipients */
|
||||
"and %{0} more..." = "and %{0} more...";
|
||||
|
||||
/* Button label to hide extended list of recipients */
|
||||
"Hide" = "Hide";
|
||||
|
||||
/* Number of selected messages in list */
|
||||
"selected" = "selected";
|
||||
|
||||
/* Date formatting from one time to another time */
|
||||
"to_time" = "to";
|
||||
|
||||
/* Date formatting from one day to another day */
|
||||
"to_date" = "to";
|
||||
|
||||
/* Encrypted message notification */
|
||||
"This message is encrypted" = "This message is encrypted";
|
||||
|
||||
/* Encrypted message but no certificate */
|
||||
"This message can't be decrypted. Please make sure you have uploaded your S/MIME certificate from the mail preferences module." = "This message can't be decrypted. Please make sure you have uploaded your S/MIME certificate from the mail preferences module.";
|
||||
|
||||
/* OpenSSL certificate error - unknown issuer */
|
||||
"certificate verify error" = "Unable to verify message signature";
|
||||
|
||||
/* OpenSSL certificate error - digest failure */
|
||||
"digest failure" = "The message has been modified";
|
||||
|
||||
/* OpenSSL reading error */
|
||||
"Error reading the certificate. Please install a new certificate." = "Error reading the certificate. Please install a new certificate.";
|
||||
|
||||
/* Trying to access a non-existent certificate */
|
||||
"No certificate associated to account." = "No certificate associated to account.";
|
||||
|
||||
/* Invalid S/MIME signature */
|
||||
"Digital signature is not valid" = "Digital signature is not valid";
|
||||
|
||||
/* Valid S/MIME signature */
|
||||
"Message is signed" = "Message is signed";
|
||||
|
||||
/* Valid S/MIME signature but common name not found */
|
||||
"Message is signed but the certificate doesn't match the sender email address" = "Message is signed but the certificate doesn't match the sender email address";
|
||||
|
||||
/* Unknown error while validating message signature */
|
||||
"Digital signature is not valid" = "Digital signature is not valid";
|
||||
|
||||
"This Folder" = "This Folder";
|
||||
|
||||
/* Label popup menu */
|
||||
"None" = "None";
|
||||
|
||||
/* Mark popup menu */
|
||||
"As Read" = "As Read";
|
||||
"Thread As Read" = "Thread As Read";
|
||||
"As Read By Date..." = "As Read By Date...";
|
||||
"All Read" = "All Read";
|
||||
"As Junk" = "As Junk";
|
||||
"As Not Junk" = "As Not Junk";
|
||||
"Run Junk Mail Controls" = "Run Junk Mail Controls";
|
||||
"Search messages in" = "Search messages in";
|
||||
"Search" = "Search";
|
||||
"Search subfolders" = "Search subfolders";
|
||||
"Match any of the following" = "Match any of the following";
|
||||
"Match all of the following" = "Match all of the following";
|
||||
"contains" = "contains";
|
||||
"does not contain" = "does not contain";
|
||||
"No matches found" = "No matches found";
|
||||
"results found" = "results found";
|
||||
"result found" = "result found";
|
||||
"Please specify at least one filter" = "Please specify at least one filter";
|
||||
|
||||
/* Folder operations */
|
||||
"Name" = "Name";
|
||||
"Enter the new name of your folder"
|
||||
="Enter the new name of your folder";
|
||||
"Do you really want to move this folder into the trash ?"
|
||||
= "Do you really want to move this folder into the trash ?";
|
||||
"Operation failed" = "Operation failed";
|
||||
"Quota" = "Quota:";
|
||||
"quotasFormat" = "%{0}% used on %{1} MB";
|
||||
"messageQuotasFormat" = "%{0}% of %{1} msgs";
|
||||
"Unable to move/delete folder." = "Unable to move/delete folder.";
|
||||
|
||||
/* Alternative operation when folder cannot be deleted */
|
||||
"The mailbox could not be moved to the trash folder. Would you like to delete it immediately?"
|
||||
= "The mailbox could not be moved to the trash folder. Would you like to delete it immediately?";
|
||||
|
||||
/* Confirmation message when deleting multiple messages */
|
||||
"Are you sure you want to delete the selected messages?" = "Are you sure you want to delete the selected messages?";
|
||||
|
||||
/* Notification on the number of messages successfuly copied */
|
||||
"%{0} message(s) copied" = "%{0} message(s) copied";
|
||||
|
||||
/* Notification on the number of messages successfuly movied */
|
||||
"%{0} message(s) moved" = "%{0} message(s) moved";
|
||||
|
||||
"Please select a message." = "Please select a message.";
|
||||
"Please select a message to print." = "Please select a message to print.";
|
||||
"Please select only one message to print." = "Please select only one message to print.";
|
||||
"The message you have selected doesn't exist anymore." = "The message you have selected doesn't exist anymore.";
|
||||
"The folder with name \"%{0}\" could not be created."
|
||||
= "The folder with name \"%{0}\" could not be created.";
|
||||
"This folder could not be renamed to \"%{0}\"."
|
||||
= "This folder could not be renamed to \"%{0}\".";
|
||||
"The folder could not be deleted."
|
||||
= "The folder could not be deleted.";
|
||||
"The trash could not be emptied."
|
||||
= "The trash could not be emptied.";
|
||||
"The folder functionality could not be changed."
|
||||
= "The folder functionality could not be changed.";
|
||||
"You need to choose a non-virtual folder!" = "You need to choose a non-virtual folder!";
|
||||
"Moving a message into its own folder is impossible!"
|
||||
= "Moving a message into its own folder is impossible!";
|
||||
"Copying a message into its own folder is impossible!"
|
||||
= "Copying a message into its own folder is impossible!";
|
||||
|
||||
/* Message operations */
|
||||
"The messages could not be moved to the trash folder. Would you like to delete them immediately?"
|
||||
= "The messages could not be moved to the trash folder. Would you like to delete them immediately?";
|
||||
|
||||
/* Message editing */
|
||||
"Please specify a subject." = "Please specify a subject.";
|
||||
"error_missingsubject" = "The message has no subject. Are you sure you want to send it?";
|
||||
"error_missingrecipients" = "Please specify at least one recipient.";
|
||||
"Send Anyway" = "Send Anyway";
|
||||
"Error while saving the draft" = "Error while saving the draft";
|
||||
|
||||
/* Error when emptying trash */
|
||||
"Unable to empty the trash folder." = "Unable to empty the trash folder.";
|
||||
|
||||
/* Error when emptying junk folder */
|
||||
"Unable to empty the junk folder." = "Unable to empty the junk folder.";
|
||||
|
||||
/* Error when uploading a file attachment */
|
||||
"Error while uploading the file \"%{0}\":" = "Error while uploading the file \"%{0}\":";
|
||||
"There is an active file upload. Closing the window will interrupt it." = "There is an active file upload. Closing the window will interrupt it.";
|
||||
"Message is too big" = "Message is too big";
|
||||
|
||||
/* Appears while sending the message */
|
||||
"Sending" = "Sending";
|
||||
|
||||
/* Appears when the message is successfuly sent */
|
||||
"Sent" = "Sent";
|
||||
|
||||
"cannot send message: (smtp) all recipients discarded" = "Cannot send message: all recipients are invalid.";
|
||||
"cannot send message (smtp) - recipients discarded" = "Cannot send message. The following addresses are invalid";
|
||||
"cannot send message: (smtp) error when connecting" = "Cannot send message: error when connecting to the SMTP server.";
|
||||
"cannot sign email without certificate" = "The message can't be signed because there's no certificate associated to the mail account.";
|
||||
"cannot sign message because the certificate can't be read" = "The message can't be signed becasue the certificate associated to the mail account can't be read.";
|
||||
"cannot sign message because the certificate doesn't include the specified sender address" = "The message can't be signed because the sender address is not included in the certificate associated to the mail account.";
|
||||
|
||||
/* Contacts list in mail editor */
|
||||
"Email" = "Email";
|
||||
"More mail options" = "More mail options";
|
||||
"Delegation" = "Delegation";
|
||||
"Add User" = "Add User";
|
||||
"Add a tag" = "Add a tag";
|
||||
"reply" = "reply";
|
||||
"Edit" = "Edit";
|
||||
"Yes" = "Yes";
|
||||
"No" = "No";
|
||||
"Location" = "Location";
|
||||
"Rename" = "Rename";
|
||||
"Compact" = "Compact";
|
||||
"Export" = "Export";
|
||||
"Set as Drafts" = "Set as Drafts";
|
||||
"Set as Sent" = "Set as Sent";
|
||||
"Set as Trash" = "Set as Trash";
|
||||
|
||||
/* Set the folder as the one holding the Templates */
|
||||
"Set as Templates" = "Set as Templates";
|
||||
|
||||
/* Set the folder as the one holding Junk mails */
|
||||
"Set as Junk" = "Set as Junk";
|
||||
|
||||
"Sort" = "Sort";
|
||||
"Order Received" = "Order Received";
|
||||
"Descending Order" = "Descending Order";
|
||||
"Back" = "Back";
|
||||
"Copy messages" = "Copy messages";
|
||||
"More messages options" = "More messages options";
|
||||
"Flag" = "Flag";
|
||||
"Unflag" = "Unflag";
|
||||
"Mark as Unread" = "Mark as Unread";
|
||||
"Mark as Read" = "Mark as Read";
|
||||
"Closing Window ..." = "Closing Window ...";
|
||||
"Tried to send too many mails. Please wait." = "Tried to send too many mails. Please wait.";
|
||||
"View Mail" = "View Mail";
|
||||
"This message contains external images." = "This message contains external images.";
|
||||
"Expanded" = "Expanded";
|
||||
"Add a Criteria" = "Add a Criteria";
|
||||
"More search options" = "More search options";
|
||||
"Your email has been saved" = "Your email has been saved";
|
||||
"Your email has been sent" = "Your email has been sent";
|
||||
"Folder compacted" = "Folder compacted";
|
||||
|
||||
"More Options" = "More Options";
|
||||
|
||||
"New draft" = "New draft";
|
||||
"Create new draft with this template" = "Create new draft with this template";
|
||||
|
||||
/* Advanced search */
|
||||
"Enter Subject" = "Enter Subject";
|
||||
"Enter From" = "Enter From";
|
||||
"Enter To" = "Enter To";
|
||||
"Enter Cc" = "Enter Cc";
|
||||
"Enter Body" = "Enter Body";
|
||||
"match" = "match";
|
||||
"does not match" = "does not match";
|
||||
|
||||
/* Aria label for scope of search on messages */
|
||||
"Search scope" = "Search scope";
|
||||
|
||||
/* Subscriptions Dialog */
|
||||
"Manage Subscriptions" = "Manage Subscriptions";
|
||||
|
||||
/* Label of filter input field in subscriptions dialog */
|
||||
"Filter" = "Filter";
|
||||
|
||||
/* Hotkey to write a new message */
|
||||
"hotkey_compose" = "w";
|
||||
|
||||
/* Hotkey to flag a message */
|
||||
"hotkey_flag" = "*";
|
||||
|
||||
/* Hotkey to reply to a message */
|
||||
"hotkey_reply" = "r";
|
||||
|
||||
/* Hotkey to reply to all recipients of a message */
|
||||
"hotkey_replyall" = "a";
|
||||
|
||||
/* Hotkey to forward to a message */
|
||||
"hotkey_forward" = "f";
|
||||
|
||||
/* Email deletion */
|
||||
"Clean folder" = "Clean folder";
|
||||
"Clean mailbox" = "Clean mailbox";
|
||||
"Delete permanently (do not use trash)" = "Delete permanently (do not use trash)";
|
||||
"Apply to subfolders" = "Apply to subfolders";
|
||||
"Delete e-mails older than" = "Delete e-mails older than";
|
||||
"3 months" = "3 months";
|
||||
"6 months" = "6 months";
|
||||
"9 months" = "9 months";
|
||||
"1 year" = "1 year";
|
||||
"Custom" = "Custom";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "You are about to permanently delete some messages. Are you sure you want to proceed with this action?";
|
||||
"Apply" = "Apply";
|
||||
"%{0} message(s) deleted" = "%{0} message(s) deleted";
|
||||
@@ -143,23 +143,23 @@
|
||||
"This mail is being sent from an unsecure network!" = "A levelet nem biztonságos hálózatból készül elküldeni!";
|
||||
"Address Book" = "Címjegyzék";
|
||||
"Search For" = "Keresés";
|
||||
"Contains" = "Contains";
|
||||
"Does not contains" = "Does not contains";
|
||||
"Advanced search" = "Advanced search";
|
||||
"Anytime" = "Anytime";
|
||||
"Last 7 days" = "Last 7 days";
|
||||
"Last 30 days" = "Last 30 days";
|
||||
"Last 6 month" = "Last 6 month";
|
||||
"Before" = "Before";
|
||||
"After" = "After";
|
||||
"Between" = "Between";
|
||||
"and" = "and";
|
||||
"With attachments" = "With attachments";
|
||||
"In favorites" = "In favorites";
|
||||
"Unseen only" = "Unseen only";
|
||||
"Show more" = "Show more";
|
||||
"Reset" = "Reset";
|
||||
"Message size" = "Message size";
|
||||
"Contains" = "Tartalmazza";
|
||||
"Does not contains" = "Nem tartalmazza";
|
||||
"Advanced search" = "Bővített keresés";
|
||||
"Anytime" = "Bármikor";
|
||||
"Last 7 days" = "Előző 7 nap";
|
||||
"Last 30 days" = "Előző 30 nap";
|
||||
"Last 6 month" = "Előző 6 hónap";
|
||||
"Before" = "Előtte";
|
||||
"After" = "Utána";
|
||||
"Between" = "Között";
|
||||
"and" = "és";
|
||||
"With attachments" = "Mellékletekkel";
|
||||
"In favorites" = "Kedvencek között";
|
||||
"Unseen only" = "Csak a még nem olvasott";
|
||||
"Show more" = "Továbbiak megjelenítése";
|
||||
"Reset" = "Alaphelyzet";
|
||||
"Message size" = "Üzenet mérete";
|
||||
|
||||
/* Popup "show" */
|
||||
"all" = "összes";
|
||||
@@ -171,7 +171,7 @@
|
||||
/* MailListView */
|
||||
"Sender" = "Feladó";
|
||||
"Subject or Sender" = "Tárgy vagy feladó";
|
||||
"Subject or Recipient" = "Subject or Recipient";
|
||||
"Subject or Recipient" = "Tárgy vagy címzett";
|
||||
"To or Cc" = "Címzett vagy másolat";
|
||||
"Entire Message" = "A teljes üzenet";
|
||||
"Date" = "Dátum";
|
||||
@@ -257,7 +257,7 @@
|
||||
"Save As..." = "Mentés másként...";
|
||||
"Print Preview" = "Nyomtatási kép";
|
||||
"View Message Source" = "Üzenet forrása";
|
||||
"View raw message" = "View raw message";
|
||||
"View raw message" = "Nyers üzenet megtekintése";
|
||||
|
||||
/* Message view "more" menu: create an event from message */
|
||||
"Convert To Event" = "Eseménnyé alakít";
|
||||
@@ -434,7 +434,7 @@
|
||||
"cannot sign message because the certificate doesn't include the specified sender address" = "Az üzenetet nem lehet aláírni, mivel a feladó címe nem található meg postafiókhoz hozzárendelt tanúsítványban.";
|
||||
|
||||
/* Contacts list in mail editor */
|
||||
"Email" = "Email";
|
||||
"Email" = "Email cím";
|
||||
"More mail options" = "További levelezési tulajdonságok";
|
||||
"Delegation" = "Jogok átadása";
|
||||
"Add User" = "Felhasználó hozzáadása";
|
||||
@@ -517,16 +517,16 @@
|
||||
"hotkey_forward" = "f";
|
||||
|
||||
/* Email deletion */
|
||||
"Clean folder" = "Clean folder";
|
||||
"Clean mailbox" = "Clean mailbox";
|
||||
"Delete permanently (do not use trash)" = "Delete permanently (do not use trash)";
|
||||
"Apply to subfolders" = "Apply to subfolders";
|
||||
"Delete e-mails older than" = "Delete e-mails older than";
|
||||
"3 months" = "3 months";
|
||||
"6 months" = "6 months";
|
||||
"9 months" = "9 months";
|
||||
"1 year" = "1 year";
|
||||
"Custom" = "Custom";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "You are about to permanently delete some messages. Are you sure you want to proceed with this action?";
|
||||
"Apply" = "Apply";
|
||||
"%{0} message(s) deleted" = "%{0} message(s) deleted";
|
||||
"Clean folder" = "Mappa ürítése";
|
||||
"Clean mailbox" = "Postafiók ürítése";
|
||||
"Delete permanently (do not use trash)" = "Végleges törlés (ne használjon lomtárat)";
|
||||
"Apply to subfolders" = "Alkalmazza az almappákra";
|
||||
"Delete e-mails older than" = "Emailek törlése amelyek régebbiek mint";
|
||||
"3 months" = "3 hónap";
|
||||
"6 months" = "6 hónap";
|
||||
"9 months" = "9 hónap";
|
||||
"1 year" = "1 év";
|
||||
"Custom" = "Egyéni";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "Véglegesen törölni kíván néhány üzenetet. Biztosan végrehajtja a műveletet?";
|
||||
"Apply" = "Alkalmaz";
|
||||
"%{0} message(s) deleted" = "%{0} üzenet törölve";
|
||||
@@ -171,7 +171,7 @@
|
||||
/* MailListView */
|
||||
"Sender" = "Nadawca";
|
||||
"Subject or Sender" = "Temat lub nadawca";
|
||||
"Subject or Recipient" = "Subject or Recipient";
|
||||
"Subject or Recipient" = "Nadawca lub Odbiorca";
|
||||
"To or Cc" = "Do lub DW";
|
||||
"Entire Message" = "Cała wiadomość";
|
||||
"Date" = "Data";
|
||||
@@ -517,16 +517,16 @@
|
||||
"hotkey_forward" = "f";
|
||||
|
||||
/* Email deletion */
|
||||
"Clean folder" = "Clean folder";
|
||||
"Clean mailbox" = "Clean mailbox";
|
||||
"Delete permanently (do not use trash)" = "Delete permanently (do not use trash)";
|
||||
"Apply to subfolders" = "Apply to subfolders";
|
||||
"Delete e-mails older than" = "Delete e-mails older than";
|
||||
"3 months" = "3 months";
|
||||
"6 months" = "6 months";
|
||||
"9 months" = "9 months";
|
||||
"1 year" = "1 year";
|
||||
"Custom" = "Custom";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "You are about to permanently delete some messages. Are you sure you want to proceed with this action?";
|
||||
"Apply" = "Apply";
|
||||
"%{0} message(s) deleted" = "%{0} message(s) deleted";
|
||||
"Clean folder" = "Uporządkuj folder";
|
||||
"Clean mailbox" = "Uporządkuj skrzynkę pocztową";
|
||||
"Delete permanently (do not use trash)" = "Usuń trwale (nie używaj kosza)";
|
||||
"Apply to subfolders" = "Zastosuj do podfolderów";
|
||||
"Delete e-mails older than" = "Usuń wiadomości starsze niż";
|
||||
"3 months" = "3 miesiące";
|
||||
"6 months" = "6 miesięcy";
|
||||
"9 months" = "9 miesięcy";
|
||||
"1 year" = "1 rok";
|
||||
"Custom" = "Ustaw";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "Za chwilę trwale usuniesz część wiadomości. Na pewno chcesz to zrobić?";
|
||||
"Apply" = "Wykonaj";
|
||||
"%{0} message(s) deleted" = "usunięto %{0} wiadomości";
|
||||
@@ -293,10 +293,10 @@
|
||||
"selected" = "выбран";
|
||||
|
||||
/* Date formatting from one time to another time */
|
||||
"to_time" = "в";
|
||||
"to_time" = "до";
|
||||
|
||||
/* Date formatting from one day to another day */
|
||||
"to_date" = "в";
|
||||
"to_date" = "по";
|
||||
|
||||
/* Encrypted message notification */
|
||||
"This message is encrypted" = "Это сообщение зашифровано";
|
||||
|
||||
Loaded 100 of 277 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user