Compare commits

...
127 Commits
Author SHA1 Message Date
smizrahi 9f96905c3a feat(core): Add URL encryption for GDPR compliancy. Remove log 2024-01-02 13:48:54 +01:00
smizrahi 10d789fb1f feat(core): Add URL encryption for GDPR compliancy 2023-12-22 11:33:40 +01:00
smizrahi d505b874f7 Merge branch 'master' into feature-gdpr 2023-12-20 18:01:40 +01:00
Hivert Quentin cbeaa4cc11 chore(ytnef): missing symbols with centos 2023-12-20 17:02:32 +01:00
Hivert Quentin 427f7f4b4f feature(contact): Show 100 first results for global address book. Fix commit #17eca6f 2023-12-20 15:36:37 +01:00
Hivert Quentin d68bbc836c chore(js/css): update generated files 2023-12-19 01:00:44 -05:00
smizrahi 51b6c0d9a3 fix(ui): Fix text/placeholder overlaps when Chrome autofill applies 2023-12-18 22:42:13 +01:00
Hivert Quentin 5f2e4889f3 chore(js/css): update generated files 2023-12-18 08:27:23 -05:00
smizrahi 37379ba416 fix(preferences): Fix error 500 when changing password 2023-12-18 14:24:50 +01:00
smizrahi 17eca6f96a feature(contact): Show 100 first results for global address book 2023-12-18 08:34:53 +01:00
Hivert Quentin 26c7462eb0 fix(contacts): Custom contacts categories in sogo.conf wasn't working 2023-12-14 18:11:10 +01:00
smizrahi 0d471efe97 Update changelog 2023-12-12 13:00:46 +01:00
Hivert Quentin 8375c9352e chore(js/css): update generated files 2023-12-12 06:10:11 -05:00
smizrahi f85c53190c fix(addressbook): Fix exception when using multiple address book source and searching. Fixes #5906. 2023-12-12 12:08:25 +01:00
Hivert Quentin 3cd860838c chore(js/css): update generated files 2023-12-12 01:00:56 -05:00
Hivert Quentin 377cff935f chore(release): 5.9.1 2023-12-11 15:49:23 +01:00
Hivert Quentin 06a6ed7768 i18n(cy): Update Welsh translations 2023-12-11 14:32:48 +01:00
Hivert Quentin 0e50d37531 i18n(uk): Update Ukrainian translations 2023-12-11 14:32:47 +01:00
Hivert Quentin 8d1fc1e306 i18n(tr_TR): Update TurkishTurkey translations 2023-12-11 14:32:47 +01:00
Hivert Quentin 10369aa654 i18n(sv): Update Swedish translations 2023-12-11 14:32:46 +01:00
Hivert Quentin 057a1ba105 i18n(es_ES): Update SpanishSpain translations 2023-12-11 14:32:46 +01:00
Hivert Quentin 527fded19c i18n(es_AR): Update SpanishArgentina translations 2023-12-11 14:32:45 +01:00
Hivert Quentin ca21bf4ce1 i18n(sl_SI): Update Slovenian translations 2023-12-11 14:32:45 +01:00
Hivert Quentin cd7e06c2ed i18n(sk): Update Slovak translations 2023-12-11 14:32:44 +01:00
Hivert Quentin 9126cae27d i18n(sr@latin): Update SerbianLatin translations 2023-12-11 14:32:43 +01:00
Hivert Quentin ed444fdc22 i18n(sr): Update Serbian translations 2023-12-11 14:32:43 +01:00
Hivert Quentin 3809ec3904 i18n(ru): Update Russian translations 2023-12-11 14:32:41 +01:00
Hivert Quentin d9c716c1b6 i18n(ro_RO): Update Romanian translations 2023-12-11 14:32:41 +01:00
Hivert Quentin e4f07c466e i18n(pt): Update Portuguese translations 2023-12-11 14:32:40 +01:00
Hivert Quentin 6d270fe7a4 i18n(nn_NO): Update NorwegianNynorsk translations 2023-12-11 14:32:40 +01:00
Hivert Quentin 3d5f352111 i18n(nb_NO): Update NorwegianBokmal translations 2023-12-11 14:32:39 +01:00
Hivert Quentin fe7369e427 i18n(sr_ME@latin): Update Montenegrin translations 2023-12-11 14:32:39 +01:00
Hivert Quentin d6c9ecdeb0 i18n(mk_MK): Update Macedonian translations 2023-12-11 14:32:39 +01:00
Hivert Quentin a9ecaed5fa i18n(lv): Update Latvian translations 2023-12-11 14:32:38 +01:00
Hivert Quentin 21741954dd i18n(kk): Update Kazakh translations 2023-12-11 14:32:38 +01:00
Hivert Quentin 41fb85e6a3 i18n(ja): Update Japanese translations 2023-12-11 14:32:38 +01:00
Hivert Quentin 53036b323f i18n(it): Update Italian translations 2023-12-11 14:32:36 +01:00
Hivert Quentin a16d29b70b i18n(id_ID): Update Indonesian translations 2023-12-11 14:32:35 +01:00
Hivert Quentin 2de6241220 i18n(is): Update Icelandic translations 2023-12-11 14:32:34 +01:00
Hivert Quentin 0b22fa6cd5 i18n(hu): Update Hungarian translations 2023-12-11 14:32:34 +01:00
Hivert Quentin 694c21de99 i18n(he): Update Hebrew translations 2023-12-11 14:32:34 +01:00
Hivert Quentin 5aa7ebf2ae i18n(gl): Update Galician translations 2023-12-11 14:32:33 +01:00
Hivert Quentin dba2332864 i18n(fi): Update Finnish translations 2023-12-11 14:32:33 +01:00
Hivert Quentin 402c3d0a1f i18n(nl): Update Dutch translations 2023-12-11 14:32:33 +01:00
Hivert Quentin 76911fd445 i18n(da_DK): Update Danish translations 2023-12-11 14:32:32 +01:00
Hivert Quentin 029a82143f i18n(cs): Update Czech translations 2023-12-11 14:32:32 +01:00
Hivert Quentin 715d25d40a i18n(hr_HR): Update Croatian translations 2023-12-11 14:32:31 +01:00
Hivert Quentin fc2a82c3b0 i18n(zh_TW): Update ChineseTaiwan translations 2023-12-11 14:32:31 +01:00
Hivert Quentin cf87022348 i18n(zh_CN): Update ChineseChina translations 2023-12-11 14:32:31 +01:00
Hivert Quentin 3040543c79 i18n(ca): Update Catalan translations 2023-12-11 14:32:31 +01:00
Hivert Quentin 3815bc1c5e i18n(bg_BG): Update Bulgarian translations 2023-12-11 14:32:31 +01:00
Hivert Quentin 2afbcbeaed i18n(bs_BA): Update Bosnian translations 2023-12-11 14:32:31 +01:00
Hivert Quentin 33f3a1b716 i18n(eu): Update Basque translations 2023-12-11 14:32:31 +01:00
Hivert Quentin 28d883dac1 i18n(ar): Update Arabic translations 2023-12-11 14:32:31 +01:00
Hivert Quentin c75f210864 i18n(pl): Update Polish translations 2023-12-11 14:32:31 +01:00
Hivert Quentin cfab85624b i18n(pt_BR): Update BrazilianPortuguese translations 2023-12-11 14:32:30 +01:00
Hivert Quentin 6e9e7f98ef i18n(lt): Update Lithuanian translations 2023-12-11 14:32:30 +01:00
Hivert Quentin 8a4bc2a716 i18n(de): Update German translations 2023-12-11 14:32:30 +01:00
Hivert Quentin fd5e28ec77 chore(js/css): update theme default 2023-12-11 14:06:44 +01:00
Hivert Quentin 1961f1a914 chore(js/css): update generated files 2023-12-11 14:06:44 +01:00
Hivert Quentin 0704949056 chore(npm): Update CKEditor to version 4.22.1 2023-12-11 14:06:44 +01:00
WoodySlum 85870d6b16 Merge pull request #350 from kovacs-andras/master
docs(guides): update documentation url
2023-12-11 14:03:27 +01:00
Andras Kovacs 669dcaa242 update documentation url 2023-12-05 14:38:11 +01:00
Hivert Quentin 21571ab1e0 fix(calendar): If content is NSData, properly convert it to NSString 2023-12-05 10:58:48 +01:00
smizrahi 7d66699219 feat(password): Add specials characters to POLICY_MIN_SPECIAL_SYMBOLS 2023-12-04 16:43:16 +01:00
smizrahi cd50ee0176 feat(core): Add mobile provisioning download for Apple's devices. Fix nil port when using standard http configuration (port 80 and 443) 2023-12-04 10:36:41 +01:00
WoodySlum da24c0d0a7 Merge pull request #348 from marvin-j97/patch-1
style(login): Replace envelop icon with key on login page
2023-11-28 16:44:03 +01:00
Marvin 7b15327b19 Use vpn_key icon 2023-11-28 15:47:35 +01:00
Hivert Quentin 6eae3f2b16 i18n(gl): Change Galician name to Galego 2023-11-28 08:49:31 +01:00
smizrahi 3cd9910638 fix(core): Fix user profile retrieval when using utf8mb4_bin collation - in this case the SQL results may return NSdata instead of NSString. Fixes #5902. 2023-11-27 15:51:33 +01:00
smizrahi fb542e6e26 Merge branch 'feature-5726-gab-autocomplete' 2023-11-27 11:19:17 +01:00
smizrahi 60e6bb5b3b Merge branch 'master' into feature-5726-gab-autocomplete 2023-11-27 11:18:31 +01:00
Hivert Quentin 86c9b4ec07 chore(js/css): update generated files 2023-11-24 01:01:04 -05:00
Hivert Quentin 2e670f7e62 feat(mail): Add an option in Preferences to display full email instead of name alone in mailboxes 2023-11-23 14:09:57 +01:00
Hivert Quentin 8babb23c58 chore(js/css): update generated files 2023-11-23 01:00:53 -05:00
Hivert Quentin 1ae02ebd70 fix(UI): selectAll button was still keeping alle items in memory 2023-11-22 11:07:58 +01:00
smizrahi aa53524751 feat(mail): Add SOGoMailHideInlineAttachments option to hide attachments when inline. Fixes #5490. Fix default values in sogo.conf. 2023-11-20 11:57:26 +01:00
Marvin 6734b4ea16 design(RootPage): Use lock icon for password field
https://pictogrammers.com/library/mdi/icon/key/
2023-11-18 15:46:46 +01:00
Hivert Quentin bb943e414d fix(sogo-tool): add protection to expire-sessions if the input is not an integer 2023-11-17 15:50:41 +01:00
smizrahi ca2c5c188e feat(mail): Add SOGoMailHideInlineAttachments option to hide attachments when inline. Fixes #5490. Improve bracket icon. 2023-11-17 10:46:22 +01:00
Hivert Quentin 0023a9ce3c fix(calendar): do not let DURATION and DTEND be both present in vevent 2023-11-17 09:24:12 +01:00
Hivert Quentin 1e8127b461 fix(calendar): properly set the start date range for yearly events 2023-11-16 11:18:23 +01:00
smizrahi 6b08f2e4de fix(core): Fix calendar issues with Thunderbird related to vlist exclusion. Fix error log on photo. Closes #5885 2023-11-13 23:02:07 +01:00
Hivert Quentin 605d8b1169 chore(js/css): update generated files 2023-11-11 00:00:50 -05:00
Hivert Quentin c872fb4d9c feat(preferences): can set SOGoForwardConstraints to 3 to accept both internal and external domains from SOGoForwardConstraintsDomains 2023-11-10 15:07:14 +01:00
smizrahi 11ad203388 feat(addressbook): Add global address book autocomplete on vlist 2023-11-09 14:08:16 +01:00
smizrahi 0b1f2b0405 feat(addressbook): Add global address book autocomplete on vlist 2023-11-08 22:36:40 +01:00
smizrahi 0560efd1f6 feat(addressbook): Add global address book autocomplete on vlist 2023-11-08 18:10:06 +01:00
smizrahi d1634054d6 fix(mail): Clean temporary files when mail is sent. Check if body part is NGMimeFileData to add path for cleaning. 2023-11-07 10:38:54 +01:00
Hivert Quentin 7481ccf370 fix(hmtl): prevent html injection of tag form 2023-11-06 14:04:53 +01:00
Hivert Quentin 65374e44fc fix(scripts): wrong type for c_value in script for complete unicode coverage 2023-11-06 09:21:52 +01:00
Hivert Quentin f8b7986501 fix(template): wrong ending tag 2023-11-04 11:32:17 +01:00
Hivert Quentin 8da3d06117 chore(js/css): update generated files 2023-11-04 00:00:46 -04:00
Hivert Quentin d0b4b50456 feat(core): add SOGoDisableExport option to disable export for mail, calendar and contacts 2023-11-03 18:20:12 +01:00
Hivert Quentin e0ef59d5f2 feat(core): Add SOGoDisableSharingAnyAuthUser option to disable sharing to any user authenticated for mail, contacts and calendar 2023-11-03 17:01:49 +01:00
Hivert Quentin 6e60b10755 feat(ux): select all button will unselect all if click again 2023-11-03 15:13:48 +01:00
Hivert Quentin 0df0e34073 doc(sogo-tool): Add doc to detailed sogo-tool 2023-11-02 17:20:05 +01:00
smizrahi f41ab2ed0c feat(mail): Add SOGoMailHideInlineAttachments option to hide attachments when inline. Fixes #5490. 2023-11-02 09:45:51 +01:00
smizrahi abce5f42cf feat(mail): Add SOGoMailHideInlineAttachments option to hide attachments when inline. Fixes #5490. 2023-11-01 18:25:01 +01:00
smizrahi 277b73c663 docs(calendar+addressbook): Add provisioning profile doc 2023-11-01 15:57:42 +01:00
smizrahi f35a37bbdd fix(mail): Clean temporary files when mail is sent 2023-11-01 15:40:33 +01:00
smizrahi 9c0948518b fix(mail): Fix duplication of images when saving draft. Fixes #5888. Clean old code 2023-11-01 10:29:25 +01:00
smizrahi 4fe01f96d7 feat(core): Add mobile provisioning download for Apple's devices. Update translations (incompatible icon under windows) 2023-10-31 12:15:00 +01:00
smizrahi a273f7aca5 feat(core): Add mobile provisioning download for Apple's devices. Update translations (incompatible icon under windows) 2023-10-31 12:10:05 +01:00
Hivert Quentin 8f635d4856 chore(js/css): update generated files 2023-10-31 00:00:55 -04:00
Hivert Quentin 068126cd22 chore(js/css): update generated files 2023-10-19 00:00:47 -04:00
smizrahi 9ef49bb56f feat(core): Add URL encryption for GDPR compliancy (fix some dav issues) 2023-10-18 16:37:08 +02:00
smizrahi 54a1f922f9 Merge branch 'master' into feature-gdpr 2023-10-18 13:29:29 +02:00
smizrahi 65f8336255 feat(core): Add mobile provisioning download for Apple's devices. Fix shared calendar and contacts 2023-10-18 11:43:35 +02:00
WoodySlum c67ad819ab Merge pull request #347 from leecher1337/fix-5884
fix(eas): Fix for excessive memory usage on mailboxes with thousands of folders (by @leecher1337)
2023-10-17 21:03:39 +02:00
smizrahi 64a6319635 feat(core): Add URL encryption for GDPR compliancy (refactoring) 2023-10-17 16:43:50 +02:00
smizrahi 31c6f78913 feat(core): Add URL encryption for GDPR compliancy 2023-10-17 16:17:25 +02:00
Hivert Quentin 4b45dc7584 fix(translation): incorret value causing trouble to transifex 2023-10-17 09:23:33 +02:00
leecher1337 063fb2be3d Fix for excessive memory usage on mailboxes with thousands of folders 2023-10-16 16:12:24 +02:00
smizrahi ee9899fe3d fix(mail): Fix duplication of images when saving draft. Fixes #5888 2023-10-13 10:29:42 +02:00
smizrahi 81f2d88db3 fix(core): Add cache for CDefaultsSize to avoid spamming SQL request (pgsql) 2023-10-11 12:57:45 +02:00
Hivert Quentin baf6bdfedf chore(js/css): update generated files 2023-10-11 06:23:20 -04:00
Hivert Quentin c569ed2d77 fix(http): set correct Accept header when dowloading eml file 2023-10-11 11:32:26 +02:00
smizrahi 87e1240ace fix(core): Add cache for CDefaultsSize to avoid spamming SQL request 2023-10-10 17:37:59 +02:00
Hivert Quentin b396a277f0 feat(reply): add references header when replying 2023-10-04 14:55:27 +02:00
Hivert Quentin e460e5377c chore(js/css): update generated files 2023-10-04 00:00:47 -04:00
Hivert Quentin 1d3da92bab fix(addressbook): autocomplete correctly return two contacts from two ldap with same id 2023-10-03 14:28:57 +02:00
Hivert Quentin b1d8475520 chore(language): fixed french and double key 2023-10-03 09:12:02 +02:00
smizrahi d38cc86d29 feat(core): Add mobile provisioning download for Apple's devices. Fix build issue 2023-09-28 09:18:43 +02:00
Hivert Quentin df2f73f1f6 chore(js/css): update generated files 2023-09-28 00:00:48 -04:00
smizrahi 19915e3dff feat(core): Add mobile provisioning download for Apple's devices 2023-09-27 17:28:29 +02:00
smizrahi 6d16ee7988 feat(core): Add mobile provisioning download for Apple's devices 2023-09-27 17:28:29 +02:00
402 changed files with 3519 additions and 1260 deletions

No files matched your search

+2 -2
View File
@@ -2627,17 +2627,17 @@ FIXME
// We first check of any of the collections we want to sync are already
// in an other sync process. If that's the case, we do not do anything
// and we return immediately. So we'll let the other sync process terminate
globalMetadata = [self globalMetadataForDevice];
for (j = 0; j < [allCollections count]; j++)
{
aCollection = [allCollections objectAtIndex: j];
globalMetadata = [self globalMetadataForDevice];
key = [NSString stringWithFormat: @"SyncRequest+%@", [[[(id)[aCollection getElementsByTagName: @"CollectionId"] lastObject] textValue] stringByUnescapingURL]];
if (!([[globalMetadata objectForKey: key] isEqual: processIdentifier]))
{
if (debugOn)
[self logWithFormat: @"EAS - Discard response %@", [self globalMetadataForDevice]];
[self logWithFormat: @"EAS - Discard response %@", globalMetadata];
[output appendString: @"<Status>13</Status>"];
[output appendString: @"</Sync>"];
+81
View File
@@ -2,6 +2,87 @@
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.9.1](https://github.com/Alinto/sogo/compare/SOGo-5.9.0...SOGo-5.9.1) (2023-12-12)
### Features
* **addressbook:** Add global address book autocomplete on vlist ([11ad203](https://github.com/Alinto/sogo/commit/11ad203388ad33a22bd300047745869a27872cd9) [0b1f2b0](https://github.com/Alinto/sogo/commit/0b1f2b0405410628cb7ba8602b9286d71256d8e6) [0560efd](https://github.com/Alinto/sogo/commit/0560efd1f6a94bcb256d970ebe5535954e36cafe), [f85c531](https://github.com/Alinto/sogo/commit/f85c53190c38c4e28536f78e43623f6776248291))
* **core:** Add mobile provisioning download for Apple's devices ([19915e3](https://github.com/Alinto/sogo/commit/19915e3dffc14c90b03277f9f97b4e6b1158aa87) [6d16ee7](https://github.com/Alinto/sogo/commit/6d16ee798863a7f196c14915c47888adf0758f1a) [d38cc86](https://github.com/Alinto/sogo/commit/d38cc86d29ffce580bf26dd278a6b68556471c14) [cd50ee0](https://github.com/Alinto/sogo/commit/cd50ee017656f3e6cfd46cff7147258d4893706b) [65f8336](https://github.com/Alinto/sogo/commit/65f8336255577566282039f4058fe4f3c38a16d4) [4fe01f9](https://github.com/Alinto/sogo/commit/4fe01f96d73690bf1a2d60755bb552d25324ccaf) [a273f7a](https://github.com/Alinto/sogo/commit/a273f7aca5df120a50af0486161880040ee20519))
* **core:** add SOGoDisableExport option to disable export for mail, calendar and contacts ([d0b4b50](https://github.com/Alinto/sogo/commit/d0b4b50456cf3e23aa12d5cf7165531a7670edf6))
* **core:** Add SOGoDisableSharingAnyAuthUser option to disable sharing to any user authenticated for mail, contacts and calendar ([e0ef59d](https://github.com/Alinto/sogo/commit/e0ef59d5f212aced72a17e3af9e72a434eedd68e))
* **mail:** Add an option in Preferences to display full email instead of name alone in mailboxes ([2e670f7](https://github.com/Alinto/sogo/commit/2e670f7e6293b703f8cfe23ebf923ce13b463a19))
* **mail:** Add SOGoMailHideInlineAttachments option to hide attachments when inline. Fixes [#5490](https://bugs.sogo.nu/view.php?id=5490). ([f41ab2e](https://github.com/Alinto/sogo/commit/f41ab2ed0c71903b80bda66adc54cc94b0cf70d6) [abce5f4](https://github.com/Alinto/sogo/commit/abce5f42cf4daef721ebf6b48d727eb957e20b14) [aa53524](https://github.com/Alinto/sogo/commit/aa535247513b06804fce666fe20ebcc9bd231c1f) [ca2c5c1](https://github.com/Alinto/sogo/commit/ca2c5c188ed980629f494e5b8e23ba42cdd54f58))
* **password:** Add specials characters to POLICY_MIN_SPECIAL_SYMBOLS ([7d66699](https://github.com/Alinto/sogo/commit/7d666992198e5e91e29081b99443607b1c96d354))
* **preferences:** can set SOGoForwardConstraints to 3 to accept both internal and external domains from SOGoForwardConstraintsDomains ([c872fb4](https://github.com/Alinto/sogo/commit/c872fb4d9c68382431a52181073ba1964cf44c22))
* **reply:** add references header when replying ([b396a27](https://github.com/Alinto/sogo/commit/b396a277f00d879d2c179db780d6f621a9057d0c))
* **ux:** select all button will unselect all if click again ([6e60b10](https://github.com/Alinto/sogo/commit/6e60b107556212123f41d95e4399d9605a4c16f9) [1ae02eb](https://github.com/Alinto/sogo/commit/1ae02ebd708da0a53ae588531e122adddaa7a5de))
### Bug Fixes
* **addressbook:** autocomplete correctly return two contacts from two ldap with same id ([1d3da92](https://github.com/Alinto/sogo/commit/1d3da92bab972ec7ec935eba72128e72387216c0))
* **calendar:** do not let DURATION and DTEND be both present in vevent ([0023a9c](https://github.com/Alinto/sogo/commit/0023a9ce3c4027bb32699efc5529a4a53d7699f6))
* **calendar:** If content is NSData, properly convert it to NSString ([21571ab](https://github.com/Alinto/sogo/commit/21571ab1e000da47b91b3f21bfaba89d1abec71f))
* **calendar:** properly set the start date range for yearly events ([1e8127b](https://github.com/Alinto/sogo/commit/1e8127b46122e83df02c394536950288b0ee16aa))
* **core:** Add cache for CDefaultsSize to avoid spamming SQL request ([87e1240](https://github.com/Alinto/sogo/commit/87e1240ace297645559e698a8c1f1a76b9901895) [81f2d88](https://github.com/Alinto/sogo/commit/81f2d88db362cc21c50858295d0e9d375db61f67))
* **core:** Fix calendar issues with Thunderbird related to vlist exclusion. Fix error log on photo. Closes [#5885](https://bugs.sogo.nu/view.php?id=5885) ([6b08f2e](https://github.com/Alinto/sogo/commit/6b08f2e4decc87ee57609355dee5a6657bca6110))
* **core:** Fix user profile retrieval when using utf8mb4_bin collation - in this case the SQL results may return NSdata instead of NSString. Fixes [#5902](https://bugs.sogo.nu/view.php?id=5902). ([3cd9910](https://github.com/Alinto/sogo/commit/3cd991063805f88a5672b10fbcc04a4149e13e26))
* **hmtl:** prevent html injection of tag form ([7481ccf](https://github.com/Alinto/sogo/commit/7481ccf37087c3f456d7e5a844da01d0f8883098))
* **http:** set correct Accept header when dowloading eml file ([c569ed2](https://github.com/Alinto/sogo/commit/c569ed2d77cf23c274c3dfc7cd3533cf268d09af))
* **mail:** Clean temporary files when mail is sent ([f35a37b](https://github.com/Alinto/sogo/commit/f35a37bbdd2005a63b42f9bab1588ce9a935b112) [d163405](https://github.com/Alinto/sogo/commit/d1634054d6f4dd18bdb82a7903b3bbbceae5b0e8))
* **mail:** Fix duplication of images when saving draft. Fixes [#5888](https://bugs.sogo.nu/view.php?id=5888) ([ee9899f](https://github.com/Alinto/sogo/commit/ee9899fe3d6aa7bf694f959a8e4f09faa39e737a) [9c09485](https://github.com/Alinto/sogo/commit/9c0948518b1e8365d6fadb3fccae1a0257b518ed))
* **scripts:** wrong type for c_value in script for complete unicode coverage ([65374e4](https://github.com/Alinto/sogo/commit/65374e44fc2a861d3a7c9f1f9ba25505601d79f1))
* **sogo-tool:** add protection to expire-sessions if the input is not an integer ([bb943e4](https://github.com/Alinto/sogo/commit/bb943e414d3fc8b71ebb169e31c261cd2dcd6d37))
* **translation:** incorret value causing trouble to transifex ([4b45dc7](https://github.com/Alinto/sogo/commit/4b45dc7584984602071efe99b9638c6231efba8c))
### Localization
* **ar:** Update Arabic translations ([28d883d](https://github.com/Alinto/sogo/commit/28d883dac1ccbafb878b9e13ba38f570f44ea325))
* **bg_BG:** Update Bulgarian translations ([3815bc1](https://github.com/Alinto/sogo/commit/3815bc1c5e6fe37aaad5492c246697fe34e4286d))
* **bs_BA:** Update Bosnian translations ([2afbcbe](https://github.com/Alinto/sogo/commit/2afbcbeaed24571785437aa5af1c092ba129ce97))
* **ca:** Update Catalan translations ([3040543](https://github.com/Alinto/sogo/commit/3040543c797fe9176df048b8a72a2c6f7dbfd3b7))
* **cs:** Update Czech translations ([029a821](https://github.com/Alinto/sogo/commit/029a82143f1d0d82ca8d6a5c9e5a14ac351718bf))
* **cy:** Update Welsh translations ([06a6ed7](https://github.com/Alinto/sogo/commit/06a6ed776824f47e5606c29a162903380e72fbd9))
* **da_DK:** Update Danish translations ([76911fd](https://github.com/Alinto/sogo/commit/76911fd4454c9f0213f11b4e2e95b29010eed9a4))
* **de:** Update German translations ([8a4bc2a](https://github.com/Alinto/sogo/commit/8a4bc2a71642a2a431008c02214ffdd0eb2ace23))
* **es_AR:** Update SpanishArgentina translations ([527fded](https://github.com/Alinto/sogo/commit/527fded19ceaf995963e997659b79c5e1290b8c5))
* **es_ES:** Update SpanishSpain translations ([057a1ba](https://github.com/Alinto/sogo/commit/057a1ba1053f462cd0633b86c3ee86d76acbd6bb))
* **eu:** Update Basque translations ([33f3a1b](https://github.com/Alinto/sogo/commit/33f3a1b716a006df8a28c416fc947e44fc285e37))
* **fi:** Update Finnish translations ([dba2332](https://github.com/Alinto/sogo/commit/dba2332864fa38116615c9b58eb3590fe251a37a))
* **gl:** Change Galician name to Galego ([6eae3f2](https://github.com/Alinto/sogo/commit/6eae3f2b1601033558a791c27bc4e27acf0825e7))
* **gl:** Update Galician translations ([5aa7ebf](https://github.com/Alinto/sogo/commit/5aa7ebf2aefef6e45423b2193c136fadced51375))
* **he:** Update Hebrew translations ([694c21d](https://github.com/Alinto/sogo/commit/694c21de99522733c95304d0e775e81493ff7200))
* **hr_HR:** Update Croatian translations ([715d25d](https://github.com/Alinto/sogo/commit/715d25d40a84b518b1d8f97b4946045a4be761b5))
* **hu:** Update Hungarian translations ([0b22fa6](https://github.com/Alinto/sogo/commit/0b22fa6cd5b55db5d021bbbfcc53d411ff4bb9d7))
* **id_ID:** Update Indonesian translations ([a16d29b](https://github.com/Alinto/sogo/commit/a16d29b70b50eeee14a3ad1b627e8f8a59216461))
* **is:** Update Icelandic translations ([2de6241](https://github.com/Alinto/sogo/commit/2de624122045d9df877f39f665d271056af0fba8))
* **it:** Update Italian translations ([53036b3](https://github.com/Alinto/sogo/commit/53036b323fe65b4bf40c838ff0578fa076bfea93))
* **ja:** Update Japanese translations ([41fb85e](https://github.com/Alinto/sogo/commit/41fb85e6a320b25776ce63672ef4251e932f82f0))
* **kk:** Update Kazakh translations ([2174195](https://github.com/Alinto/sogo/commit/21741954dd2762b3f03c0b5b21b8feb4d826cfb1))
* **lt:** Update Lithuanian translations ([6e9e7f9](https://github.com/Alinto/sogo/commit/6e9e7f98ef379ce26937e00daedfad88383615a4))
* **lv:** Update Latvian translations ([a9ecaed](https://github.com/Alinto/sogo/commit/a9ecaed5fa6fe8fecf08ec0354bbb187824d2fbb))
* **mk_MK:** Update Macedonian translations ([d6c9ecd](https://github.com/Alinto/sogo/commit/d6c9ecdeb0490fa44bc1c444819b5c82ccf89073))
* **nb_NO:** Update NorwegianBokmal translations ([3d5f352](https://github.com/Alinto/sogo/commit/3d5f35211189802ef031be688cadddc2ab684d37))
* **nl:** Update Dutch translations ([402c3d0](https://github.com/Alinto/sogo/commit/402c3d0a1f83d32af2fca2f3e5abafbe8850de08))
* **nn_NO:** Update NorwegianNynorsk translations ([6d270fe](https://github.com/Alinto/sogo/commit/6d270fe7a4bad2253f7e8427be660405460b2139))
* **pl:** Update Polish translations ([c75f210](https://github.com/Alinto/sogo/commit/c75f210864de1a7bb313c1ba21be987143a2f7ca))
* **pt_BR:** Update BrazilianPortuguese translations ([cfab856](https://github.com/Alinto/sogo/commit/cfab85624b3e725f121ea61d181340189e969229))
* **pt:** Update Portuguese translations ([e4f07c4](https://github.com/Alinto/sogo/commit/e4f07c466e195d59f72b934567cb3aa4d18cb9f3))
* **ro_RO:** Update Romanian translations ([d9c716c](https://github.com/Alinto/sogo/commit/d9c716c1b679a792876c9bc7ebed2d530ab8d89f))
* **ru:** Update Russian translations ([3809ec3](https://github.com/Alinto/sogo/commit/3809ec3904a7882239e50c671aa72c9f7f013c62))
* **sk:** Update Slovak translations ([cd7e06c](https://github.com/Alinto/sogo/commit/cd7e06c2ede339d078e54b76b6078523b78383fc))
* **sl_SI:** Update Slovenian translations ([ca21bf4](https://github.com/Alinto/sogo/commit/ca21bf4ce1758717eac8ec961788d067e9428456))
* **sr_ME@latin:** Update Montenegrin translations ([fe7369e](https://github.com/Alinto/sogo/commit/fe7369e427d7cc6f4efb23a78437bd2b2c65e6cd))
* **sr@latin:** Update SerbianLatin translations ([9126cae](https://github.com/Alinto/sogo/commit/9126cae27d49b7f199f2a6b259eb40589b011a55))
* **sr:** Update Serbian translations ([ed444fd](https://github.com/Alinto/sogo/commit/ed444fdc2266888f9d15d557e1ba92896158d870))
* **sv:** Update Swedish translations ([10369aa](https://github.com/Alinto/sogo/commit/10369aa654058b50285ae7239a9356f736c7ac1c))
* **tr_TR:** Update TurkishTurkey translations ([8d1fc1e](https://github.com/Alinto/sogo/commit/8d1fc1e306d926b3efeab2e3017823201254caf0))
* **uk:** Update Ukrainian translations ([0e50d37](https://github.com/Alinto/sogo/commit/0e50d37531d850b46009af2af5049a6b46541da0))
* **zh_CN:** Update ChineseChina translations ([cf87022](https://github.com/Alinto/sogo/commit/cf87022348296b9659e83e3a3985b48d89f5e01f))
* **zh_TW:** Update ChineseTaiwan translations ([fc2a82c](https://github.com/Alinto/sogo/commit/fc2a82c3b0f4b780df3b4d27ad0da78e34f665c6))
## [5.9.0](https://github.com/Alinto/sogo/compare/SOGo-5.8.3...SOGo-5.9.0) (2023-09-27)
+526 -6
View File
@@ -21,7 +21,7 @@ devices with SOGo.
The instructions are based on version {release_version} of SOGo.
The latest version of this guide is available
at https://sogo.nu/downloads/documentation.html.
at https://www.sogo.nu/support.html#/documentation.
Introduction
------------
@@ -693,6 +693,13 @@ Defaults to `NO` when unset.
|S |SOGoDisableSharing
|List of modules where sharing should be disabled, for example `(Mail, Calendar)`. Modules can be `Mail`, `Contacts` and `Calendar`. Default value empty list (sharing enabled for everybody).
|S |SOGoDisableSharingAnyAuthUser
|List of modules where sharing with any authenticated user option should be disabled, for example `(Mail, Calendar)`. Modules can be `Mail`, `Contacts` and `Calendar`. Default value empty list (sharing enabled for everybody).
|S |SOGoDisableExport
|List of modules where export should be disabled, for example `(Mail, Calendar)`. Modules can be `Mail`, `Contacts` and `Calendar`. Default value empty list (export enabled for everybody).
|S |SOGoPasswordChangeEnabled
|Parameter used to allow or not users to change their passwords from
SOGo.
@@ -819,7 +826,17 @@ specified as an array of dictionaries.
|D |SOGoCreateIdentitiesDisabled
|Disable identity creation for users in preferences. If `YES`, users won't be able to add new identities and will allow to change only full name, signature and default identity. Default value is `NO`. Note : If this settings is set to `YES`, it will not be possible to crete auxiliary mail accounts.
|S |SOGoURLEncryptionEnabled
|Enable URL encryption to make SOGo GDPR compatible. Setting this parameter to `YES` will encrypt username in URL. The encryption data are cached to avoid high cpu usage, ig the value of thie parameter is changed, memcached server needs to be restarted. If the encryption is enabled, the DAV url will change. Default value is `NO`.
|S |SOGoURLEncryptionPassphrase
|Passphrase for `SOGoURLEncryptionEnabled`. The string must be 128 bits (16 characters). If this settings change, the cache server must be restarted, and the DAV url will change. Default value is `SOGoSuperSecret0`.
|S |SOGoGlobalAddressBookFirstEntries
|Display first entries in Global Address Book. Default value is `NO`. If source is LDAP, the LDAP overlay `sssvlv` must be enabled on the system for server side sorting.
|S |SOGoGlobalAddressBookFirstEntriesCount
|Number of entries displayed when `SOGoGlobalAddressBookFirstEntries` is enabled. Default value is `100`.
|=======================================================================
@@ -2273,12 +2290,14 @@ Defaults to `NO` when unset.
|D |SOGoForwardConstraints
|Parameter used to set constraints on possible addresses used when
automatically forwarding mails. When set to `0` (default), no constraint
is enforced. When set to `1`, only internal domains can be used. When
set to `2`, only external domains can be used.
is enforced. When set to `1`, only internal domains can be used.
When set to `2`, only external domains defined in `SOGoForwardConstraintsDomains`
can be used. When set to `3`, internal domains and other domains defined
in `SOGoForwardConstraintsDomains` can be used.
|D |SOGoForwardConstraintsDomains
|Parameter used to set which domains are allowed as external domains
when SOGoForwardConstraints is set to `2`. For example, setting:
|Parameter used to set which external domains are allowed
when SOGoForwardConstraints is set to `2` or `3`. For example, setting:
SOGoForwardConstraintsDomains = ("gmail.com", "googlemail.com");
@@ -2481,6 +2500,13 @@ Defaults to `NO` when unset.
Defaults to `inline` when unset.
|U |SOGoMailDisplayFullEmail
|Show recipients or sender full email in mailboxes if set to `YES`. Default value is `NO`.
|U |SOGoMailHideInlineAttachments
|Hide inline message as attachements if set to `YES`. Default value is `NO`.
|U |SOGoMailCustomFullName
|The string to use as full name when composing an email, if
_SOGoMailCustomFromEnabled_ is set in the user's domain defaults.
@@ -3206,7 +3232,7 @@ your site. However, be aware that in order to use the SOGo Integrator
plug in, you will need to repackage it with specific modifications.
Please refer to the documentation published online:
https://sogo.nu/downloads/documentation.html
https://www.sogo.nu/support.html#/documentation
If you only use the SOGo Connector plug in, you can still easily access
your data.
@@ -3243,6 +3269,12 @@ http://127.0.0.1/SOGo/dav/jdoe/
Note that the trailing slash is important for the old Apple iCal 3 application.
Since SOGo 5.9.1, calendar can be installed using provisioning profiles. On the calendar interface next to the calendar name (eg `Personal`), click on the three dots button and click on `Download iOS - MacOS configuration profile`.
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
~~~~~~~~~~~~~~~~~
@@ -3286,6 +3318,12 @@ The virtual host should be defined like:
This configuration is also required if you want to configure a CardDAV
account on an Apple iOS device (version 4.0 and later).
Since SOGo 5.9.1, address book can be installed using provisioning profiles. On the address book interface next to the address book name (eg `Personal`), click on the three dots button and click on `Download iOS - MacOS configuration profile`.
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
~~~~~~~~~~~~~~~~~~~~
@@ -3296,6 +3334,488 @@ 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
---------------
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:
yum install sogo-tool
*_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
~~~~~~~~~~~~~~~~~~~~~~~~
The backup tool saves the information of a user into a file. The information saved are its preferences, its events and its contacts.
sogo-tool backup directory ALL|user1 [user2] ...
* First argument, *directory* must be a path, only the last subdirectory will be created, the previous ones must exist.
* Second argument is *ALL* to backup all users or put each user space-separated.
* Each user's info will take one file, the filename will be the username.
* The files are readable but in a specific format for _sogo-tool restore_.
Example:
----
sogo-tool backup /tmp/foo ALL # Will save all users into /tmp/foo
sogo-tool backup /etc/sogo_backup/foo user1 user2 # Will save only user1 and user2. The directory /etc/sogo_backup must exist.
----
Using the files produced by the backup, you can restore all or some information of a user with the _restore_ command:
sogo-tool restore [-l|-p|-f/-F folder/ALL] [-c credentialFile] directory user
* First argument must be one of the four mode options *-l*, *-p*, *-f* or *-F*.
* Second, optional, is *-c* with the credential file. Only useful with *-p* mode.
* *directory* is the path where the backup file is.
* *user* is the name of the backup file, which is the username if you use the _backup_ tool.
The differents mode are:
* *-l* will only list the folders (meaning calendar and address book) that would be restored with *-f* or *-F*.
Example:
----
sogo-tool restore -l /tmp/backup user1
----
Result:
----
Calendar/60C8-65323D80-7-4D9F7D80 (new_calendar)
Calendar/personal (Personal Calendar)
Contacts/personal (Personal Address Book)
----
* *-p* will restore the user's preferences. If the user has an active sieve script (filter, vacation, forward...) you must provide a credential file with
the parameters *-c*. The credential file is a simple one-line file that contains the "username:password" of an admin account of your imap/sieve server.
Example:
----
sogo-tool restore -p /tmp/backup user1
sogo-tool restore -p -c /var/sogo/cred /tmp/backup user1
----
* *-f* will restore the events/contacts of folders (calendar and address book) from the backup file that don't exist in the database. If the event/contact
was deleted but is in the backup file, it will be restored. If the event/contact exist, nothing will be done even if it has been modified compared to the
backup file. If a whole folder has been deleted but is in the backup file, it will be restored. *-f* expect a value that can be ALL to restore all folders,
or the name of the folder to restore. You can list them with the *-l* mode.
Example:
----
sogo-tool restore -f ALL /tmp/backup user1
sogo-tool restore -f "Contacts/personal" tmp/backup user1
sogo-tool restore -f "Calendar/60C8-65323D80-7-4D9F7D80" tmp/backup user1
----
The commands will either prints out nothing or any events/contacts restored:
----
restoring record '60CA-65323D00-1-680B0A00.ics'
restoring record '60C8-65323D00-1-4D9F7D80.vcf'
restoring record '60C8-65323D80-9-4D9F7D80.ics'
----
* *-F* has the same behavior as *-f* but it will first delete all contacts and events in database before restoring the backup.
So if an event/contact is not in the backup file, it will be lost. If a folder exists but is not in the backup file, nothing will happen
to it and its content.
*-F* expect a value that can be ALL to restore all folders, or the name of the folder to restore. You can list them with the *-l* mode.
Example:
----
sogo-tool restore -F ALL /tmp/backup user1
sogo-tool restore -F "Contacts/personal" tmp/backup user1
sogo-tool restore -F "Calendar/60C8-65323D80-7-4D9F7D80" tmp/backup user1
----
sogo-tool checkup
~~~~~~~~~~~~~~~~~
Check the events and contacts data's integrity of a user
sogo-tool checkup [-d] user...
* *-d*, optional, will delete all corrupted data.
* *user* is a single username or multiple user each space-separated.
Will print out nothing if no corrupted data were found or one of the following messages:
* Corrupted calendar item (missing tags) in path <path> with c_name = <ics_id>
* Corrupted calendar item (unparsable) in path <path> with c_name = <ics_id>
* Missing start date of event in path <path> with c_name = <ics_id> (<event_name>)"
* Missing end date of event in path <path> with c_name = <ics_id> (<event_name>)"
* Start date (<start_date>) is not before end date (<end_date>) for event in path <path> with c_name = <ics_id> (<event_name>)
* Corrupted card item (unparsable) in path <path> with c_name = <vcard_id>
It can also print log from SOGo if it raise errors:
* <0x0x55e0956c4d00[VSCardSaxDriver]> serious inconsistency among begin/end tags
Example:
----
sogo-tool checkup user1
sogo-tool checkup -d user1
----
sogo-tool cleanup
~~~~~~~~~~~~~~~~~
Will purge all user's deleted events and contacts which the deletion is older than a number of days.
sogo-tool cleanup [days] ALL|user1 [user2]
* *days* the age of deleted records to purge in days
* Second argument is *ALL* to purge events of all users or put each user space-separated.
Example:
----
sogo-tool cleanup 30 ALL
sogo-tool cleanup 30 user1 user2
----
Outputs:
----
Purged 3 records from folder /Users/user1/Calendar/60C7-65325300-9-18F39AA0
Purged 1 records from folder /Users/user1/Calendar/60C8-65323D80-7-4D9F7D80
Purged 0 records from folder /Users/user1/Calendar/personal
Purged 0 records from folder /Users/user1/Contacts/personal
Purged 5 records from folder /Users/user2/Calendar/personal
----
sogo-tool create-folder
~~~~~~~~~~~~~~~~~~~~~~~
Create a folder (Calendar or Address Book) for a user.
create-folder user type [displayname ...]
* *user* is the name of the user
* *type* is either "Calendar" or "Contacts"
* *displayname* is the folder's name. If the name is already taken, a new folder will still be made but with another uid.
Example:
----
sogo-tool create-folder user1 Contacts Pro_Contacts Ext_Contacts
sogo-tool create-folder user2 Calendar Pro_Calendar
----
sogo-tool dump-defaults
~~~~~~~~~~~~~~~~~~~~~~~
Output all current defaults value of GNUstep and SOGo (sogo.conf)
sogo-tool dump-defaults [-f <filename>|[all]]
* Can be used without arguments and will output the defaults for gnustep domain 'sogod'.
* *all* option will output all defaults value found from sogo and gnustep in property list format.
* *-f* expect a filepath of an .xml file and will output it in property list format (sogo.conf). May need some tweaks, though.
Example:
----
sogo-tool dump-defaults
sogo-tool dump-defaults all
sogo-tool dump-defaults -f /tmp/foo/conf.xml
----
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
also set a cookie with an encoded value to fetch this database table. That way, each time the user make a request with that cookie,
sogo will know which connected user it is. This command will remove all user's session from database
without activity for specified number of minutes. Those users will have to log in again.
sogo-tool expire-sessions [nbMinutes]
* *nbMinutes* Integer, number of minutes. All session without activity in these last minutes will be removed.
Example:
----
sogo-tool expire-sessions #Will print usage.
sogo-tool expire-sessions 160 #Will remove session which last activity is older than 160 minutes.
sogo-tool expire-sessions 0 #Will remove session which last activity is older than 0 minutes.
----
sogo-tool manage-acl
~~~~~~~~~~~~~~~~~~~~
Manage access-control list (ACL) of a user for folders (Calendar and Address Book).
sogo-tool manage-acl get|add|remove|subscribe|unsubscribe owner folder user|group <rights>
* First argument is the action among *get*, *add*, *remove*, *subscribe* and *unsubscribe*.
* Second argument is the username of the folder's owner.
* Third argument is the name of the folder.
* Fourth argument is the user whom to manage its acl. It also can be _ALL_, _anonymous_ and _<defaults>_.
* Fifth argument, only needed with *add* action, is the rights to set for the user.
The actions:
* *get* will print out the folder's rights of the user or nothing if the user is not found or doesn't have any rights.
Example:
----
sogo-tool manage-acl get sogo-tests1 Calendar/5E1F-653FC400-1-38155940 sogo-tests2
----
Result:
----
Rights for sogo-tests2 ["PublicModifier", "ConfidentialModifier", "PrivateModifier", "ObjectCreator", "ObjectEraser"]
----
* *add* will add the given rights to the user for the given folder. the value right is a json string of an array with each right to set.
Be Careful as there is no check for the rights already set. It could be better to first remove them, then add them.
The rights for Address Book are:
* _ObjectCreator_: can create cards (contact of list)
* _ObjectEditor_: can modify cards
* _ObjectViewer_: can view cards
* _ObjectEraser_: can delete cards
The rights for Calendar are:
* _ObjectCreator_: can create event or task
* _ObjectEraser_: can delete event or task
* _<type>_ can be _Public_, _Confidential_ or _Private_
* _<type>Viewer_: can view the whole events (ex: PrivateViewer)
* _<type>DAndTViewer_: can only view the date and time of events
* _<type>Modifier_: can view and edit the events
* _<type>Responder_: can view the events
Example:
----
sogo-tool manage-acl add sogo-tests1 Contacts/5E1D-653FC400-1-1A330C40 sogo-tests2 '["ObjectViewer", "ObjectEraser"]'
----
* *remove* all user's rights to the folder.
Example:
----
sogo-tool manage-acl remove sogo-tests1 Contacts/5E1D-653FC400-1-1A330C40 sogo-tests2
----
* *subscribe* the user to the folder.
Example:
----
sogo-tool manage-acl subscribe sogo-tests1 Contacts/5E1D-653FC400-1-1A330C40 sogo-tests2
----
* *unsubscribe* the user to the folder.
Example:
----
sogo-tool manage-acl unsubscribe sogo-tests1 Contacts/5E1D-653FC400-1-1A330C40 sogo-tests2
----
sogo-tool manage-eas
~~~~~~~~~~~~~~~~~~~~
Manage EAS folders
sogo-tool manage-eas listdevices|listfolders|resetdevice|resetfolder|mergevcard|mergevevent user <deviceId | folderId> <YES | NO>
* First argument is the action among *listdevices*, *listfolders*, *resetdevice*, *resetfolder*, *mergevcard* and *mergevevent*.
* Second argument is the *user* whom to perform the action.
* Third argument is the *deviceId* of, if the action is *resetFolder*, the *folderId*. No need of this argument if the action is *listdevices*
* Fourth argument, only use with *mergevcard* and *mergevevent* is either YES to merge and *NO* to un-merge.
The actions:
* *listdevices*: list the devices belonging to user.
* *listfolders*: list all folders of deviceId for user.
* *resetdevice*: force deviceId of user to resync everything.
* *resetfolder*: force folderId of user to resync everything.
* *mergevcard*: merge/un-merge all addressbooks into one for deviceId of user.
* *mergevevent*: merge/un-merge all calendars into one for deviceId of user.
Examples:
----
sogo-tool manage-eas listdevices janedoe
sogo-tool manage-eas listfolders janedoe androidc316986417
sogo-tool manage-eas resetdevice janedoe androidc316986417
sogo-tool manage-eas resetfolder janedow androidc316986417 folderlala-dada-sasa_7a13_1a2386e0_e
sogo-tool manage-eas mergevcard janedow androidc316986417 YES
sogo-tool manage-eas mergevevent janedow androidc316986417 YES
----
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.
sogo-tool remove user1 [user2]
* Arguments one user or several space-separated.
* You can add -v after sogo*tool to list all removed folders
Example:
----
sogo-tool remove user1
sogo-tool -v remove user2
----
Output example with -v options:
----
Deleting /Users/user2/Calendar/B088-65363400-3-2B9DF0C0
Deleting /Users/user2/Calendar/personal
Deleting /Users/user2/Contacts/B087-65363380-5-374DA380
Deleting /Users/user2/Contacts/B087-65363400-7-374DA380
Deleting /Users/user2/Contacts/personal
----
sogo-tool remove-doubles
~~~~~~~~~~~~~~~~~~~~~~~~
remove duplicate contacts from the specified user addressbook
sogo-tool remove-doubles USER FOLDER
* *USER* is the name of the user to perform the removal
* *FOLDER* is the name of the folder to clean from duplicates
Two contacts are considered duplicates when they have the same mails or display name. When two or more contacts
are duplicates, each one will get a score. The ones with the highest score will be kept and the others
will be discarded. If two records have the same score, the first one to have reach it will be kept.
The scores are distributed as such:
* Record which has been the last modified: +1
* Record has the most content: +2
* Record has the most quick field set: +3
* Record is in a contact list: +6
Example:
----
sogo-tool remove-doubles user1 personal
sogo-tool remove-doubles user2 489-65376E80-1-2D2BA000
----
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.
sogo-tool rename-user fromuserid touserid
* *fromuserid* Previous user id
* *touserid* New user id
If the new user id already exist, the command will output a message and do nothing.
**WARNING** This command only change database of sogo, if you use ldap or others databases they will still keep the old id.
Example:
----
sogo-tool rename-user old_username new_username
----
sogo-tool truncate-calendar
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Remove old calendar entries from the specified user calendar.
sogo-tool truncate-calendar [-r] USER FOLDER DATE
* *-r* optional, to also delete recurrent events that have occurrence after *DATE*
* *USER* is the name of the owner of the calendar
* *FOLDER* is the name of the calendar folder to clean up
* *DATE* UTC datetime, event older than this date will be removed
Without *-r*, only reccurrent events which all occurrences are older than *DATE* will be removed.
With *-r*, event the if there are occurrences after *DATE*, the recurrent event will be removed.
*DATE* can take the value `date +%FT%T` which is the current time
Example:
----
sogo-tool truncate-calendar sogo-tests1 personal 2023-10-25T00:00:00
sogo-tool truncate-calendar -r sogo-tests2 5E38-6538BE80-5-AFF8310 2022-01-01T15:30:00
sogo-tool truncate-calendar -r sogo-tests2 personal `date +%FT%T` #will delete all event older than now
----
Result:
----
No record to remove. All records kept.
----
----
Removing 1 records...
Removed 1 records.
----
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,
the starting and ending date, the body and others parameters. If needed, the command
will write the sieve script accordingly.
sogo-tool update-autoreply -p credentialFile
* *-p- The credential file, a simple one-line file that contains "username:password" of an admin account of your imap/sieve server.
Example:
----
sogo-tool update-autoreply -p /var/sogo/cred
----
sogo-tool user-preferences
~~~~~~~~~~~~~~~~~~~~~~~~~~
Get, set or unset user defaults / settings in the database.
_Settings_ stores parameters for user's calendar, mail and contacts. It can be graphic
as month view or week view for calendar but it also stores subscription, delegation...
It also stores the private Salt for TOTP and the parameter ForceResetPassword to force the
user to change password.
_Defaults_ stores all parameters that can be found in Preferences panel. So it goes from default language to
autoreply to many others options.
user-preferences get|set|unset defaults|settings user key [value|-f filename] [-p credentialFile]
* First argument is the action *get*, *set* or *unset*
* Second argument is parameter type *settings* or *defaults*
* Third argument *user* is the name of the user where to make the action
* Fourth argument *key* is the name of the parameters where to make the action
* If the action is *set*, you should provide either *value* as fifth argument or a file with the value inside with *-f* filename/path
* If the action is *set* or *unset* and the *key* concerns a sieve script (filter, vacation, forward...), you
should provide a credential file, a one-line file that contains "username:password" of an admin account of your imap/sieve server.
As there is a lot of parameters, this documentation will not go into details for each one. To know what are
the key names and their value you should got to your database in table defined by _SOGoProfileURL_ in your sogo.conf.
Here, for each row (user) you will find c_defaults and c_settings which are json with the keys. However, if
a parameter has never been set, it won't appears in those json. The clean way to know the missing keys is to
set it up in one of your dummy/dev/test account then see the values in _SOGoProfileURL_. Be careful, a value
can be a json itself, only the primary key can be get/set/unset.
Example with forwarding, *get* action:
----
sogo-tool user-preferences get defaults user1 Forward
----
If forward has never been set the result will be:
----
Value for key "Forward" not found in defaults
----
Else it will be
----
{"forwardAddress":["sogo-tests2@sogo.alinto"],"enabled":1,"keepCopy":1}
----
*unset* action:
----
sogo-tool user-preferences unset defaults user1 Forward -p /etc/sogo/cred
----
*set* action:
----
sogo-tool user-preferences set defaults user1 Forward '{"forwardAddress":["sogo-tests2@sogo.alinto"],"enabled":1,"keepCopy":0}' -p cred
----
or create a json file which contains _{"forwardAddress":["sogo-tests2@sogo.alinto"],"enabled":1,"keepCopy":0}_ then:
----
sogo-tool user-preferences set defaults user1 Forward -f /path/filename -p cred
----
Upgrading
---------
@@ -22,7 +22,7 @@ devices (iPhone, iPod touch, and iPad).
The instructions are based on version {release_version} of SOGo.
The latest version of this guide is available at
https://sogo.nu/downloads/documentation.html.
https://www.sogo.nu/support.html#/documentation.
Introduction
------------
@@ -22,7 +22,7 @@ Guide_ for more information on installing and configuring SOGo.
The instructions are based on version {release_version} of SOGo.
The latest version of this guide is available
at https://sogo.nu/downloads/documentation.html.
at https://www.sogo.nu/support.html#/documentation.
Introduction
------------
+11 -4
View File
@@ -349,8 +349,11 @@ static BOOL debugLeaks;
{
if ([[context request] handledByDefaultHandler])
authenticator = [SOGoWebAuthenticator sharedSOGoWebAuthenticator];
else
else {
authenticator = [SOGoDAVAuthenticator sharedSOGoDAVAuthenticator];
[authenticator setContext: context];
}
}
return authenticator;
@@ -363,10 +366,14 @@ static BOOL debugLeaks;
{
SOGoUser *user;
id userFolder;
user = [SOGoUser userWithLogin: _key roles: nil];
NSData *decodedLogin;
NSString *login;
login = [SOGoUser getDecryptedUsernameIfNeeded: _key withContext: _ctx];
user = [SOGoUser userWithLogin: login roles: nil];
if (user)
userFolder = [$(@"SOGoUserFolder") objectWithName: _key
userFolder = [$(@"SOGoUserFolder") objectWithName: login
inContainer: self];
else
userFolder = nil;
+6
View File
@@ -72,8 +72,14 @@
- (void) setEndDate: (NSCalendarDate *) newEndDate
{
CardElement *c;
[(iCalDateTime *) [self uniqueChildWithTag: @"dtend"]
setDateTime: newEndDate];
c = [self uniqueChildWithTag: @"duration"];
if (c)
[self removeChild: c];
}
- (NSCalendarDate *) endDate
+25 -11
View File
@@ -44,10 +44,11 @@
{
NSMutableArray *ranges;
NSArray *byMonth;
NSCalendarDate *firStart, *lastDate, *rStart, *rEnd, *until, *referenceDate;
NSCalendarDate *firStart, *lastDate, *rStart, *rEnd, *until, *referenceDate, *rTemp;
NSInteger *hoursOfOffset;
iCalMonthlyRecurrenceCalculator *monthlyCalc;
unsigned j, yearIdxInRange, numberOfYearsInRange, count, interval, monthDiff;
int diff, repeatCount, currentMonth;
int diff, repeatCount, currentMonth, origNbDaysInMonth;
firStart = [firstRange startDate];
rStart = [_r startDate];
@@ -186,18 +187,31 @@
days: 0];
//Due to the bug with dateByAddingYears, we have to take off one day (see line 133)
rStart = [NSCalendarDate dateWithYear: [rStart yearOfCommonEra]
month: [rStart monthOfYear]
day: 0
hour: [rStart hourOfDay]
minute: [rStart minuteOfHour]
second: 0
timeZone: [rStart timeZone]];
//Due to the bug with dateByAddingYears, we may take the previous day (see line 133)
hoursOfOffset = [rStart hourOfDay];
origNbDaysInMonth = [rStart numberOfDaysInMonth];
if(hoursOfOffset > 12) {
//If rStart is 1st 22:00, we should start at the previous day 22:00
rTemp = [NSCalendarDate dateWithYear: [rStart yearOfCommonEra]
month: 1+([rStart monthOfYear]-2)%12
day: 1
hour: [rStart hourOfDay]
minute: [rStart minuteOfHour]
second: 0
timeZone: [rStart timeZone]];
rStart = [NSCalendarDate dateWithYear: [rStart yearOfCommonEra]
month: 1+([rStart monthOfYear]-2)%12
day: [rTemp numberOfDaysInMonth]
hour: [rStart hourOfDay]
minute: [rStart minuteOfHour]
second: 0
timeZone: [rStart timeZone]];
}
rEnd = [rStart dateByAddingYears: 0
months: 0
days: [rStart numberOfDaysInMonth]];
days: origNbDaysInMonth];
rangeForMonth = [NGCalendarDateRange calendarDateRangeWithStartDate: rStart
+1 -1
View File
@@ -141,7 +141,7 @@ CREATE TABLE sogo_quick_contact (
CREATE TABLE sogo_sessions_folder (
c_id varchar(255) NOT NULL,
c_value varchar(255) NOT NULL,
c_value varchar(4096) NOT NULL,
c_creationdate int(11) NOT NULL,
c_lastseen int(11) NOT NULL,
PRIMARY KEY (c_id)
@@ -53,7 +53,7 @@ vtodo_class2 = "(Vertrauliche Aufgabe)";
"The following parameters have changed in the \"%{Summary}\" meeting:"
= "Folgendes wurde am Termin \"%{Summary}\" geändert:";
"Please accept or decline those changes."
= "Bitte akzeptieren Sie diese Änderung, oder lehnen Sie diese ab.";
= "Bitte akzeptieren Sie diese Änderungen, oder lehnen Sie diese ab.";
/* Reply */
"Accepted invitation: \"%{Summary}\"" = "Einladung zugestimmt: \"%{Summary}\"";
@@ -12,9 +12,9 @@ vtodo_class2 = "(Konfidenciali užduotis)";
"The event \"%{Summary}\" was created" = "Įvykis \"%{summary}\" buvo sukurtas";
"The event \"%{Summary}\" was deleted" = "Įvykis \"%{Summary}\" buvo ištrintas";
"The event \"%{Summary}\" was updated" = "Įvykis \"%{Summary}\" buvo atnaujintas";
"The task \"%{Summary}\" was created" = "Įvykis \\"%{summary}\\" buvo sukurtas";
"The task \"%{Summary}\" was deleted" = "Įvykis \\"%{Summary}\\" buvo ištrintas";
"The task \"%{Summary}\" was updated" = "Įvykis \\"%{Summary}\\" buvo atnaujintas";
"The task \"%{Summary}\" was created" = "Įvykis \"%{summary}\" buvo sukurtas";
"The task \"%{Summary}\" was deleted" = "Įvykis \"%{Summary}\" buvo ištrintas";
"The task \"%{Summary}\" was updated" = "Įvykis \"%{Summary}\" buvo atnaujintas";
"The following attendees(s) were notified" = "Šiems dalyviui(iams) buvo pranešta";
"The following attendees(s) were added" = "Šie dalyvis(iai) buvo pridėti";
"The following attendees(s) were removed" = "Šie dalyvis(iai) buvo pašalinti";
@@ -33,13 +33,13 @@ vtodo_class2 = "(Konfidenciali užduotis)";
"attendee_label" = "Dalyvis";
/* Invitation */
"Event Invitation: \"%{Summary}\"" = "Įvykio pakvietimas: \"%{Summary}\"";
"(sent by %{SentBy}) " = "(išsiųsta nuo %{SentBy}) ";
"Event Invitation: \"%{Summary}\"" = "Kvietimas į renginį: \"%{Summary}\"";
"(sent by %{SentBy}) " = "(išsiųsta %{SentBy}) ";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText} pakvietė Jus į %{Summary}.\nPradžia: %{StartDate}\nPabaiga: %{EndDate}\nAprašymas: %{Description}";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText} pakvietė Jus į %{Summary}.\n\nPradžia: %{StartDate} nuo %{StartTime}\nPabaiga: %{EndDate} nuo %{EndTime}\nAprašymas: %{Description}";
/* Deletion */
"Event Cancelled: \"%{Summary}\"" = "Įvykis atšauktas: \\"%{Summary}\\"";
"Event Cancelled: \"%{Summary}\"" = "Įvykis atšauktas: \"%{Summary}\"";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
= "%{Organizer} %{SentByText} atšaukė šį įvykį: %{Summary}.\n\nPradžia: %{StartDate}\nPabaiga: %{EndDate}\nAprašymas: %{Description}";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
@@ -63,11 +63,11 @@ vtodo_class2 = "(Konfidenciali užduotis)";
"%{Attendee} %{SentByText}has accepted your event invitation."
= "%{Attendee} %{SentByText} priėmė Jūsų įvykio pakvietimą.";
"%{Attendee} %{SentByText}has declined your event invitation."
= "%{Attendee} %{SentByText} atmetė Jūsų įvykio pakvietimą.";
= "%{Attendee} %{SentByText} atmetė Jūsų pakvietimą į renginį.";
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
= "%{Attendee} %{SentByText} delegavo pakvietimą į %{Delegate}.";
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
= "%{Attendee} %{SentByText} neapsisprendė dėl Jūsų įvykio pakvietimo.";
= "%{Attendee} %{SentByText} neapsisprendė dėl Jūsų kvietimo į renginį.";
/* Reminder */
"Reminder: \"%{Summary}\" - %{StartDate}" = "Priminimas: \"%{Summary}\" - %{StartDate}";
@@ -88,7 +88,7 @@
}
tag = [NSArray arrayWithObjects: @"href", XMLNS_WEBDAV, @"D",
[NSString stringWithFormat: @"/SOGo/dav/%@/", nameInContainer],
[NSString stringWithFormat: @"/SOGo/dav/%@/", [self nameInContainer]],
nil];
[addresses addObjectUniquely: tag];
@@ -128,7 +128,7 @@
}
tag = [NSArray arrayWithObjects: @"href", XMLNS_WEBDAV, @"D",
[NSString stringWithFormat: @"/SOGo/dav/%@/", nameInContainer],
[NSString stringWithFormat: @"/SOGo/dav/%@/", [self nameInContainer]],
nil];
[addresses addObjectUniquely: tag];
@@ -1,2 +1,2 @@
"Personal Address Book" = "Asmeninė adresų knyga";
"Collected Address Book" = "Rinktinė adresų knyga";
"Collected Address Book" = "Rinktinė adresų knygą";
+1 -1
View File
@@ -418,7 +418,7 @@ convention:
[self setCategories: [o componentsSeparatedByString: @","]];
// Photo
if ([ldifRecord objectForKey: @"photo"])
if ([ldifRecord objectForKey: @"photo"] && [ldifRecord objectForKey: @"photo"] != [NSNull null])
[self setPhoto: [[ldifRecord objectForKey: @"photo"] stringByEncodingBase64]];
[self cleanupEmptyChildren];
@@ -271,6 +271,9 @@ static NSArray *folderListingFields = nil;
if ([data length])
[contactRecord setObject: data forKey: @"id"];
// Container name
[contactRecord setObject: [self displayName] forKey: @"containerName"];
// c_cn
data = [contactRecord objectForKey: @"c_cn"];
if (![data length])
+38 -14
View File
@@ -239,6 +239,13 @@
[newRecord setObject: [oldRecord objectForKey: @"c_uid"]
forKey: @"c_uid"];
//source id
[newRecord setObject: [source sourceID] forKey: @"sourceID"];
//source display name
[newRecord setObject: [self displayName]
forKey: @"containerName"];
// c_name => id
[newRecord setObject: [oldRecord objectForKey: @"c_name"]
forKey: @"c_name"];
@@ -427,26 +434,43 @@
{
NSArray *records, *result;
EOSortOrdering *ordering;
BOOL processed;
result = nil;
processed = NO;
if ([filter length] > 0 || ![source listRequiresDot])
[source setListRequiresDot: NO];
if ( ![source listRequiresDot])
{
records = [source fetchContactsMatching: filter
if ([filter length] > 0) {
records = [source fetchContactsMatching: filter
withCriteria: criteria
inDomain: domain];
[childRecords setObjects: records
forKeys: [records objectsForKey: @"c_name"
notFoundMarker: nil]];
records = [self _flattenedRecords: records];
ordering
= [EOSortOrdering sortOrderingWithKey: sortKey
selector: ((sortOrdering == NSOrderedDescending)
? EOCompareCaseInsensitiveDescending
: EOCompareCaseInsensitiveAscending)];
result
= [records sortedArrayUsingKeyOrderArray:
[NSArray arrayWithObject: ordering]];
processed = YES;
} else if ([[SOGoSystemDefaults sharedSystemDefaults] globalAddressBookFirstEntriesEnabled]) {
records = [source fetchContactsMatching: filter
withCriteria: criteria
inDomain: domain
limit: [[SOGoSystemDefaults sharedSystemDefaults] globalAddressBookFirstEntriesCount]];
processed = YES;
}
if (processed) {
[childRecords setObjects: records
forKeys: [records objectsForKey: @"c_name"
notFoundMarker: nil]];
records = [self _flattenedRecords: records];
ordering
= [EOSortOrdering sortOrderingWithKey: sortKey
selector: ((sortOrdering == NSOrderedDescending)
? EOCompareCaseInsensitiveDescending
: EOCompareCaseInsensitiveAscending)];
result
= [records sortedArrayUsingKeyOrderArray:
[NSArray arrayWithObject: ordering]];
}
}
return result;
+6 -1
View File
@@ -56,6 +56,7 @@
int sourceIMAP4ID;
NSMutableDictionary *headers;
NSString *inReplyTo;
NSString *references;
NSString *text;
NSString *sourceURL;
NSString *sourceFlag;
@@ -63,6 +64,7 @@
BOOL isHTML;
BOOL sign;
BOOL encrypt;
NSMutableArray *tmpFiles;
// Used during S/MIME encryption
NSMutableDictionary *certificates;
@@ -95,6 +97,9 @@
- (NSString *) inReplyTo;
- (void) setInReplyTo: (NSString *) newInReplyTo;
- (NSString *) references;
- (void) setReferences: (NSString *) newReferences;
- (void) setSourceURL: (NSString *) newSurceURL;
- (void) setSourceFlag: (NSString *) newSourceFlag;
- (void) setSourceFolder: (NSString *) newSourceFolder;
@@ -117,7 +122,7 @@
/* NGMime representations */
- (NSData *) mimeMessageForRecipient: (NSString *) theRecipient;
- (NSData *)mimeMessageForRecipient:(NSString *)theRecipient extractingImages:(BOOL)extractImage;
/* operations */
- (NSArray *) allRecipients;
+90 -60
View File
@@ -67,6 +67,7 @@
#import <SOGo/SOGoUserFolder.h>
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <SOGo/NGMimeFileData+SOGo.h>
#import <NGCards/NGVCard.h>
@@ -138,9 +139,11 @@ static NSString *userAgent = nil;
sourceURL = nil;
sourceFlag = nil;
inReplyTo = nil;
references = nil;
isHTML = NO;
sign = NO;
encrypt = NO;
tmpFiles = [[NSMutableArray alloc] init];
}
return self;
@@ -155,6 +158,8 @@ static NSString *userAgent = nil;
[sourceURL release];
[sourceFlag release];
[inReplyTo release];
[references release];
[tmpFiles release];
[super dealloc];
}
@@ -361,6 +366,16 @@ static NSString *userAgent = nil;
ASSIGN (inReplyTo, newInReplyTo);
}
- (NSString *) references
{
return references;
}
- (void) setReferences: (NSString *) newReferences
{
ASSIGN (references, newReferences);
}
- (void) setSourceURL: (NSString *) newSourceURL
{
ASSIGN (sourceURL, newSourceURL);
@@ -421,6 +436,8 @@ static NSString *userAgent = nil;
forKey: @"isHTML"];
if (inReplyTo)
[infos setObject: inReplyTo forKey: @"inReplyTo"];
if (references)
[infos setObject: references forKey: @"references"];
if (sourceIMAP4ID > -1)
[infos setObject: [NSString stringWithFormat: @"%i", sourceIMAP4ID]
forKey: @"sourceIMAP4ID"];
@@ -492,6 +509,10 @@ static NSString *userAgent = nil;
value = [infoDict objectForKey: @"inReplyTo"];
if (value)
[self setInReplyTo: value];
value = [infoDict objectForKey: @"references"];
if (value)
[self setReferences: value];
}
//
@@ -570,7 +591,7 @@ static NSString *userAgent = nil;
id result;
error = nil;
message = [self mimeMessageForRecipient: nil];
message = [self mimeMessageForRecipient: nil extractingImages: NO];
if (!message)
{
@@ -914,7 +935,6 @@ static NSString *userAgent = nil;
if (filename)
{
NSMutableDictionary *currentInfo;
currentInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
filename, @"filename",
mimeType, @"mimetype",
@@ -1041,6 +1061,7 @@ static NSString *userAgent = nil;
{
BOOL fromSentMailbox;
NSString *msgID;
NSString *oldReferences;
NSMutableDictionary *info;
NGImap4Envelope *sourceEnvelope;
SOGoUserDefaults *ud;
@@ -1059,6 +1080,13 @@ static NSString *userAgent = nil;
msgID = [sourceEnvelope messageID];
if ([msgID length] > 0)
[self setInReplyTo: msgID];
oldReferences = [sourceMail references];
if ([oldReferences length] > 0)
[self setReferences: [oldReferences stringByAppendingFormat: @" %@", msgID]];
else
[self setReferences: msgID];
ud = [[context activeUser] userDefaults];
@@ -1832,6 +1860,9 @@ static NSString *userAgent = nil;
if (inReplyTo)
[map setObject: inReplyTo forKey: @"in-reply-to"];
if (references)
[map setObject: references forKey: @"references"];
/* add subject */
if ([(s = [headers objectForKey: @"subject"]) length] > 0)
[map setObject: [s asQPSubjectString: @"utf-8"]
@@ -1893,8 +1924,10 @@ static NSString *userAgent = nil;
if (_extractImages)
{
newText = [text htmlByExtractingImages: extractedBodyParts];
if ([extractedBodyParts count])
if ([extractedBodyParts count]) {
[self setText: newText];
[self addTmpFiles: extractedBodyParts];
}
}
@@ -1906,8 +1939,11 @@ static NSString *userAgent = nil;
//[self debugWithFormat: @"MIME Envelope: %@", map];
allBodyParts = [self bodyPartsForAllAttachments];
if (!allBodyParts)
return nil;
if (!allBodyParts) {
return nil;
} else {
[self addTmpFiles: allBodyParts];
}
//[self debugWithFormat: @"attachments: %@", bodyParts];
@@ -1926,58 +1962,13 @@ static NSString *userAgent = nil;
}
}
if (_extractImages)
{
int i;
for (i = 0 ; i < [extractedBodyParts count] ; i++) {
NSMutableDictionary *currentInfo;
NSString *filename, *mimeType, *bodyId, *encoding;
NSData *body;
NGMimeBodyPart *extractedBodyPart;
NGMimeContentDispositionHeaderField *contentDisposition;
extractedBodyPart = [extractedBodyParts objectAtIndex:i];
if (extractedBodyPart && [extractedBodyPart headerForKey: @"content-disposition"]) {
encoding = [extractedBodyPart encoding];
contentDisposition = [[NGMimeContentDispositionHeaderField alloc] initWithString: [extractedBodyPart headerForKey: @"content-disposition"]];
if (encoding
&& [extractedBodyPart contentType]
&& [extractedBodyPart contentId]
&& [contentDisposition filename]) {
mimeType = [[extractedBodyPart contentType] stringValue];
bodyId = [[extractedBodyPart contentId] stringValue];
filename = [contentDisposition filename];
currentInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
filename, @"filename",
mimeType, @"mimetype",
bodyId, @"bodyId",
nil];
if ([[extractedBodyParts objectAtIndex:i] body]) {
if (encoding && [encoding rangeOfString:@"base64"].location != NSNotFound)
body = [[[extractedBodyParts objectAtIndex:i] body] dataByDecodingBase64];
else
body = [[extractedBodyParts objectAtIndex:i] body];
[self saveAttachment: body
withMetadata: currentInfo];
}
}
[contentDisposition release];
}
}
}
return message;
}
}
//
// Return a NGMimeMessage object with inline HTML images (<img src=data>) extracted as attachments (<img src=cid>).
//
- (NSData *) mimeMessageForRecipient: (NSString *) theRecipient
- (NSData *) mimeMessageForRecipient: (NSString *) theRecipient extractingImages: (BOOL)extractImage
{
NGMimeMessageGenerator *generator, *partGenerator;
NGMimeMessage *mimeMessage;
@@ -1990,7 +1981,7 @@ static NSString *userAgent = nil;
// Nothing to sign or encrypt, let's generate the message and return immediately
if (![self sign] && ![self encrypt])
{
mimeMessage = [self mimeMessageWithHeaders: nil excluding: nil extractingImages: YES bodyOnly: NO];
mimeMessage = [self mimeMessageWithHeaders: nil excluding: nil extractingImages: extractImage bodyOnly: NO];
if (mimeMessage)
{
generator = [[[NGMimeMessageGenerator alloc] init] autorelease];
@@ -2004,7 +1995,7 @@ static NSString *userAgent = nil;
partGenerator = [[[NGMimePartGenerator alloc] init] autorelease];
content = [partGenerator generateMimeFromPart: [self mimeMessageWithHeaders: nil
excluding: nil
extractingImages: YES
extractingImages: extractImage
bodyOnly: YES]];
if ([self sign])
@@ -2242,6 +2233,41 @@ static NSString *userAgent = nil;
return [self sendMailAndCopyToSent: YES];
}
// Extract tmp files in NGMimeBuildMimeTempDirectory from NSArray and store locally
// The tmp files will be deleted once the message sent
- (void) addTmpFiles:(NSArray *) parts {
NGMimeBodyPart *part;
for (part in parts) {
NGMimeFileData *body;
NSString *path;
body = [part body];
if (body && [body isKindOfClass: [NGMimeFileData class]]) {
path = [body path];
if (path) {
[tmpFiles addObject: path];
}
}
}
}
// Clean temporary files
- (void) cleanTmpFiles {
NSString *path;
NSFileManager *fm;
fm = [NSFileManager defaultManager];
for (path in tmpFiles) {
if ([fm fileExistsAtPath: path])
[fm removeFileAtPath: path handler: nil];
}
// Clean tmp files
[tmpFiles removeAllObjects];
}
//
//
//
@@ -2271,9 +2297,9 @@ static NSString *userAgent = nil;
recipient = [recipients objectAtIndex: i];
if ([[context activeUser] hasEmail: recipient])
message = messageForSent = [self mimeMessageForRecipient: nil];
message = messageForSent = [self mimeMessageForRecipient: nil extractingImages: YES];
else
message = [self mimeMessageForRecipient: recipient];
message = [self mimeMessageForRecipient: recipient extractingImages: YES];
if (!message)
return [NSException exceptionWithHTTPStatus: 500
@@ -2287,19 +2313,21 @@ static NSString *userAgent = nil;
inContext: context
systemMessage: NO];
if (error)
if (error) {
[self cleanTmpFiles];
return error;
}
}
// If the current user isn't part of the recipient list for encrypted emails
// let's generate a crypted email for its sent folder.
if (!messageForSent)
messageForSent = [self mimeMessageForRecipient: nil];
messageForSent = [self mimeMessageForRecipient: nil extractingImages: YES];
}
else
{
// Encryption is done or not, if we didn't have to.
message = messageForSent = [self mimeMessageForRecipient: nil];
message = messageForSent = [self mimeMessageForRecipient: nil extractingImages: YES];
if (!message)
return [NSException exceptionWithHTTPStatus: 500
@@ -2347,6 +2375,8 @@ static NSString *userAgent = nil;
[imap4 doesMailboxExistAtURL: [container imap4URL]])
[(SOGoDraftsFolder *) container expunge];
[self cleanTmpFiles];
return error;
}
@@ -2372,7 +2402,7 @@ static NSString *userAgent = nil;
NSString *str;
NSData *message;
message = [self mimeMessageForRecipient: nil];
message = [self mimeMessageForRecipient: nil extractingImages: NO];
if (message)
{
str = [[NSString alloc] initWithData: message
+1
View File
@@ -97,6 +97,7 @@ extern NSArray *SOGoMailCoreInfoKeys;
- (NSString *) cc;
- (NSString *) from;
- (NSString *) inReplyTo;
- (NSString *) references;
- (NSString *) messageId;
- (NSString *) received;
+8 -2
View File
@@ -93,7 +93,10 @@ SOGo_HEADER_FILES = \
\
JWT.h \
\
NGMimeBodyPart+SOGo.h
NGMimeBodyPart+SOGo.h \
NGMimeFileData+SOGo.h \
\
SOGoMobileProvision.h
all::
@touch SOGoBuild.m
@@ -180,7 +183,10 @@ SOGo_OBJC_FILES = \
\
JWT.m \
\
NGMimeBodyPart+SOGo.m
NGMimeBodyPart+SOGo.m \
NGMimeFileData+SOGo.m \
\
SOGoMobileProvision.m
SOGo_C_FILES += lmhash.c aes.c crypt_blowfish.c pkcs5_pbkdf2.c
+59 -12
View File
@@ -1384,6 +1384,21 @@ groupObjectClasses: (NSArray *) newGroupObjectClasses
- (NSArray *) fetchContactsMatching: (NSString *) match
withCriteria: (NSArray *) criteria
inDomain: (NSString *) theDomain
{
if ([match length] > 0) {
return [self fetchContactsMatching: (NSString *) match
withCriteria: (NSArray *) criteria
inDomain: (NSString *) theDomain
limit: -1];
} else {
return [NSMutableArray array];
}
}
- (NSArray *) fetchContactsMatching: (NSString *) match
withCriteria: (NSArray *) criteria
inDomain: (NSString *) theDomain
limit: (int) limit
{
NSAutoreleasePool *pool;
NGLdapConnection *ldapConnection;
@@ -1392,6 +1407,8 @@ groupObjectClasses: (NSArray *) newGroupObjectClasses
NSMutableArray *contacts;
EOQualifier *qualifier;
unsigned int i;
NSString *sortAttribute;
BOOL sortReverse;
contacts = [NSMutableArray array];
@@ -1400,18 +1417,48 @@ groupObjectClasses: (NSArray *) newGroupObjectClasses
ldapConnection = [self _ldapConnection];
qualifier = [self _qualifierForFilter: match onCriteria: criteria];
if ([_scope caseInsensitiveCompare: @"BASE"] == NSOrderedSame)
entries = [ldapConnection baseSearchAtBaseDN: _baseDN
qualifier: qualifier
attributes: _lookupFields];
else if ([_scope caseInsensitiveCompare: @"ONE"] == NSOrderedSame)
entries = [ldapConnection flatSearchAtBaseDN: _baseDN
qualifier: qualifier
attributes: _lookupFields];
else /* we do it like before */
entries = [ldapConnection deepSearchAtBaseDN: _baseDN
qualifier: qualifier
attributes: _lookupFields];
if (limit > 0) {
[ldapConnection setQuerySizeLimit: limit];
}
if (limit > 0) {
// Sort results
sortAttribute = @"cn";
sortReverse = NO;
if ([_scope caseInsensitiveCompare: @"BASE"] == NSOrderedSame)
entries = [ldapConnection baseSearchAtBaseDN: _baseDN
qualifier: qualifier
attributes: _lookupFields
sortAttribute: sortAttribute
sortReverse: sortReverse];
else if ([_scope caseInsensitiveCompare: @"ONE"] == NSOrderedSame)
entries = [ldapConnection flatSearchAtBaseDN: _baseDN
qualifier: qualifier
attributes: _lookupFields
sortAttribute: sortAttribute
sortReverse: sortReverse];
else /* we do it like before */
entries = [ldapConnection deepSearchAtBaseDN: _baseDN
qualifier: qualifier
attributes: _lookupFields
sortAttribute: sortAttribute
sortReverse: sortReverse];
} else {
// No sort results
if ([_scope caseInsensitiveCompare: @"BASE"] == NSOrderedSame)
entries = [ldapConnection baseSearchAtBaseDN: _baseDN
qualifier: qualifier
attributes: _lookupFields];
else if ([_scope caseInsensitiveCompare: @"ONE"] == NSOrderedSame)
entries = [ldapConnection flatSearchAtBaseDN: _baseDN
qualifier: qualifier
attributes: _lookupFields];
else /* we do it like before */
entries = [ldapConnection deepSearchAtBaseDN: _baseDN
qualifier: qualifier
attributes: _lookupFields];
}
i = 0;
pool = [NSAutoreleasePool new];
+34
View File
@@ -0,0 +1,34 @@
/* NGMimeFileData+SOGo.h - this file is part of SOGo
*
* Copyright (C) 2023 Alinto
*
* Author: Sébastien Mizrahi <smizrahi@alinto.eu>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef NGMIMEFILEDATA_SOGO_H
#define NGMIMEFILEDATA_SOGO_H
#import <NGMime/NGMimeFileData.h>
@interface NGMimeFileData (SOGoExtensions)
- (NSString *) path;
@end
#endif /* NGMIMEFILEDATA_SOGO_H */
+32
View File
@@ -0,0 +1,32 @@
/* NGMimeFileData+SOGo.m - this file is part of SOGo
*
* Copyright (C) 2023 Alinto
*
* Author: Sébastien Mizrahi <smizrahi@alinto.eu>
*
* 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 "NGMimeFileData+SOGo.h"
@implementation NGMimeFileData (SOGoExtensions)
- (NSString *) path {
return path;
}
@end
+7 -1
View File
@@ -26,6 +26,7 @@
#define NSSTRING_CRYPTO_H
#import <Foundation/NSString.h>
#import <Foundation/Foundation.h>
typedef enum {
encDefault, //!< default encoding, let the algorithm decide
@@ -35,8 +36,10 @@ typedef enum {
} keyEncoding;
@class NSObject;
@class NSScanner;
@interface NSString (SOGoCryptoExtension)
@interface
NSString(SOGoCryptoExtension)
- (BOOL) isEqualToCrypted: (NSString *) cryptedPassword
withDefaultScheme: (NSString *) theScheme
@@ -62,6 +65,9 @@ typedef enum {
+ (NSArray *) getDefaultEncodingForScheme: (NSString *) passwordScheme;
- (NSString *) encodeAES128ECBBase64:(NSString *)passwordScheme encodedURL:(BOOL)encodedURL exception:(NSException **)ex;
- (NSString *) decodeAES128ECBBase64:(NSString *)passwordScheme encodedURL:(BOOL)encodedURL exception:(NSException **)ex;
@end
#endif /* NSSTRING_CRYPTO_H */
+136
View File
@@ -29,6 +29,11 @@
#import "NSData+Crypto.h"
#import <NGExtensions/NGBase64Coding.h>
#import "aes.h"
#define AES_SIZE 8096
#define AES_KEY_SIZE 16
static const NSString *kAES128ECError = @"kAES128ECError";
@implementation NSString (SOGoCryptoExtension)
@@ -349,4 +354,135 @@
return [[NSData encodeDataAsHexString: [d asLM]] uppercaseString];
}
/**
* Encrypts the data using AES 128 ECB mechanism
*
* @param passwordScheme The 128 bits password key
* @param encodedURL YES if the special base64 characters shall be escaped for URL
* @param ex Exception pointer
* @return If successful, encrypted string in base64
*/
- (NSString *) encodeAES128ECBBase64:(NSString *)passwordScheme encodedURL:(BOOL)encodedURL exception:(NSException **)ex
{
NSData *inputData, *keyData, *outputData;
if (AES_KEY_SIZE != [passwordScheme length]) {
*ex = [NSException exceptionWithName:kAES128ECError reason: [NSString stringWithFormat:@"Key must be %d bits", (AES_KEY_SIZE * 8)] userInfo: nil];
return nil;
}
NSString *value;
int size, i;
uint8_t output[AES_SIZE], input[AES_SIZE];
inputData = [self dataUsingEncoding: NSUnicodeStringEncoding];
keyData = [passwordScheme dataUsingEncoding: NSUnicodeStringEncoding];
size = [inputData length] + 16; // Add one unicode char size 16 bits (NUL)
if (inputData == nil) {
*ex = [NSException exceptionWithName:kAES128ECError reason: @"Invalid input data (encrypt)" userInfo: nil];
return nil;
}
if (((AES_SIZE / 2) - 16) < [self length]) {
*ex = [NSException exceptionWithName:kAES128ECError reason: [NSString stringWithFormat:@"Invalid size (encrypt). max size is %d. Current size : %d", ((AES_SIZE / 2) - 16), [self length]] userInfo: nil];
return nil;
}
memset(output, 0x00, AES_SIZE);
memset(input, 0x00, AES_SIZE);
[inputData getBytes: input length: [inputData length]];
input[[inputData length]] = '\0'; // Add NUL
for(i = 0 ; i < (AES_SIZE / 16) ; ++i)
{
AES128_ECB_encrypt(input + (i*16), [keyData bytes], output+(i*16));
}
outputData = [NSData dataWithBytes: (char *)output length: size];
if (outputData) {
value = [outputData base64EncodedStringWithOptions: 0];
if (encodedURL) {
value = [value stringByReplacingOccurrencesOfString: @"+" withString: @"."];
value = [value stringByReplacingOccurrencesOfString: @"/" withString: @"_"];
value = [value stringByReplacingOccurrencesOfString: @"=" withString: @"-"];
}
return value;
} else {
*ex = [NSException exceptionWithName:kAES128ECError reason:@"Empty data" userInfo: nil];
}
return nil;
}
/**
* Decrypts the base64 data using AES 128 ECB mechanism
*
* @param passwordScheme The 128 bits password key
* @param encodedURL YES if the special base64 characters has been escaped for URL
* @param ex Exception pointer
* @return If successful, decrypted string
*/
- (NSString *) decodeAES128ECBBase64:(NSString *)passwordScheme encodedURL:(BOOL)encodedURL exception:(NSException **)ex
{
NSData *inputData, *keyData, *outputData;
NSString *value, *inputString, *tmpStr;
int i;
uint8_t output[AES_SIZE];
if (AES_KEY_SIZE != [passwordScheme length]) {
*ex = [NSException exceptionWithName:kAES128ECError reason: [NSString stringWithFormat:@"Key must be %d bits", (AES_KEY_SIZE * 8)] userInfo: nil];
return nil;
}
value = nil;
keyData = [passwordScheme dataUsingEncoding: NSUnicodeStringEncoding];
memset(output, 0x00, AES_SIZE);
inputString = [NSString stringWithString: self];
if (encodedURL) {
inputString = [inputString stringByReplacingOccurrencesOfString: @"." withString: @"+"];
inputString = [inputString stringByReplacingOccurrencesOfString: @"_" withString: @"/"];
inputString = [inputString stringByReplacingOccurrencesOfString: @"-" withString: @"="];
}
inputData = [[NSData alloc] initWithBase64EncodedString:inputString options:0];
if (inputData == nil) {
*ex = [NSException exceptionWithName:kAES128ECError reason: @"Invalid input data (decrypt)" userInfo: nil];
return nil;
}
if ((AES_SIZE) < [inputData length]) {
*ex = [NSException exceptionWithName:kAES128ECError reason: [NSString stringWithFormat:@"Invalid size (decrypt). max size is %d. Current size : %d", AES_SIZE, [inputData length]] userInfo: nil];
return nil;
}
for(i = 0; i < (AES_SIZE / 16); ++i)
{
AES128_ECB_decrypt([inputData bytes] + (i*16), [keyData bytes], output + (i*16));
}
outputData = [NSData dataWithBytes: output length:([inputData length] - 16)];
if (outputData) {
tmpStr = [[NSString alloc] initWithData: outputData encoding: NSUnicodeStringEncoding];
if (tmpStr) {
value = [NSString stringWithUTF8String: [tmpStr UTF8String]];
} else {
*ex = [NSException exceptionWithName:kAES128ECError reason:@"Empty converted decrypted data" userInfo: nil];
value = nil;
}
[tmpStr release];
} else {
*ex = [NSException exceptionWithName:kAES128ECError reason:@"Empty data" userInfo: nil];
}
return value;
}
@end
+1
View File
@@ -65,6 +65,7 @@
- (id) objectFromJSONString;
/* bare email addresses */
- (NSString *) mailDomain;
- (NSString *) pureEMailAddress;
- (NSString *) asQPSubjectString: (NSString *) encoding;
+24
View File
@@ -609,6 +609,18 @@ static int cssEscapingCount;
return newString;
}
- (NSString *) mailDomain
{
NSArray *mailSeparated;
mailSeparated = [self componentsSeparatedByString: @"@"];
if([mailSeparated count] == 2)
return [mailSeparated objectAtIndex: 1];
[self logWithFormat: @"Error while extracting domain from : %@", self];
return nil;
}
- (NSString *) pureEMailAddress
{
NSString *pureAddress;
@@ -979,6 +991,18 @@ static int cssEscapingCount;
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"<ifr***"];
result = [NSString stringWithString: newResult];
// Remove <form
regex = [NSRegularExpression regularExpressionWithPattern:@"<[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*f[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*o[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*r[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*m"
options: NSRegularExpressionCaseInsensitive error:&error];
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"<for*"];
result = [NSString stringWithString: newResult];
// Remove </form
regex = [NSRegularExpression regularExpressionWithPattern:@"<[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*/[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*f[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*o[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*r[\\s\\u200B&#x09;&#x0A;&#x0D;\\\\0]*m"
options: NSRegularExpressionCaseInsensitive error:&error];
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"</for*"];
result = [NSString stringWithString: newResult];
// Remove onload
regex = [NSRegularExpression regularExpressionWithPattern:@"onload="
options: NSRegularExpressionCaseInsensitive error:&error];
+13 -2
View File
@@ -100,8 +100,19 @@
if (data) {
if ([data isKindOfClass: [NSString class]])
ASSIGN (content, data);
else
ASSIGN (content, [NSString stringWithUTF8String:[data bytes]]);
else {
char lastByte;
[data getBytes:&lastByte range:NSMakeRange([data length]-1, 1)];
if (lastByte == 0x0) {
// string is null terminated
ASSIGN (content, [NSString stringWithUTF8String: [data bytes]]);
} else {
// string is not null terminated
NSString* myString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
ASSIGN (content, myString);
[myString release];
}
}
}
data = [objectRecord objectForKey: @"c_version"];
if (data)
+2
View File
@@ -29,6 +29,8 @@
@interface SOGoDAVAuthenticator : SoHTTPAuthenticator <SOGoAuthenticator>
WOContext *context;
+ (id) sharedSOGoDAVAuthenticator;
@end
+12 -1
View File
@@ -41,12 +41,19 @@
{
static SOGoDAVAuthenticator *auth = nil;
if (!auth)
if (!auth) {
auth = [self new];
context = nil;
}
return auth;
}
- (void) setContext: (WOContext *) _context
{
context = _context;
}
- (BOOL) checkLogin: (NSString *) _login
password: (NSString *) _pwd
{
@@ -68,6 +75,10 @@
expire: &expire
grace: &grace]
&& perr == PolicyNoError);
if (context) {
[SOGoUser getEncryptedUsernameIfNeeded: [_login stringByReplacingString: @"%40"
withString: @"@"] withContext: context]; // Create cache entry
}
if (!rc)
{
sd = [SOGoSystemDefaults sharedSystemDefaults];
+2
View File
@@ -123,6 +123,8 @@
SOGoTemplatesFolderName = "Templates";
SOGoMailComposeMessageType = "html";
SOGoMailComposeFontSize = "0";
SOGoMailHideInlineAttachments = NO;
SOGoMailDisplayFullEmail = NO;
SOGoMailDisplayRemoteInlineImages = "never";
SOGoMailCertificateEnabled = YES;
+1 -1
View File
@@ -217,7 +217,7 @@
v = [self integerForKey: @"SOGoForwardConstraints"];
return (v > 2 ? 0 : v);
return (v > 3 ? 0 : v);
}
- (NSArray *) forwardConstraintsDomains
+5 -3
View File
@@ -533,7 +533,7 @@ static NSArray *childRecordFields = nil;
publicParticle = @"";
path = [NSString stringWithFormat: @"/%@/dav%@/%@/%@/%@/",
appName, publicParticle,
[[self ownerInContext: nil] stringByEscapingURL],
[[SOGoUser getEncryptedUsernameIfNeeded:[self ownerInContext: nil] withContext: context] stringByEscapingURL],
[[container nameInContainer] stringByEscapingURL],
[[self realNameInContainer] stringByEscapingURL]];
currentDavURL = [self davURL];
@@ -739,7 +739,8 @@ static NSArray *childRecordFields = nil;
qualifier = aclQualifier;
// For Thunderbird, disable contact list
if ([[context request] isThunderbird]) {
// This will be removed when VCARD will be implemented
if ([[context request] isThunderbird] && [self isKindOfClass: NSClassFromString(@"SOGoContactGCSFolder")]) {
vlistExclusionQualifier = [EOQualifier qualifierWithQualifierFormat: @"c_component != 'vlist'"];
qualifier = [[[EOAndQualifier alloc] initWithQualifiers:
vlistExclusionQualifier,
@@ -1191,7 +1192,8 @@ static NSArray *childRecordFields = nil;
folder = [self ocsFolder];
// For Thunderbird, disable contact list
if ([[context request] isThunderbird]) {
// This will be removed when VCARD will be implemented
if ([[context request] isThunderbird] && [self isKindOfClass: NSClassFromString(@"SOGoContactGCSFolder")]) {
vlistExclusionQualifier = [EOQualifier qualifierWithQualifierFormat: @"c_component != 'vlist'"];
qualifier = [[[EOAndQualifier alloc] initWithQualifiers:
vlistExclusionQualifier,
+45
View File
@@ -0,0 +1,45 @@
/* SOGoMobileProvision.h - this file is part of SOGo
*
* Copyright (C) 2023 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.
*/
#ifndef SOGOMOBILEPROVISION_H
#define SOGOMOBILEPROVISION_H
#include <SOGo/SOGoObject.h>
@class SOGoMobileProvision;
@class NSString;
typedef enum
{
ProvisioningTypeCalendar = 0,
ProvisioningTypeContact = 1
} ProvisioningType;
@interface SOGoMobileProvision : SOGoObject
{
}
+ (NSString *)plistForCalendarsWithContext:(WOContext *)context andPath:(NSString *)path andName:(NSString *)name;
+ (NSString *)plistForContactsWithContext:(WOContext *)context andPath:(NSString *)path andName:(NSString *)name;
@end
#endif /* SOGOMOBILEPROVISION_H */
+131
View File
@@ -0,0 +1,131 @@
/* SOGoMobileProvision.m - this file is part of SOGo
*
* Copyright (C) 2023 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/Foundation.h>
#import "SOGoMobileProvision.h"
#import "SOGoUser.h"
#import "NSString+Crypto.h"
@implementation SOGoMobileProvision
+ (NSString *)_plistWithContext:(WOContext *)context andPath:(NSString *)path andType:(ProvisioningType) provisioningType andName:(NSString *)name
{
NSData *plistData;
SOGoUser *activeUser;
NSURL *serverURL;
NSDictionary *provisioning;
NSError *error;
NSString *payloadType, *prefix, *type;
NSNumber *port;
activeUser = [context activeUser];
serverURL = [context serverURL];
if (!context || !path) {
[self errorWithFormat: @"Invalid provisioning profile - no parameters"];
return nil;
}
switch(provisioningType) {
case ProvisioningTypeCalendar:
payloadType = @"com.apple.caldav.account";
prefix = @"CalDAV";
type = @"Calendar";
break;
case ProvisioningTypeContact:
payloadType = @"com.apple.carddav.account";
prefix = @"CardDAV";
type = @"Contact";
break;
}
port = [serverURL port];
if (!port) {
if ([[serverURL scheme] isEqualToString:@"https"]) {
port = [NSNumber numberWithInt: 443];
} else {
port = [NSNumber numberWithInt: 80];
}
}
provisioning = [NSDictionary dictionaryWithObjectsAndKeys:
[NSArray arrayWithObject: [NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat:@"%@ %@", type, name], [NSString stringWithFormat:@"%@%@", prefix, @"AccountDescription"],
[serverURL host], [NSString stringWithFormat:@"%@%@", prefix, @"HostName"],
port, [NSString stringWithFormat:@"%@%@", prefix, @"Port"],
path, [NSString stringWithFormat:@"%@%@", prefix, @"PrincipalURL"],
[NSNumber numberWithBool:[[serverURL scheme] isEqualToString:@"https"]], [NSString stringWithFormat:@"%@%@", prefix, @"UseSSL"],
[activeUser login], [NSString stringWithFormat:@"%@%@", prefix, @"Username"],
[NSString stringWithFormat: @"SOGo %@ provisioning", prefix], @"PayloadDescription",
[NSString stringWithFormat:@"%@ %@", type, name], @"PayloadDisplayName",
[NSString stringWithFormat:@"%@.%@.apple.%@", [serverURL host], [name asMD5String], [prefix lowercaseString]], @"PayloadIdentifier",
[serverURL host], @"PayloadOrganization",
payloadType, @"PayloadType",
[SOGoObject globallyUniqueObjectId], @"PayloadUUID",
[NSNumber numberWithInt: 1], @"PayloadVersion",
nil]], @"PayloadContent",
[NSString stringWithFormat:@"SOGo %@ provisioning", prefix], @"PayloadDescription",
[NSString stringWithFormat: @"%@ (%@)", name, type], @"PayloadDisplayName",
[NSString stringWithFormat:@"%@.%@.%@.apple", [prefix lowercaseString], [serverURL host], [name asMD5String]], @"PayloadIdentifier",
@"SOGo", @"PayloadOrganization",
[NSNumber numberWithBool: NO], @"PayloadRemovalDisallowed",
@"Configuration", @"PayloadType",
[SOGoObject globallyUniqueObjectId], @"PayloadUUID",
[NSNumber numberWithInt: 1], @"PayloadVersion",
nil];
return [NSPropertyListSerialization dataWithPropertyList: provisioning
format: NSPropertyListXMLFormat_v1_0
options: 0
error: &error];
}
+ (NSString *)plistForCalendarsWithContext:(WOContext *)context andPath:(NSString *)path andName:(NSString *)name
{
NSData *plistData;
SOGoUser *activeUser;
plistData = [self _plistWithContext: context andPath: path andType: ProvisioningTypeCalendar andName: name];
if (nil != plistData) {
return [[[NSString alloc] initWithData:plistData encoding:NSUTF8StringEncoding] autorelease];
} else {
[self errorWithFormat: @"Invalid provisioning profile plist for account : %@", [activeUser login]];
return nil;
}
}
+ (NSString *)plistForContactsWithContext:(WOContext *)context andPath:(NSString *)path andName:(NSString *)name
{
NSData *plistData;
SOGoUser *activeUser;
plistData = [self _plistWithContext: context andPath: path andType: ProvisioningTypeContact andName: name];
if (nil != plistData) {
return [[[NSString alloc] initWithData:plistData encoding:NSUTF8StringEncoding] autorelease];
} else {
[self errorWithFormat: @"Invalid provisioning profile plist for account : %@", [activeUser login]];
return nil;
}
}
@end
+2 -1
View File
@@ -103,7 +103,8 @@
/* ownership */
- (void) setOwner: (NSString *) newOwner;
- (NSString *)owner;
- (void)setOwner:(NSString *)newOwner;
- (NSString *) ownerInContext: (id) _ctx;
/* a helper that determines whether access rights can be ignored on
+7 -2
View File
@@ -211,6 +211,11 @@
/* ownership */
- (NSString *) owner
{
return owner;
}
- (void) setOwner: (NSString *) newOwner
{
NSString *uid;
@@ -360,7 +365,7 @@
NSString *usersUrl;
usersUrl = [NSString stringWithFormat: @"%@%@/",
[[WOApplication application] davURLAsString], owner];
[[WOApplication application] davURLAsString], [SOGoUser getEncryptedUsernameIfNeeded: owner withContext: context]];
ownerHREF = davElementWithContent (@"href", XMLNS_WEBDAV, usersUrl);
return [davElementWithContent (@"owner", XMLNS_WEBDAV, ownerHREF)
@@ -1222,7 +1227,7 @@
davCurrentUserPrincipal = nil;
else
{
s = [NSString stringWithFormat: @"/SOGo/dav/%@", login];
s = [NSString stringWithFormat: @"/SOGo/dav/%@", [SOGoUser getEncryptedUsernameIfNeeded:login withContext:[self context]]];
userHREF = davElementWithContent (@"href", XMLNS_WEBDAV, s);
davCurrentUserPrincipal
= [davElementWithContent (@"current-user-principal",
+1 -1
View File
@@ -33,7 +33,7 @@ static const NSString *POLICY_MIN_DIGIT = @"POLICY_MIN_DIGIT";
static const NSString *POLICY_MIN_SPECIAL_SYMBOLS = @"POLICY_MIN_SPECIAL_SYMBOLS";
static const NSString *POLICY_MIN_LENGTH = @"POLICY_MIN_LENGTH";
static const NSString *SPECIAL_SYMBOL_ALLOWED = @"%$&*(){}!?\\@#.,:;+=";
static const NSString *SPECIAL_SYMBOL_ALLOWED = @"%$&*(){}!?\\@#.,:;+=\\[\\]\\|<>\\/-_";
@implementation SOGoPasswordPolicy
+4 -2
View File
@@ -32,9 +32,11 @@
acquire: (BOOL) acquire
{
id userFolder;
NSString *login;
if ([key length] > 0 && [SOGoUser userWithLogin: key roles: nil])
userFolder = [SOGoUserFolder objectWithName: key inContainer: self];
login = [SOGoUser getDecryptedUsernameIfNeeded: key withContext: localContext];
if ([key length] > 0 && [SOGoUser userWithLogin: login roles: nil])
userFolder = [SOGoUserFolder objectWithName: login inContainer: self];
else
userFolder = nil;
+39 -14
View File
@@ -27,6 +27,7 @@
#import <GDLAccess/EOAdaptorChannel.h>
#import <GDLAccess/EOAdaptorContext.h>
#import <GDLAccess/EOAttribute.h>
#import <SOGo/SOGoCache.h>
#import "SOGoSystemDefaults.h"
@@ -35,6 +36,7 @@
static NSURL *tableURL = nil;
static NSString *uidColumnName = @"c_uid";
static EOAttribute *textColumn = nil;
static const NSString *kCDefaultsLenKey = @"kCDefaultsLenKey";
@implementation SOGoSQLUserProfile
@@ -100,10 +102,12 @@ static EOAttribute *textColumn = nil;
EOAdaptorChannel *channel;
NSDictionary *row;
NSException *ex;
NSString *sql, *value;
NSString *sql, *result;
id value;
NSArray *attrs;
value = nil;
result = nil;
cm = [GCSChannelManager defaultChannelManager];
channel = [cm acquireOpenChannelForURL: tableURL];
@@ -134,6 +138,12 @@ static EOAttribute *textColumn = nil;
value = [row objectForKey: fieldName];
if (![value isNotNull])
value = nil; /* we discard any NSNull instance */
if (value && [value isKindOfClass: [NSData class]]) {
result = [NSString stringWithUTF8String: [value bytes]];
} else if (value && [value isKindOfClass: [NSString class]]) {
result = value;
}
}
[cm releaseChannel: channel];
@@ -145,7 +155,7 @@ static EOAttribute *textColumn = nil;
tableURL];
}
return value;
return result;
}
- (NSString *) generateSQLForInsert: (NSString *) jsonRepresentation
@@ -248,22 +258,37 @@ static EOAttribute *textColumn = nil;
EOAdaptorContext *context;
NSArray *attrs;
NSDictionary *infos;
SOGoCache *cache;
NSNumberFormatter *formatter;
r = 65535;
cm = [GCSChannelManager defaultChannelManager];
channel = [cm acquireOpenChannelForURL: tableURL];
sql = [NSString stringWithFormat: @"select character_octet_length as CHARACTER_MAXIMUM_LENGTH from information_schema.columns where table_name = '%@' AND column_name = 'c_defaults'", [tableURL gcsTableName]];
ex = [channel evaluateExpressionX: sql];
if (!ex) {
attrs = [channel describeResults: NO];
infos = [channel fetchAttributes: attrs withZone: NULL];
[cm releaseChannel: channel immediately: YES];
if (infos && [infos objectForKey:@"CHARACTER_MAXIMUM_LENGTH"]) {
r = [[infos objectForKey:@"CHARACTER_MAXIMUM_LENGTH"] longLongValue];
}
cache = [SOGoCache sharedCache];
if ([cache valueForKey:kCDefaultsLenKey]) {
formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
r = [[formatter numberFromString: [cache valueForKey:kCDefaultsLenKey]] unsignedLongLongValue];
[formatter release];
} else {
cm = [GCSChannelManager defaultChannelManager];
channel = [cm acquireOpenChannelForURL: tableURL];
sql = [NSString stringWithFormat: @"select character_octet_length as CHARACTER_MAXIMUM_LENGTH from information_schema.columns where table_name = '%@' AND column_name = 'c_defaults'", [tableURL gcsTableName]];
ex = [channel evaluateExpressionX: sql];
if (!ex) {
attrs = [channel describeResults: NO];
infos = [channel fetchAttributes: attrs withZone: NULL];
[cm releaseChannel: channel immediately: YES];
if (infos && [infos objectForKey:@"CHARACTER_MAXIMUM_LENGTH"]) {
r = [[infos objectForKey:@"CHARACTER_MAXIMUM_LENGTH"] longLongValue];
} else if (infos && [infos objectForKey:@"character_maximum_length"]) { // PGSQL case
r = [[infos objectForKey:@"character_maximum_length"] longLongValue];
}
}
[cache setValue: [[NSNumber numberWithUnsignedLongLong: r] stringValue] forKey: kCDefaultsLenKey];
}
return r;
}
+5
View File
@@ -75,6 +75,11 @@
- (NSArray *) fetchContactsMatching: (NSString *) filter
withCriteria: (NSArray *) criteria
inDomain: (NSString *) domain;
- (NSArray *)fetchContactsMatching:(NSString *)filter
withCriteria:(NSArray *)criteria
inDomain:(NSString *)domain
limit:(int)limit;
- (NSArray *) lookupContactsWithQualifier: (EOQualifier *) qualifier
andSortOrdering: (EOSortOrdering *) ordering
inDomain: (NSString *) domain;
+8
View File
@@ -130,6 +130,14 @@ NSComparisonResult languageSort(id el1, id el2, void *context);
- (NSString *) JWTSecret;
- (NSArray *) disableSharing;
- (NSArray *) disableSharingAnyAuthUser;
- (NSArray *) disableExport;
- (BOOL) enableGlobalAddressBookFirstEntries;
- (int) globalAddressBookFirstEntriesCount;
- (BOOL)isURLEncryptionEnabled;
- (NSString *)urlEncryptionPassphrase;
@end
+58
View File
@@ -819,5 +819,63 @@ NSComparisonResult languageSort(id el1, id el2, void *context)
return disableSharing;
}
- (BOOL)isURLEncryptionEnabled {
return [self boolForKey: @"SOGoURLEncryptionEnabled"];
}
- (NSString *) urlEncryptionPassphrase
{
NSString *passphrase;
passphrase = [self stringForKey: @"SOGoURLEncryptionPassphrase"];
if (!passphrase)
passphrase = @"SOGoSuperSecret0"; // Default passphrase
return passphrase;
}
- (NSArray *) disableSharingAnyAuthUser
{
static NSArray *disableSharingAnyAuthUser = nil;
if (!disableSharingAnyAuthUser)
{
disableSharingAnyAuthUser = [self stringArrayForKey: @"SOGoDisableSharingAnyAuthUser"];
[disableSharingAnyAuthUser retain];
}
return disableSharingAnyAuthUser;
}
- (NSArray *) disableExport
{
static NSArray *disableExport = nil;
if (!disableExport)
{
disableExport = [self stringArrayForKey: @"SOGoDisableExport"];
[disableExport retain];
}
return disableExport;
}
- (BOOL) globalAddressBookFirstEntriesEnabled
{
return [self boolForKey: @"SOGoGlobalAddressBookFirstEntries"];
}
- (int) globalAddressBookFirstEntriesCount
{
int v;
v = [self integerForKey: @"SOGoGlobalAddressBookFirstEntriesCount"];
if (!v)
v = 100;
return v;
}
@end
+4
View File
@@ -135,6 +135,10 @@
- (SOGoAppointmentFolder *) personalCalendarFolderInContext: (WOContext *) context;
- (SOGoContactFolder *) personalContactsFolderInContext: (WOContext *) context;
/* Encryption */
+ (NSString *)getEncryptedUsernameIfNeeded:(NSString *)username withContext:(WOContext *)context;
+ (NSString *)getDecryptedUsernameIfNeeded:(NSString *)username withContext:(WOContext *)context;
@end
#endif /* __SOGoUser_H__ */
+83
View File
@@ -39,6 +39,7 @@
#import "SOGoUserManager.h"
#import "SOGoUserSettings.h"
#import "WOResourceManager+SOGo.h"
#import "NSString+Crypto.h"
#if defined(MFA_CONFIG)
#include <liboath/oath.h>
@@ -46,6 +47,8 @@
#import "SOGoUser.h"
static const NSString *kEncryptedUserNamePrefix = @"uenc";
@implementation SoUser (SOGoExtension)
- (SOGoDomainDefaults *) userDefaults
@@ -1197,4 +1200,84 @@
return [accessValue boolValue];
}
/* Encryption */
+ (NSString *) getEncryptedUsernameIfNeeded:(NSString *)username withContext:(WOContext *)context
{
NSException *exception;
NSString *tmp, *cacheKey;
SOGoCache *cache;
WORequest *request;
if (![[SOGoSystemDefaults sharedSystemDefaults] isURLEncryptionEnabled])
return username;
request = [context request];
cache = [SOGoCache sharedCache];
cacheKey = [NSString stringWithFormat: @"%@_%@_%@", kEncryptedUserNamePrefix, username, [request requestHandlerKey]];
exception = nil;
tmp = nil;
tmp = [cache valueForKey: cacheKey];
if (tmp) {
return tmp;
} else {
if (username && [username length] > 0) {
tmp = [username encodeAES128ECBBase64: [[SOGoSystemDefaults sharedSystemDefaults] urlEncryptionPassphrase] encodedURL:YES exception: &exception];
if (!exception) {
[cache setValue:tmp forKey:cacheKey];
return tmp;
} else {
[self errorWithFormat: @"URL Encryption error : %@", [exception reason]];
return username;
}
} else {
[self logWithFormat: @"Empty username for encryption"];
return username;
}
}
}
+ (NSString *) getDecryptedUsernameIfNeeded:(NSString *)username withContext:(WOContext *)context
{
NSException *exception;
NSString *tmp, *cacheKey;
SOGoCache *cache;
WORequest *request;
if (![[SOGoSystemDefaults sharedSystemDefaults] isURLEncryptionEnabled])
return username;
request = [context request];
cache = [SOGoCache sharedCache];
cacheKey = [NSString stringWithFormat: @"%@_%@_%@", kEncryptedUserNamePrefix, username, [request requestHandlerKey]];
exception = nil;
tmp = nil;
tmp = [cache valueForKey: cacheKey];
if (tmp) {
return tmp;
} else {
if (username && [username length] > 0) {
tmp = [username decodeAES128ECBBase64: [[SOGoSystemDefaults sharedSystemDefaults] urlEncryptionPassphrase] encodedURL:YES exception: &exception];
if (tmp) {
[cache setValue:tmp forKey:cacheKey];
} else {
[cache setValue:username forKey:cacheKey];
}
if (!exception) {
return tmp;
} else {
[self errorWithFormat: @"URL Decryption error : %@", [exception reason]];
return username;
}
} else {
[self errorWithFormat: @"Empty username for decryption"];
return username;
}
}
}
@end /* SOGoUser */
+7 -1
View File
@@ -156,6 +156,9 @@ extern NSString *SOGoPasswordRecoverySecondaryEmail;
- (void) setMailComposeFontSize: (int) newValue;
- (int) mailComposeFontSize;
- (void) setMailDisplayFullEmail: (BOOL *) newValue;
- (BOOL *) mailDisplayFullEmail;
- (void) setMailDisplayRemoteInlineImages: (NSString *) newValue;
- (NSString *) mailDisplayRemoteInlineImages;
@@ -228,8 +231,11 @@ extern NSString *SOGoPasswordRecoverySecondaryEmail;
- (void) setMailLabelsColors: (NSDictionary *) newValues;
- (NSDictionary *) mailLabelsColors;
- (void)setHideInlineAttachments:(BOOL)newValue;
- (BOOL)hideInlineAttachments;
/* calendar */
- (void) setCalendarCategories: (NSArray *) newValues;
- (void)setCalendarCategories : (NSArray *)newValues;
- (NSArray *) calendarCategories;
- (void) setCalendarCategoriesColors: (NSDictionary *) newValues;
+20
View File
@@ -631,6 +631,16 @@ NSString *SOGoPasswordRecoverySecondaryEmail = @"SecondaryEmail";
return [self integerForKey: @"SOGoMailComposeFontSize"];
}
- (void) setMailDisplayFullEmail: (BOOL *) newValue
{
[self setBool: newValue forKey: @"SOGoMailDisplayFullEmail"];
}
- (BOOL *) mailDisplayFullEmail;
{
return [self boolForKey: @"SOGoMailDisplayFullEmail"];
}
- (void) setMailDisplayRemoteInlineImages: (NSString *) newValue
{
[self setObject: newValue forKey: @"SOGoMailDisplayRemoteInlineImages"];
@@ -959,6 +969,16 @@ NSString *SOGoPasswordRecoverySecondaryEmail = @"SecondaryEmail";
return [self objectForKey: @"SOGoMailLabelsColors"];
}
- (void) setHideInlineAttachments: (BOOL) newValue
{
[self setBool: newValue forKey: @"SOGoMailHideInlineAttachments"];
}
- (BOOL) hideInlineAttachments
{
return [self boolForKey: @"SOGoMailHideInlineAttachments"];
}
- (void) setSieveFilters: (NSArray *) newValue
{
[self setObject: newValue forKey: @"SOGoSieveFilters"];
+13
View File
@@ -24,6 +24,8 @@
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WORequest+So.h>
#import <SaxObjC/XMLNamespaces.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <DOM/DOMNode.h>
@@ -36,6 +38,7 @@
#import "NSArray+Utilities.h"
#import "NSDictionary+Utilities.h"
#import "NSString+Utilities.h"
#import "NSString+Crypto.h"
#import "SOGoUserManager.h"
#import "SOGoPermissions.h"
#import "SOGoSystemDefaults.h"
@@ -83,6 +86,16 @@
return children;
}
- (NSString *) nameInContainer {
return [SOGoUser getEncryptedUsernameIfNeeded: [super nameInContainer] withContext: context];
}
- (NSString *) davURLAsString
{
return [[container davURLAsString]
stringByAppendingFormat: @"%@/", [self nameInContainer]];
}
/* ownership */
- (NSString *) ownerInContext: (WOContext *) _ctx
+18
View File
@@ -924,6 +924,22 @@
- (NSArray *) fetchContactsMatching: (NSString *) filter
withCriteria: (NSArray *) criteria
inDomain: (NSString *) domain
{
if ([filter length] > 0) {
return [self fetchContactsMatching: (NSString *) filter
withCriteria: (NSArray *) criteria
inDomain: (NSString *) domain
limit: -1];
} else {
return [NSMutableArray array];
}
}
- (NSArray *)fetchContactsMatching: (NSString *)filter
withCriteria: (NSArray *)criteria
inDomain: (NSString *)domain
limit: (int)limit
{
EOAdaptorChannel *channel;
NSEnumerator *criteriaList;
@@ -994,6 +1010,8 @@
[sql appendFormat: @" AND %@ IS NULL", _domainField];
}
if (limit > 0)
[sql appendFormat: @" ORDER BY c_cn ASC LIMIT %i", limit];
ex = [channel evaluateExpressionX: sql];
if (!ex)
{
+1
View File
@@ -105,6 +105,7 @@
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");
+70 -70
View File
@@ -221,95 +221,95 @@
count = [objects count];
for (i = 0; i < count; i++)
{
content = [[[objects objectAtIndex: i] objectForKey: @"c_content"] stringByTrimmingSpaces];
c_name = [[objects objectAtIndex: i] objectForKey: @"c_name"];
if (is_calendar)
{
// We check for
// BEGIN:VCALENDAR
// ..
// END:VCALENDAR
iCalCalendar *calendar;
{
content = [[[objects objectAtIndex: i] objectForKey: @"c_content"] stringByTrimmingSpaces];
c_name = [[objects objectAtIndex: i] objectForKey: @"c_name"];
if (is_calendar)
{
// We check for
// BEGIN:VCALENDAR
// ..
// END:VCALENDAR
iCalCalendar *calendar;
if ([content length] < 30 ||
if ([content length] < 30 ||
[[content substringToIndex: 15] caseInsensitiveCompare: @"BEGIN:VCALENDAR"] != NSOrderedSame ||
[[content substringFromIndex: [content length]-13] caseInsensitiveCompare: @"END:VCALENDAR"] != NSOrderedSame)
{
NSLog(@"Corrupted calendar item (missing tags) in path %@ with c_name = %@", folder, c_name);
if (delete)
[gcsFolder deleteContentWithName: c_name];
[gcsFolder deleteContentWithName: c_name];
rc = NO;
}
else
else
{
calendar = [iCalCalendar parseSingleFromSource: content];
if (!calendar)
{
NSLog(@"Corrupted calendar item (unparsable) in path %@ with c_name = %@", folder, c_name);
if (delete)
[gcsFolder deleteContentWithName: c_name];
rc = NO;
}
else
{
iCalEvent *event;
{
NSLog(@"Corrupted calendar item (unparsable) in path %@ with c_name = %@", folder, c_name);
if (delete)
[gcsFolder deleteContentWithName: c_name];
rc = NO;
}
else
{
iCalEvent *event;
event = (iCalEvent *) [calendar firstChildWithTag: @"vevent"];
if (event)
{
iCalDateTime *startDate, *endDate;
event = (iCalEvent *) [calendar firstChildWithTag: @"vevent"];
if (event)
{
iCalDateTime *startDate, *endDate;
startDate = (iCalDateTime *) [event uniqueChildWithTag: @"dtstart"];
if (![startDate dateTime])
{
NSLog(@"Missing start date of event in path %@ with c_name = %@ (%@)", folder, c_name, [event summary]);
if (delete)
[gcsFolder deleteContentWithName: c_name];
rc = NO;
}
endDate = (iCalDateTime *) [event uniqueChildWithTag: @"dtend"];
if (![endDate dateTime] && ![event hasDuration])
{
NSLog(@"Missing end date of event in path %@ with c_name = %@ (%@)", folder, c_name, [event summary]);
if (delete)
[gcsFolder deleteContentWithName: c_name];
rc = NO;
}
if ([startDate dateTime] && [endDate dateTime])
{
NSComparisonResult comparison;
startDate = (iCalDateTime *) [event uniqueChildWithTag: @"dtstart"];
if (![startDate dateTime])
{
NSLog(@"Missing start date of event in path %@ with c_name = %@ (%@)", folder, c_name, [event summary]);
if (delete)
[gcsFolder deleteContentWithName: c_name];
rc = NO;
}
endDate = (iCalDateTime *) [event uniqueChildWithTag: @"dtend"];
if (![endDate dateTime] && ![event hasDuration])
{
NSLog(@"Missing end date of event in path %@ with c_name = %@ (%@)", folder, c_name, [event summary]);
if (delete)
[gcsFolder deleteContentWithName: c_name];
rc = NO;
}
if ([startDate dateTime] && [endDate dateTime])
{
NSComparisonResult comparison;
comparison = [[startDate dateTime] compare: [endDate dateTime]];
if (([event isAllDay] && comparison == NSOrderedDescending) ||
(![event isAllDay] && comparison != NSOrderedAscending))
{
NSLog(@"Start date (%@) is not before end date (%@) for event in path %@ with c_name = %@ (%@)",
[startDate dateTime], [endDate dateTime], folder, c_name, [event summary]);
if (delete)
[gcsFolder deleteContentWithName: c_name];
rc = NO;
}
}
}
}
comparison = [[startDate dateTime] compare: [endDate dateTime]];
if (([event isAllDay] && comparison == NSOrderedDescending) ||
(![event isAllDay] && comparison != NSOrderedAscending))
{
NSLog(@"Start date (%@) is not before end date (%@) for event in path %@ with c_name = %@ (%@)",
[startDate dateTime], [endDate dateTime], folder, c_name, [event summary]);
if (delete)
[gcsFolder deleteContentWithName: c_name];
rc = NO;
}
}
}
}
}
}
else
{
NGVCard *card;
}
else
{
NGVCard *card;
card = [NGVCard parseSingleFromSource: content];
card = [NGVCard parseSingleFromSource: content];
if (!card)
if (!card)
{
NSLog(@"Corrupted card item (unparsable) in path %@ with c_name = %@", folder, c_name);
if (delete)
[gcsFolder deleteContentWithName: c_name];
rc = NO;
NSLog(@"Corrupted card item (unparsable) in path %@ with c_name = %@", folder, c_name);
if (delete)
[gcsFolder deleteContentWithName: c_name];
rc = NO;
}
}
}
}
}
return rc;
}
+8 -1
View File
@@ -138,7 +138,14 @@
sessionExpireMinutes = [[arguments objectAtIndex: 0] intValue];
}
if (sessionExpireMinutes >= 0)
NSLog(@"Remove all sessions older than %d min", sessionExpireMinutes);
if (sessionExpireMinutes == 0 && ![[arguments objectAtIndex: 0] isEqualToString:@"0"])
{
//If the input is not a number intValue return 0 so we check that's really the case
[self usage];
}
else if (sessionExpireMinutes >= 0)
{
rc = [self expireUserSessionOlderThan: sessionExpireMinutes];
}
+5 -5
View File
@@ -113,13 +113,13 @@ typedef enum
" remove remove all ACL information of folder for user\n"
" subscribe subscribe user to owner's folder\n"
" unsubscribe unsubscribe user to owner's folder\n"
" owner the user owning the folder\n"
" owner the user owning the folder\n"
" folder the folder - Calendar/<ID> or Contacts/<ID>\n"
" user the user (or group without the @ prefix) to get/set rights for - 'ALL', '<default>', 'anonymous' are supported\n"
" rights rights to add\n\n"
"Example: sogo-tool manage-acl get jdoe Calendar/personal ALL\n\n"
"Note: You can add only one access right at the time. To set them all at once,\n"
" invoke 'remove' first to remove them all.\n\n");
" rights rights to add\n\n"
"Example: sogo-tool manage-acl get jdoe Calendar/personal ALL\n\n"
"Note: You can add only one access right at the time. To set them all at once,\n"
" invoke 'remove' first to remove them all.\n\n");
}
- (BOOL) parseArguments
+65 -50
View File
@@ -86,15 +86,15 @@
/* we want to match the field value case-insensitively */
recordEmail = [[record objectForKey: field] uppercaseString];
if ([recordEmail length])
{
recordList = [doubleEmails objectForKey: recordEmail];
if (!recordList)
{
recordList = [doubleEmails objectForKey: recordEmail];
if (!recordList)
{
recordList = [NSMutableArray arrayWithCapacity: 5];
[doubleEmails setObject: recordList forKey: recordEmail];
}
[recordList addObject: record];
recordList = [NSMutableArray arrayWithCapacity: 5];
[doubleEmails setObject: recordList forKey: recordEmail];
}
[recordList addObject: record];
}
}
- (void) cleanupSingleRecords: (NSMutableDictionary *) doubleEmails
@@ -220,21 +220,20 @@
recordsToRemove = [NSMutableArray arrayWithCapacity: (max - 1)];
for (count = 0; count < max; count++)
{
if (count != keptRecord)
{
if (count != keptRecord)
{
currentRecord = [records objectAtIndex: count];
[recordsToRemove
addObject: [currentRecord objectForKey: @"c_name"]];
}
currentRecord = [records objectAtIndex: count];
[recordsToRemove addObject: [currentRecord objectForKey: @"c_name"]];
}
}
return recordsToRemove;
}
- (NSArray *) records: (NSArray *) records
withLowestScores: (unsigned int *) scores
count: (unsigned int) max
count: (unsigned int) max
{
unsigned int count, highestScore;
int highestScoreRecord;
@@ -242,13 +241,13 @@
highestScore = 0;
highestScoreRecord = -1;
for (count = 0; count < max; count++)
{
if (scores[count] > highestScore)
{
if (scores[count] > highestScore)
{
highestScore = scores[count];
highestScoreRecord = count;
}
highestScore = scores[count];
highestScoreRecord = count;
}
}
if (highestScoreRecord == -1)
highestScoreRecord = 0;
@@ -268,16 +267,15 @@
highestVersion = 0;
for (count = 0; count < max; count++)
{
currentVersion = [[records objectAtIndex: count] objectForKey: @"c_version"];
version = [currentVersion intValue];
if (version > highestVersion)
{
currentVersion
= [[records objectAtIndex: count] objectForKey: @"c_version"];
version = [currentVersion intValue];
if (version > highestVersion)
{
mostModified = count;
highestVersion = version;
}
mostModified = count;
highestVersion = version;
}
}
return mostModified;
}
@@ -291,25 +289,25 @@
amount = 0;
if (!quickFields)
{
quickFields = [NSArray arrayWithObjects: @"c_givenname", @"c_cn",
@"c_sn", @"c_screenname", @"c_l", @"c_mail",
@"c_o", @"c_ou", @"c_telephonenumber", nil];
[quickFields retain];
}
{
quickFields = [NSArray arrayWithObjects: @"c_givenname", @"c_cn",
@"c_sn", @"c_screenname", @"c_l", @"c_mail",
@"c_o", @"c_ou", @"c_telephonenumber", nil];
[quickFields retain];
}
max = [quickFields count];
for (count = 0; count < max; count++)
{
value = [record objectForKey: [quickFields objectAtIndex: count]];
if ([value isKindOfClass: [NSString class]])
{
value = [record objectForKey: [quickFields objectAtIndex: count]];
if ([value isKindOfClass: [NSString class]])
{
if ([value length])
amount++;
}
else if ([value isKindOfClass: [NSNumber class]])
amount++;
if ([value length])
amount++;
}
else if ([value isKindOfClass: [NSNumber class]])
amount++;
}
return amount;
}
@@ -323,15 +321,14 @@
highestQFields = 0;
for (count = 0; count < max; count++)
{
currentQFields = [self amountOfFilledQuickFields: [records objectAtIndex: count]];
if (currentQFields > highestQFields)
{
currentQFields
= [self amountOfFilledQuickFields: [records objectAtIndex: count]];
if (currentQFields > highestQFields)
{
mostQuickFields = count;
highestQFields = currentQFields;
}
mostQuickFields = count;
highestQFields = currentQFields;
}
}
return mostQuickFields;
}
@@ -399,10 +396,28 @@
}
- (void) assignScores: (unsigned int *) scores
toRecords: (NSArray *) records
count: (unsigned int) max
toRecords: (NSArray *) records
count: (unsigned int) max
withCardsInLists: (NSArray *) cardsInLists
{
/*
Records is an Array of record which are duplicates of each other.
The goal here is to know which one to keep and whoch ones to discard.
We will assign a score to each record, the one with the best scores is kept
Record which has been the last modified: +1
Record has the most content: +2
Record has the most quick field set: +3
Record is in a list: +6
If two record have the same, for exemple, content. It's the first one on the list
that will get the points.
If two recors have the same score. t's the first one on the list
that will get the points.
quick fiels are =("c_givenname": Firstname, @"c_cn": Display,
@"c_sn": LastName, @"c_screenname": Screen Name @"c_l": City, @"c_mail": mails,
@"c_o": organisation, @"c_ou": organisation unit, @"c_telephonenumber": telephone)
*/
int recordIndex;
recordIndex = [self mostModifiedRecord: records count: max];
+1 -1
View File
@@ -634,7 +634,7 @@
if (authname == nil || authpwd == nil)
{
NSLog(@"To update Sieve scripts, you must provide the \"-p credentialFile\" parameter");
NSLog(@"To update Sieve scripts, you must provide the \"-c credentialFile\" parameter");
return NO;
}
+3 -3
View File
@@ -210,8 +210,7 @@
GCSFolder *folder;
BOOL rc;
folderPath = [NSString stringWithFormat: @"/Users/%@/Calendar/%@",
username, folderId];
folderPath = [NSString stringWithFormat: @"/Users/%@/Calendar/%@", username, folderId];
folder = [fom folderAtPath: folderPath];
if (folder)
rc = [self truncateEntriesFromFolder: folder usingDate: date];
@@ -238,12 +237,13 @@
// in the default timezone.
s = [NSString stringWithFormat: @"%@ GMT", date];
d = [NSCalendarDate dateWithString: s calendarFormat: @"%Y-%m-%dT%H:%M:%S %Z"];
NSLog(@"Date is: %@", d);
fom = [GCSFolderManager defaultFolderManager];
if (d && fom)
rc = [self processFolder: folder
ofUser: username
date: d
date: d
withFoM: fom];
else
rc = NO;
+3
View File
@@ -146,6 +146,9 @@
[helpString appendFormat: @"\t%-20@-- %@\n",
command, [currentTool objectAtIndex: 1]];
}
[helpString appendString: @"\n Visit https://www.sogo.nu/files/docs/SOGoInstallationGuide.html#_using_sogo_tool to get more infos"];
NSLog (@"%@", helpString);
}
@@ -1,7 +1,7 @@
/* this file is in UTF-8 format! */
"Help" = "Pagalba";
"Close" = "Uždarytis";
"Close" = "Uždaryti";
"Modules" = "Moduliai";
/* Modules short names */
"ACLs" = "ACLs";
@@ -14,7 +14,7 @@
/* Rights module: initial search message */
"Start a search to edit the rights" = "Pradėti paiešką redaguoti savo teisėms";
/* Rights module: Empty search result */
"No matching user" = "Nerasta atitinkantis vartotojas";
"No matching user" = "Nėra atitinkamo naudotojo";
/* Rights module: no selection */
"No resource selected" = "Nėra pasirinkta išteklių";
"Add User" = "Pridėti vartotoją";
@@ -45,7 +45,7 @@
"Reduce" = "Reduzir";
/* tooltip */
"Refresh" = "Refresh";
"Refresh" = "Atualizar";
/* generic.js */
"Unable to subscribe to that folder!"
@@ -109,7 +109,7 @@
"Personal" = "Pessoal";
"To Do" = "Tarefa";
"Later" = "Adiar";
"Forwarded" = "Forwarded";
"Forwarded" = "Encaminhado";
"Return Receipt Sent" = "Confirmação de recebimento enviada";
"a2_Sunday" = "Dom";
"a2_Monday" = "Seg";
@@ -227,9 +227,9 @@
"Move forward" = "Mover para frente";
/* 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" = "Desabilitado";
"passwordRecovery_SecretQuestion" = "Pergunta secreta";
"passwordRecovery_SecretQuestion1" = "Qual é o nome do seu primeiro animal de estimação?";
"passwordRecovery_SecretQuestion2" = "Qual foi o seu primeiro carro?";
"passwordRecovery_SecretQuestion3" = "Qual é o seu filme favorito ?";
"passwordRecovery_SecondaryEmail" = "E-mail secundário";
+16 -16
View File
@@ -26,15 +26,15 @@
"Subscribe User" = "Prenumeruoti vartotoją";
"Any Authenticated User" = "Bet kokiam autentifikuotam vartotojui";
"Public Access" = "Vieša prieiga";
"Any user not listed above" = "Bet kuris vartotojas, nesantis aukščiau išvardytų";
"Anybody accessing this resource from the public area" = "Kas nors jungiansi prie šio šaltinio iš viešos erdvės";
"Sorry, the user rights can not be configured for that object." = "Atsiprašome, vartotojo teisės negali būti konfiguruojamos šiam objektui.";
"Any user not listed above" = "Bet kuris pirmiau nenurodytas naudotojas";
"Anybody accessing this resource from the public area" = "Visi, kurie prie šio ištekliaus prieina iš viešosios erdvės.";
"Sorry, the user rights can not be configured for that object." = "Atsiprašome, naudotojo teisių šiam objektui konfigūruoti negalima.";
"Any user with an account on this system will be able to access your mailbox \"%{0}\". Are you certain you trust them all?"
= "Bet kuris vartotojas turintis paskyrą šioje sistemoje galės prieiti prie Jūsų elektroninės pašto dėžutės \"%{0}\". Ar Jūs tikrai jais pasitikite?";
"Any user with an account on this system will be able to access your calendar \"%{0}\". Are you certain you trust them all?"
= "Bet kuris vartotojas turintis paskyrą šioje sistemoje galės prieiti prie Jūsų kalendoriaus \"%{0}\". Ar Jūs tikrai jais pasitikite?";
"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?"
= "Potencialiai visi internete galės prieiti prie Jūsų kalendoriaus \"%{0}\", net jei jie ir neturi paskyros šioje sistemoje. Ar ši informacija tinka viešai prieigai?";
= "Prie Jūsų kalendoriaus \"%{0}\" galės prieiti bet kuris internete esantis asmuo, net jei jis neturi paskyros šioje sistemoje. Ar ši informacija tinka viešai prieigai?";
"Any user with an account on this system will be able to access your address book \"%{0}\". Are you certain you trust them all?"
= "Visi vartotojai turintys paskyras šioje sistemoje galės prieiti prie adresų knygos \"%{0}\". Ar Jūs tikrai jais pasitikite?";
"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?"
@@ -51,29 +51,29 @@
"Unable to subscribe to that folder!"
= "Neįmanoma prenumeruoti šio aplanko!";
"You cannot subscribe to a folder that you own!"
= "Jūs negalite prenumeruoti savo aplanko!";
= "Jūs negalite prenumeruoti Jums priklausančio aplanko!";
"Unable to unsubscribe from that folder!"
= "Negalima neprenumeruoti iš šio aplanko!";
= "Nepavyksta atsisakyti prenumeratos šiame aplanke!";
"You cannot unsubscribe from a folder that you own!"
= "Jūs negalite neprenumeruoti savo aplanko!";
= "Negalite atsisakyti prenumeratos iš Jums priklausančio aplanko!";
"Unable to rename that folder!" = "Negalima pervardinti aplanko!";
"You have already subscribed to that folder!"
= "Jūs jau prenumeruojate šį aplanką!";
= "Jūs jau užsiprenumeravote šį aplanką!";
"The user rights cannot be edited for this object!"
= "Vartotojo teisės negali būti keičiamos šiam objektui!";
"A folder by that name already exists." = "Aplankas tokiu pavadinimu jau egzistuoja.";
"You cannot create a list in a shared address book."
= "Jūs negalite sukurti sąrašo pasidalintoje adresų knygoje.";
= "Bendrai naudojamoje adresų knygoje negalima sukurti sąrašo.";
"Warning" = "Įspėjimas";
"Can't contact server" = "Įvyko klaida, kai buvo bandoma susisiekti su serveriu. Prašome bandyti dar kartą.";
"You are not allowed to access this module or this system. Please contact your system administrator."
= "Jums negalima prieiti prie šio modulio ar šios sistemos. Prašome susisiekti su Jūsų sistemos administratoriumi.";
"You don't have the required privileges to perform the operation."
= "Jūs neturite reikalingų teisių atlikti šiam veiksmui.";
"noEmailForDelegation" = "Jūs turite nurodyti adresą, kurį norite perduoti Jūsų kvietime.";
= "Neturite reikalingų teisių šiam veiksmui atlikti.";
"noEmailForDelegation" = "Turite nurodyti adresą, kuriam norite perduoti kvietimą.";
"delegate is organizer" = "Atstovas yra kelionių organizatorius. Prašome nurodyti kitą ";
"delegate is a participant" = "Atstovas jau yra dalyvis.";
"delegate is a group" = "Nurodytas adresas atitinka grupę. Jūs galite tik atstovauti unikalų asmenį.";
"delegate is a group" = "Nurodytas adresas atitinka grupę. Deleguoti galima tik unikaliam asmeniui.";
/* common buttons */
"OK" = "Gerai";
@@ -119,14 +119,14 @@
"a2_Friday" = "Pn";
"a2_Saturday" = "Š";
"Access Rights" = "Prieigos teisės";
"Add User" = "Pridėti vartotoją";
"Add User" = "Pridėti naudotoją";
"Loading" = "Įkrovimas";
"No such user." = "Tokio vartotojo nėra.";
"No such user." = "Tokio naudotojo nėra.";
"You cannot (un)subscribe to a folder that you own!" = "Jūs negalite (atsisakyti) užsiregistruoti šio aplanko, nes jis jums priklauso!";
/* SMIME Certificate field */
"S/MIME Certificate" = "S/MIME Certificate";
"Subject Name" = "Subject Name";
"S/MIME Certificate" = "S/MIME Sertifikatas";
"Subject Name" = "Temos pavadinimas";
"Issuer" = "Issuer";
"streetAddress" = "Street";
"stateOrProvinceName" = "State or Province";
+8 -8
View File
@@ -45,7 +45,7 @@
"Reduce" = "Zmniejsz";
/* tooltip */
"Refresh" = "Refresh";
"Refresh" = "Odśwież";
/* generic.js */
"Unable to subscribe to that folder!"
@@ -109,7 +109,7 @@
"Personal" = "Osobiste";
"To Do" = "Do zrobienia";
"Later" = "Później";
"Forwarded" = "Forwarded";
"Forwarded" = "Przekazane";
"Return Receipt Sent" = "Potwierdzenie wysłane";
"a2_Sunday" = "Ni";
"a2_Monday" = "Pn";
@@ -227,9 +227,9 @@
"Move forward" = "Idź naprzód";
/* 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" = "Zablokowane";
"passwordRecovery_SecretQuestion" = "Poufne pytanie";
"passwordRecovery_SecretQuestion1" = "Jakie jest imię twojego pierwszego zwierzaka?";
"passwordRecovery_SecretQuestion2" = "Jaki miałeś pierwszy samochód?";
"passwordRecovery_SecretQuestion3" = "Jaki jest twój ulubiony film?";
"passwordRecovery_SecondaryEmail" = "Dodatkowy e-mail";
+24 -1
View File
@@ -101,7 +101,11 @@
NSDictionary *currentUserInfos;
NSMutableDictionary *userData;
id <WOActionResults> result;
WORequest *request;
NSArray *reqPathArray;
NSEnumerator *aclsEnum;
BOOL defaultUserDisable;
SOGoSystemDefaults *sd;
if (!prepared)
{
@@ -142,8 +146,27 @@
}
// Add the 'Any authenticated' user
if (defaultUserID)
request = [[self context] request];
reqPathArray = [request requestHandlerPathArray];
sd = [SOGoSystemDefaults sharedSystemDefaults];
if (NSNotFound != [reqPathArray indexOfObject: kDisableSharingMail]
&& nil != [sd disableSharingAnyAuthUser]
&& NSNotFound != [[sd disableSharingAnyAuthUser] indexOfObject: kDisableSharingMail]) {
defaultUserDisable = YES;
}
if (NSNotFound != [reqPathArray indexOfObject: kDisableSharingContacts]
&& nil != [sd disableSharingAnyAuthUser]
&& NSNotFound != [[sd disableSharingAnyAuthUser] indexOfObject: kDisableSharingContacts]) {
defaultUserDisable = YES;
}
if (NSNotFound != [reqPathArray indexOfObject: kDisableSharingCalendar]
&& nil != [sd disableSharingAnyAuthUser]
&& NSNotFound != [[sd disableSharingAnyAuthUser] indexOfObject: kDisableSharingCalendar]) {
defaultUserDisable = YES;
}
if (!defaultUserDisable && defaultUserID)
{
userData = [NSDictionary dictionaryWithObjectsAndKeys:
defaultUserID, @"uid",
[self labelForKey: @"Any Authenticated User"], @"cn",
+26
View File
@@ -292,6 +292,32 @@
while ((currentUser = [usersList nextObject]))
{
currentUid = [currentUser objectForKey: @"uid"];
//Check if we disable the fact to set rights for defaultsUser
if (!defaultUserID)
ASSIGN (defaultUserID, [[self clientObject] defaultUserID]);
if([currentUid isEqualToString: defaultUserID])
{
if (NSNotFound != [reqPathArray indexOfObject: kDisableSharingMail]
&& nil != [sd disableSharingAnyAuthUser]
&& NSNotFound != [[sd disableSharingAnyAuthUser] indexOfObject: kDisableSharingMail]) {
response = [self responseWithStatus: 403];
return response;
}
if (NSNotFound != [reqPathArray indexOfObject: kDisableSharingContacts]
&& nil != [sd disableSharingAnyAuthUser]
&& NSNotFound != [[sd disableSharingAnyAuthUser] indexOfObject: kDisableSharingContacts]) {
response = [self responseWithStatus: 403];
return response;
}
if (NSNotFound != [reqPathArray indexOfObject: kDisableSharingCalendar]
&& nil != [sd disableSharingAnyAuthUser]
&& NSNotFound != [[sd disableSharingAnyAuthUser] indexOfObject: kDisableSharingCalendar]) {
response = [self responseWithStatus: 403];
return response;
}
}
if (!([self _initRightsForUserID: currentUid]))
{
jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"No such user."]
@@ -193,6 +193,7 @@
"Work" = "العمل";
"Mobile" = "Mobile";
"Pager" = "النداء";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "الزميل، المنافس، العملاء، الصديق، العائلة، شريك تجاري، مقدم خدمة، الصحافة ، كبار الشخصيات";
@@ -193,6 +193,7 @@
"Work" = "Lana";
"Mobile" = "Mugikorra";
"Pager" = "Orrikatzailea";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Lankide, Lehiakide, Bezero, Lagun, Familia, Negoziokidea, Hornitzailea, Prentsa, VIP";
@@ -193,6 +193,7 @@
"Work" = "Posao";
"Mobile" = "Mobilni";
"Pager" = "Pejdžer";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Kolega, Konkurent, Klijent, Prijatelj, Porodica, Poslovni Partner, Provajder, Štampa, VIP";
@@ -193,6 +193,7 @@
"Work" = "Comercial";
"Mobile" = "Celular";
"Pager" = "Pager";
"Download iOS - MacOS configuration profile" = "Baixe perfil de configuração para iOS -MacOS ";
/* categories */
"contacts_category_labels" = "Colega, Concorrente, Cliente, Amigo, Família, Parceiro de Negócios, Provedor, Press, VIP";
@@ -193,6 +193,7 @@
"Work" = "Работа";
"Mobile" = "Мобилно";
"Pager" = "Пейджър";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Колега, Конкурент, Клиент, Приятел, Член на семейството, Бизнес партньор, Доставчик, Преса, VIP";
@@ -193,6 +193,7 @@
"Work" = "Feina";
"Mobile" = "Mòbil";
"Pager" = "Cercapersones";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Colleague, Competitor, Customer, Friend, Family, Business Partner, Provider, Press, VIP";
@@ -193,6 +193,7 @@
"Work" = "工作";
"Mobile" = "手机";
"Pager" = "传呼";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "同事, 竞争对手, 客户, 朋友, 家庭, 工作伙伴, 供应商, 媒体, VIP";
@@ -193,6 +193,7 @@
"Work" = "公司";
"Mobile" = "手機";
"Pager" = "呼叫器";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "同事,競爭對手,客戶,朋友,家人,事業夥伴,供應商,出版社,VIP";
@@ -193,6 +193,7 @@
"Work" = "Posao";
"Mobile" = "Mobitel";
"Pager" = "Pager";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Kolega, Natjecatelj, Kupac, Prijatelj, Obitelj, Poslovni partner, Uslužitelj, Tisak, VIP";
@@ -193,6 +193,7 @@
"Work" = "Zaměstnání";
"Mobile" = "Mobilní telefon";
"Pager" = "Pager";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Kolega, Konkurent, Zákazník, Přítel, Rodina, Obchodní partner, Dodavatel, Tisk, VIP";
@@ -193,6 +193,7 @@
"Work" = "Arbejde";
"Mobile" = "Mobil";
"Pager" = "Personsøger";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS-konfigurationsprofil";
/* categories */
"contacts_category_labels" = "kollega, konkurrent, kunde, ven, familie, samarbejdspartner, udbyder, presse, VIP";
@@ -193,6 +193,7 @@
"Work" = "Werk";
"Mobile" = "Mobiel";
"Pager" = "Pieper";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Collega, Concurrent, Klant, Vriend, Familie, Zakenpartner, Leverancier, Pers, VIP";
@@ -193,6 +193,7 @@
"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";
@@ -193,6 +193,7 @@
"Work" = "Työ";
"Mobile" = "GSM";
"Pager" = "Hakulaite";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Kollega, Kilpailija, Asiakas, Ystävä, Perhe, Liikekummpani, Palveluntarjoaja, Lehdistö, VIP";
@@ -193,6 +193,7 @@
"Work" = "Travail";
"Mobile" = "Portable";
"Pager" = "Téléavertisseur";
"Download iOS - MacOS configuration profile" = "Télécharger le profil de configuration pour iOS - MacOS";
/* categories */
"contacts_category_labels" = "Ami, Client, Collègue, Concurrent, Famille, Fournisseur, Partenaire d'affaire, Presse, VIP";
@@ -193,6 +193,7 @@
"Work" = "Traballo";
"Mobile" = "Móbil";
"Pager" = "Buscapersonas";
"Download iOS - MacOS configuration profile" = "Descargar o perfil de configuración de iOS - MacOS";
/* categories */
"contacts_category_labels" = "Colega, Competidor, Cliente, Amigo, Familia, Socio, Provedor, Prensa, VIP";
@@ -193,6 +193,7 @@
"Work" = "Dienstlich";
"Mobile" = "Handy";
"Pager" = "Pager";
"Download iOS - MacOS configuration profile" = "iOS - MacOS Konfigurationsprofil herunterladen";
/* categories */
"contacts_category_labels" = "Anbieter, Familienmitglied, Freund, Geschäftspartner, Kollegin, Konkurrent, Kunde, Lieferant, Presse, VIP";
@@ -193,6 +193,7 @@
"Work" = "עבודה";
"Mobile" = "נייד";
"Pager" = "ביפר";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "עמית, מתחרה, לקוח, חבר, משפחה, שותף עסקי, ספק, עיתונות, VIP";
@@ -193,6 +193,7 @@
"Work" = "Munkahely";
"Mobile" = "Mobiltelefon";
"Pager" = "Személyhívó";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Munkatárs, Versenytárs, Felhasználó, Barát, Család, Üzleti partner, Szolgáltató, Sajtó, VIP";
@@ -193,6 +193,7 @@
"Work" = "Vinnusími";
"Mobile" = "Farsími";
"Pager" = "Símboði";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Samstarfsmaður, Keppinautur, Viðskiptavinur, Vinur, Fjölskylda, Viðskiptatengsl, Þjónustuaðili, Fjölmiðlar, VIP";
@@ -193,6 +193,7 @@
"Work" = "Kerja";
"Mobile" = "Handphone";
"Pager" = "Pager";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Rekan, Pesaing, Pelanggan, Teman, Keluarga, Mitra Bisnis, Provider, Pers, VIP";
@@ -193,6 +193,7 @@
"Work" = "Lavoro";
"Mobile" = "Cellulare";
"Pager" = "Cerca Persone";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Collega, Concorrente, Cliente, Amico, Famiglia, Socio, Provider, Stampa, VIP";
@@ -193,6 +193,7 @@
"Work" = "職業";
"Mobile" = "携帯電話";
"Pager" = "ポケベル";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "同僚, 競合企業, 顧客, 友達, 家族, ビジネスパートナー, プロバイダー, 報道機関, VIP";
@@ -193,6 +193,7 @@
"Work" = "Жұмыс";
"Mobile" = "Ұялы";
"Pager" = "Пейджер";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Әріптес, Бәсекелес, Клиент, Дос, Отбасы, Серіктес, Жеткізуші, Баспасөз, VIP";
@@ -193,6 +193,7 @@
"Work" = "Darbs";
"Mobile" = "Mobilais";
"Pager" = "Peidžeris";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Kolēģi, konkurenti, klienti, draugi, ģimene, biznesa partneri, piegādātāji, Prese, VIP";
@@ -45,8 +45,8 @@
"Copy To" = "Kopijuoti į";
"Add to" = "Pridėti prie";
"To" = "To";
"Carbon Copy (Cc)" = "Carbon Copy (Cc)";
"Blind Carbon Copy (Bcc)" = "Blind Carbon Copy (Bcc)";
"Carbon Copy (Cc)" = "Kopija (Cc)";
"Blind Carbon Copy (Bcc)" = "Nematomoji kopija (Bcc)";
/* Search scope: name fields */
"name" = "Vardas";
@@ -58,7 +58,7 @@
"mozillanickname" = "Antras el. paštas";
/* Search scope: screen name field */
"nsaimid" = "Screen name";
"nsaimid" = "Abonento vardas";
/* Search scope: mail fields */
"mail" = "Mail";
@@ -174,11 +174,11 @@
"Sharing..." = "Bendrinti...";
"Write" = "Rašyti";
"Delete" = "Panaikinti";
"Instant Message" = "Greitoji žinutė";
"Instant Message" = "Žinutė";
"Add..." = "Pridėti";
"Remove" = "Pašalinti";
"Please wait..." = "Prašome palaukti...";
"No possible subscription" = "Nėra įmanomos prenumeratos";
"No possible subscription" = "Prenumerata negalima";
"Preferred" = "Pageidautina";
"Display" = "Rodyti";
"Display Name" = "Ekrano vardas";
@@ -193,6 +193,7 @@
"Work" = "Darbo";
"Mobile" = "Mobilus:";
"Pager" = "Gaviklis:";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Kolega, konkurentas, Klientas, Draugas, Šeima, Verslo partneris, Teikėjas, Spauda, VIP";
@@ -213,28 +214,28 @@
"Timezone" = "Laiko juosta";
"Birthday" = "Gimtadienis";
"Birthday (yyyy-mm-dd)" = "Gimtadienis (yyyy-mm-dd):";
"Freebusy URL" = "Laisvalaikiui ir užimto adresas";
"Freebusy URL" = "Užimtumo adresas";
"Add as..." = "Pridėti kaip...";
"Recipient" = "Gavėjas";
"Carbon Copy" = "Kopija";
"Blind Carbon Copy" = "Nematoma kopija";
"New Addressbook..." = "Nauja adresų knyga...";
"Subscribe to an Addressbook..." = "Įsirašyti į adresų knygą...";
"Remove the selected Addressbook" = "Ištrinti pažymętus iš adresų knygos";
"Subscribe to a shared contact" = "Subscribe to a shared addressbook";
"Search User" = "Ieškoti vartotojo";
"Subscribe to an Addressbook..." = "Prenumeruoti adresų knygą...";
"Remove the selected Addressbook" = "Pašalinti pasirinktą adresų knygą";
"Subscribe to a shared contact" = "Prisijungti prie bendros adresų knygos";
"Search User" = "Ieškoti naudotojo";
"Name of the Address Book" = "Adresų knygos pavadinimas";
"Are you sure you want to delete the selected address book?"
= "Ar jūs įsitikinęs, jog norite ištrinti pažymėtą adresų knygą?";
"Are you sure you want to delete the addressbook \"%{0}\"?"
= "Ar tikrai norite ištrinti adresų knygelę \"%{0}\"?";
= "Ar tikrai norite ištrinti adresų knygą \"%{0}\"?";
"You cannot remove nor unsubscribe from a public addressbook."
= "Jūs negalite pašalinti arba atsisakyti iš viešos adresų knygos.";
"You cannot remove nor unsubscribe from your personal addressbook."
= "Jūs negalite pašalinti arba atsisakyti iš jūsų asmeninės adresų knygos.";
"Are you sure you want to delete the selected contacts?"
= "Ar tikrai norite ištrinti pasirinktus kontaktus?";
"Are you sure you want to delete the card of %{0}?" = "Are you sure you want to delete the card of %{0}?";
"Are you sure you want to delete the card of %{0}?" = "Ar tikrai norite ištrinti kortelę %{0}?";
"You cannot delete the card of \"%{0}\"."
= "Jūs negalite trinti kortelės iš \"%{0}\".";
"You cannot subscribe to a folder that you own!"
@@ -243,15 +244,15 @@
= "Nepavyko prisijungti prie šio aplanko.";
/* security */
"Security" = "Security";
"Security" = "Saugumas";
"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" = "Prieigos teisės";
"For user" = "Vartotojui";
"Any Authenticated User" = "Visiems autorizuotiems vartotojams";
"For user" = "Naudotojui";
"Any Authenticated User" = "Visiems autorizuotiems naudotojams";
"Public Access" = "Viešas priėjimas";
"This person can add cards to this addressbook."
= "Šis asmuo gali pridėti korteles šioje adresų knygoje.";
@@ -193,6 +193,7 @@
"Work" = "Работа";
"Mobile" = "Мобилен";
"Pager" = "Пејџер";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Колега, конкурент, клиент, пријател, фамилија, деловен партнер, провајдер, новинар, ВИП";
@@ -193,6 +193,7 @@
"Work" = "Posao";
"Mobile" = "Mobilni";
"Pager" = "Pejdžer";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Kolega, Konkurent, Klijent, Prijatelj, Porodica, Poslovni Partner, Provajder, Novinar, VIP";
@@ -193,6 +193,7 @@
"Work" = "Arbeid";
"Mobile" = "Mobiltelefon";
"Pager" = "Personsøker";
"Download iOS - MacOS configuration profile" = "Last ned konfigurasjonsprofil for iOS - MacOS";
/* categories */
"contacts_category_labels" = "Kollega, Konkurrent, Kunde, Venn, Familie, Forretningspartner, Leverandør, Presse, VIP";
@@ -193,6 +193,7 @@
"Work" = "Arbeid";
"Mobile" = "Mobiltelefon";
"Pager" = "Personsøker";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Colleague, Competitor, Customer, Friend, Family, Business Partner, Provider, Press, VIP";
@@ -193,6 +193,7 @@
"Work" = "Praca";
"Mobile" = "Telefon kom.";
"Pager" = "Pager";
"Download iOS - MacOS configuration profile" = "Pobierz profil konfiguracyjny iOS - MacOS";
/* categories */
"contacts_category_labels" = "Kolega, Konkurencja, Klient, Przyjaciel, Rodzina, Biznes, Dostawca, Prasa, VIP";
@@ -193,6 +193,7 @@
"Work" = "Trabalho";
"Mobile" = "Móvel";
"Pager" = "Pager";
"Download iOS - MacOS configuration profile" = "Descarregar perfil de configuração para iOS - MacOS";
/* categories */
"contacts_category_labels" = "Colega, Concorrência, Cliente, Amigo, Família, Parceiro de Negócios, Fornecedor, Imprensa, VIP";
@@ -193,6 +193,7 @@
"Work" = "Muncă";
"Mobile" = "Mobil";
"Pager" = "Pager";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Coleg, Competitor, Client, Prieten, Familie, Partener de Business, Furnizor, Presă, VIP";
@@ -193,6 +193,7 @@
"Work" = "Рабочий";
"Mobile" = "Мобильный";
"Pager" = "Пейджер";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Коллега, Конкурент, Клиент, Друг, Семья, Партнер, Поставщик, Пресса, VIP";
@@ -340,7 +341,7 @@
"Import" = "Импорт";
"More options" = "Больше опций";
"Role" = "Роль";
"Add Screen Name" = "Добавить имя экрана";
"Add Screen Name" = "Добавить отображаемое имя";
"Custom 1" = "Настраиваемое 1";
"Custom 2" = "Настраиваемое 2";
"Custom 3" = "Настраиваемое 3";
@@ -193,6 +193,7 @@
"Work" = "Посао";
"Mobile" = "Мобилни";
"Pager" = "Пејџер";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Колега, Конкурент, Клијент, Пријатељ, Породица, Пословни Партнер, Провајдер, Новинар, ВИП";
@@ -193,6 +193,7 @@
"Work" = "Posao";
"Mobile" = "Mobilni";
"Pager" = "Pejdžer";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Kolega, Konkurent, Klijent, Prijatelj, Porodica, Poslovni Partner, Provajder, Novinar, VIP";
@@ -193,6 +193,7 @@
"Work" = "Do práce";
"Mobile" = "Mobil";
"Pager" = "Pager";
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
/* categories */
"contacts_category_labels" = "Kolega, Konkurent, Zákazník, Priateľ, Rodina, Obchodný partner, Dodávateľ, Novinár, VIP";
Loaded 100 of 402 files, more files were not shown because too many files have changed in this diff. Show more