Compare commits

...
345 Commits
Author SHA1 Message Date
Francis Lachapelle ac6e9a564a Merge to 2.2.7 2014-07-30 11:20:25 -04:00
Francis Lachapelle 07324e56a0 Update ChangeLog 2014-07-30 11:16:35 -04:00
Francis Lachapelle 397a36cc89 Preparation for release 2.2.7 2014-07-30 11:16:10 -04:00
Francis Lachapelle c240931c54 Update CKEditor to version 4.4.3 2014-07-30 11:15:05 -04:00
Francis Lachapelle ef2432e10f Update NEWS file 2014-07-30 10:36:31 -04:00
Francis Lachapelle 571322958a Update fi, fr, de, and es_ES translations 2014-07-30 10:33:15 -04:00
Francis Lachapelle bd5c05cca2 Indentation in JavaScript files 2014-07-30 10:31:25 -04:00
Francis Lachapelle ea44308aa3 Fix all-day events display in IE
It also fixes the display of the event categories for all-day events in
IE.
2014-07-29 16:05:46 -04:00
Ludovic Marcotte 94f3246658 Improved error message when you cannot invite users 2014-07-29 10:36:20 -04:00
Ludovic Marcotte 1df7e989e0 Removed worthless declaration 2014-07-25 14:48:25 -04:00
Francis Lachapelle d9ca1051b3 Improve headers of multicolumns view 2014-07-25 11:34:33 -04:00
Ludovic Marcotte 4eefa4c269 Fixed test since we now return a 200 instead of a 204 2014-07-25 08:12:12 -04:00
Ludovic Marcotte 4c21a050d9 JSON interface to folder subscriptions 2014-07-24 14:00:57 -04:00
Alexandre Cloutier b52289904f task.png for DnD taskList 2014-07-24 13:48:41 -04:00
Alexandre Cloutier d5b71526ed Merge branch 'master' of https://github.com/inverse-inc/sogo 2014-07-24 13:44:02 -04:00
Alexandre Cloutier c389630d76 DnD tasksList 2014-07-24 13:35:14 -04:00
Ludovic Marcotte f6ef94a631 improved handling of SOGoSubscriptionFolderFormat 2014-07-24 12:48:03 -04:00
Francis Lachapelle 5de51e8aa1 Fix missing argument with new DnD controller 2014-07-24 09:30:19 -04:00
Ludovic Marcotte 006727a74b Properly destroy cache objects of vanished folders 2014-07-24 08:39:41 -04:00
extrafu 037dd67635 Merge pull request #47 from dekkers/mailpartviewers-requires
Add Mailer and Appointments to product.list requires of MailPartViewers
2014-07-22 14:00:35 -04:00
Jeroen Dekkers 6619840f80 Add Mailer and Appointments to product.list requires of MailPartViewers 2014-07-22 19:54:18 +02:00
Francis Lachapelle 08fd2fcfaa Fix JavaScript after bad merge 2014-07-22 13:26:28 -04:00
Alexandre Cloutier a43dd97fc9 Fix bug with DnD; leftPanelController.stopEvent() 2014-07-22 11:37:45 -04:00
Francis Lachapelle 192659fdd9 Add missing localizable string 2014-07-21 16:12:27 -04:00
Francis Lachapelle 06fe36fd75 Add missing localizable strings 2014-07-21 16:07:13 -04:00
Francis Lachapelle 24f9d83ff7 Fix JavaScript from merge leftover 2014-07-21 16:06:24 -04:00
Ludovic Marcotte 8dd967d0a8 Updated NEWS file for two merged pull requests 2014-07-21 15:38:23 -04:00
Ludovic Marcotte 08cd080d47 Fixed charset substitution in meta tags 2014-07-21 15:34:56 -04:00
Francis Lachapelle 11920f592c Merge pull request #46 from alexcloutier/feature/DragNDropCalendars
Improve drag'n'drop of events in multi-column view
2014-07-21 11:00:27 -04:00
Alexandre Cloutier 28e6bb8b9d Applied comments 2014-07-21 09:52:09 -04:00
Alexandre Cloutier b892b3f794 Add RegEx 2014-07-21 09:52:09 -04:00
Alexandre Cloutier cdf4cc1acb fix DnD from eventList to calendarList for repeated event 2014-07-21 09:52:08 -04:00
Alexandre Cloutier 3cac794de5 move line 2014-07-21 09:52:08 -04:00
Alexandre Cloutier 8f9b24a23f visual helper while dragging from calendar view to calendarList 2014-07-21 09:52:08 -04:00
Alexandre Cloutier a2a7014140 fix dnd repeated event bug + applied comments 2014-07-21 09:52:08 -04:00
Alexandre Cloutier a5ecb2063f added event7.png and adjust javascript indentation 2014-07-21 09:52:08 -04:00
Alexandre Cloutier 9bd7aeebfb DnD from calendarView to CalendarList 2014-07-21 09:40:04 -04:00
Alexandre Cloutier 01af72cfe9 DnD from eventList to the calendarList 2014-07-21 09:40:04 -04:00
Alexandre Cloutier 6dddb5c98c dragNdrop from the events table to the calendars list 2014-07-21 09:40:04 -04:00
Alexandre Cloutier ccf181bcf9 applied comments and fix repeated events dragNdrop between calendars 2014-07-21 09:40:04 -04:00
Alexandre Cloutier e478b29c2e creating and dragNDrop between calendars in multicolumndayview 2014-07-21 09:40:04 -04:00
Francis Lachapelle f3ded6ce2a Merge pull request #45 from alexcloutier/feature/PreventInvitations
New user preference to prevent invitations
2014-07-21 09:38:42 -04:00
Alexandre Cloutier c2027f072d indentation 2014-07-21 09:29:00 -04:00
Alexandre Cloutier ce6a31dd38 Adjust line of code to make it easier to read 2014-07-21 09:27:02 -04:00
Alexandre Cloutier a71013eebf javascript indentation 2014-07-21 09:27:02 -04:00
Alexandre Cloutier eaec5a614d Change exception 403 to 409 and fix indentation in the javascript 2014-07-21 09:27:02 -04:00
Alexandre Cloutier 5217bed5ae Organized the categories and appointments invitations inside a tabContainer 2014-07-21 09:27:02 -04:00
Alexandre Cloutier 17319cc8dd reverted UIxListEditor.wox 2014-07-21 09:27:02 -04:00
Alexandre Cloutier 89d116363c replace ampersands with commas 2014-07-21 09:27:02 -04:00
Alexandre Cloutier 7c3e85f517 applied comments 2014-07-21 09:27:02 -04:00
Alexandre Cloutier 05fb7ae0c8 applied comments 2014-07-21 09:27:02 -04:00
Alexandre Cloutier ef20108e32 fix bug where the user could enter any names in the whitelist 2014-07-21 09:27:02 -04:00
Alexandre Cloutier b5c0363400 applied comment and refactor code 2014-07-21 09:27:02 -04:00
Alexandre Cloutier f0b8eb8dfb server side code to integrate the whitelist 2014-07-21 09:27:02 -04:00
Alexandre Cloutier 16d02455bd Serialization of the whiteList 2014-07-21 09:27:02 -04:00
Alexandre Cloutier 8ded5a8aaf Prevent Invitations and whitelist GUI 2014-07-21 09:27:02 -04:00
Ludovic Marcotte 1cc93c700a Updated NEWS file for changes occurred right after v2.2.6 was released 2014-07-09 14:08:31 -04:00
Francis Lachapelle 44d0cb5c0d Fix refresh of list when forwarding a message
Fixes #2818
2014-07-09 11:19:35 -04:00
Ludovic Marcotte dbdb7d9051 Fix sending of METHOD:REPLY for DAV clients 2014-07-09 10:04:44 -04:00
Francis Lachapelle e343ed240b Fix regression of word breaking
Fixes #2845
2014-07-08 22:01:41 -04:00
Francis Lachapelle 45553be122 Fix rename of calendars, improve tasks count badge 2014-07-08 17:19:55 -04:00
Alexandre Cloutier 1cf4841477 fix display glitch 2014-07-04 11:23:59 -04:00
Alexandre Cloutier 017a85b7f2 fix month events categories display 2014-07-04 10:46:49 -04:00
Alexandre Cloutier 103bb6803a Merge branch 'master' of https://github.com/inverse-inc/sogo 2014-07-04 10:38:24 -04:00
Alexandre Cloutier 8c8e47daf6 fix spacing between events and categorie display 2014-07-04 10:37:35 -04:00
Ludovic Marcotte 8a17246725 Cleaned up code and fixed the translation of the weekdays in the datepicker 2014-07-04 10:18:56 -04:00
Ludovic Marcotte 4843c6b6d7 Renamed Multi-Column to Multicolumn and refactored some code 2014-07-04 08:55:35 -04:00
Ludovic Marcotte 04904d8c61 Merge to 2.2.6 2014-07-02 11:41:46 -04:00
Ludovic Marcotte 6e13f15477 Update ChangeLog 2014-07-02 11:32:18 -04:00
Ludovic Marcotte 5dd2088d42 Updated for the release 2014-07-02 11:32:06 -04:00
Ludovic Marcotte 9c3c2cb926 Updated the doc for the release 2014-07-02 11:23:57 -04:00
Ludovic Marcotte 55422b5f03 Fixed typo 2014-07-02 10:11:13 -04:00
Ludovic Marcotte 899a1eb026 Updated NEWS file 2014-07-02 08:39:01 -04:00
Alexandre Cloutier 660f39a980 delete notice and put grey background for multi-columns view 2014-06-30 14:13:52 -04:00
Alexandre Cloutier 8335c38830 fix infinite loop bug 2014-06-30 13:57:10 -04:00
Alexandre Cloutier 0fb7135335 bugfixes 2014-06-30 13:36:12 -04:00
extrafu 70b0cb78cd Merge pull request #44 from alexcloutier/fix/DailyViewByCalendars
Fix/daily view by calendars
2014-06-30 11:01:06 -04:00
Alexandre Cloutier d197ab71b7 merging conflicts 2014-06-30 10:55:55 -04:00
Alexandre Cloutier 6b58e034f3 printView display the parentView by default 2014-06-30 10:42:07 -04:00
Ludovic Marcotte ff015afde8 Fixed indent 2014-06-30 10:35:55 -04:00
Ludovic Marcotte 6da03bc75c Cleaned up code for older gcc 2014-06-28 08:31:07 -04:00
Alexandre Cloutier 2b119c63e0 Applied comments 2014-06-27 17:21:18 -04:00
Alexandre Cloutier 5b61df8ca4 activeTasks updates dynamically 2014-06-27 17:00:32 -04:00
Alexandre Cloutier 659e2f3aa8 Merge branch 'master' of https://github.com/inverse-inc/sogo 2014-06-27 10:30:10 -04:00
extrafu 8191576361 Merge pull request #41 from alexcloutier/fix/displayTaskNumber
Display the number of active tasks in calendar view
2014-06-27 09:07:07 -04:00
Alexandre Cloutier 5b9c7e07d1 text wraping and text alignment in list view 2014-06-26 21:22:12 -04:00
Alexandre Cloutier cafb896e8c Merge branch 'fix/displayTaskNumber' of https://github.com/alexcloutier/SOGo into fix/displayTaskNumber 2014-06-26 16:43:10 -04:00
Alexandre Cloutier 7a69bc46eb applied comments 2014-06-26 16:42:05 -04:00
Alexandre Cloutier 302e40a1c3 bugFix#2823 2014-06-26 16:08:47 -04:00
Ludovic Marcotte b6be4e6e2f Applied patch from bug #2810 2014-06-26 11:01:16 -04:00
Alexandre Cloutier dabd8d3282 Fix list view printing with multiColumns view 2014-06-26 10:05:48 -04:00
Alexandre Cloutier d7d458a934 multiColumns print view + bugFixes 2014-06-25 17:39:48 -04:00
Ludovic Marcotte 5419f411e5 Fix for bug #2734 2014-06-25 15:05:25 -04:00
Ludovic Marcotte 22f5ed62fe Fixed tests regarding default permissions on CalDAV collections 2014-06-25 10:14:28 -04:00
Ludovic Marcotte 3523dc489f Fix for bug #2825 2014-06-23 12:19:02 -04:00
Alexandre Cloutier 5b3de04fc1 Fix error from the last commit 2014-06-20 13:27:04 -04:00
Alexandre Cloutier eb3cc8916d The multiColumns view 2014-06-20 13:16:55 -04:00
Ludovic Marcotte 9fa0b42e19 Ignore SCHEDULE-AGENT for Thunderbird/Lightning 2014-06-20 11:25:02 -04:00
Ludovic Marcotte e048346cb7 Include, in our private NS, all ACLs defined on a calendar collectiob 2014-06-19 16:08:15 -04:00
Ludovic Marcotte 333b561a59 Applied patch from bug #2736 2014-06-16 15:30:26 -04:00
Ludovic Marcotte 50c0b49a6f Fix for bug #2813 2014-06-16 11:00:39 -04:00
Francis Lachapelle 8202d0588f Add documentation for SOGoSubscriptionFolderFormat
Fixes #2799
2014-06-16 10:20:34 -04:00
Francis Lachapelle d9b578b869 Wait 20 seconds before deleting temporary forms
Those temporary forms are created to download attachments.
Fixes #2811
2014-06-16 09:52:29 -04:00
Francis Lachapelle 5bb64916c6 Fix regression when attaching files to a reply 2014-06-12 09:09:08 -04:00
Ludovic Marcotte e7ddfb0546 Fix for bug #2805 2014-06-11 12:55:51 -04:00
Alexandre Cloutier 0e182f8436 Update SOGoAppointmentFolder.m
Fix the status filtering from 2 to 1
2014-06-11 11:25:17 -04:00
Alexandre Cloutier de2ee2322a Change the NSString with NSNumber and add some JavaScript 2014-06-11 10:24:04 -04:00
Ludovic Marcotte ce07695a55 Make sure to keep the / path prefix 2014-06-10 16:35:36 -04:00
Alexandre Cloutier 43ac57b671 display the number of active tasks in calendar view 2014-06-10 16:18:12 -04:00
Francis Lachapelle 7f7e3cb06a Fix folder name of new subscriptions
Fixes #2801
2014-06-10 14:48:25 -04:00
Francis Lachapelle 6b3a3f858b Update prototype.js to version 1.7.2 2014-06-10 14:32:35 -04:00
Ludovic Marcotte 0133bb3b6b Correctly update the cache on folder update/delete ops. 2014-06-10 13:07:14 -04:00
Ludovic Marcotte 91e3e19e40 Added the Ping ActiveSync command 2014-06-10 11:04:27 -04:00
Ludovic Marcotte 19a95a1818 Applied fix from #2809 2014-06-10 08:58:44 -04:00
Ludovic Marcotte 1292c191ec Make sure we don't have '-' in table names. 2014-06-10 08:46:35 -04:00
Ludovic Marcotte 77dad178d1 Make sure we don't have '-' in table names. 2014-06-10 08:45:35 -04:00
Ludovic Marcotte f48839bf55 Added (slightly modified) patch from #2806 2014-06-09 09:34:00 -04:00
Ludovic Marcotte 0f04be2bcb Added patch from #2808 2014-06-09 09:25:06 -04:00
Ludovic Marcotte 3f8bbe8c60 Applied patch from #2807 2014-06-09 09:14:30 -04:00
Francis Lachapelle f0b4a05c70 Merge to 2.2.5 2014-06-05 13:35:45 -04:00
Francis Lachapelle 6b6ec8a2ae Update ChangeLog 2014-06-05 13:35:17 -04:00
Francis Lachapelle ad30df26af Preparation for release 2.2.5 2014-06-05 13:34:40 -04:00
Francis Lachapelle 6e56f46f86 Update Dutch, Finnish, German, Polish translations 2014-06-05 13:29:10 -04:00
Francis Lachapelle fe38518a36 Minor syntax and comments improvements 2014-06-05 12:14:34 -04:00
Francis Lachapelle e118a72eab Add meta tag to tell IE to use the highest mode 2014-06-05 10:32:13 -04:00
Ludovic Marcotte 72bec939d6 Fixed text/plain reencoding issues for Outlook 2014-06-04 15:56:22 -04:00
Ludovic Marcotte ba258ca806 Fixed repetitive events issues 2014-06-04 15:23:41 -04:00
Ludovic Marcotte 0c2e2f28f7 Don't try to add attachments during reply operations 2014-05-30 13:53:20 -04:00
Ludovic Marcotte f0dfe37a55 Avoid crashing when forwarding mails with no Subject header 2014-05-30 08:41:42 -04:00
Francis Lachapelle 95d6911f1a Merge to 2.2.4 2014-05-29 11:17:46 -04:00
Francis Lachapelle dace1439df Update ChangeLog 2014-05-29 11:16:59 -04:00
Francis Lachapelle d91b37413f Preparation for release 2.2.4 2014-05-29 11:16:40 -04:00
Francis Lachapelle bd916f06eb Update ChangeLog 2014-05-29 11:15:13 -04:00
Francis Lachapelle ecbe0858f7 Update translations 2014-05-29 11:14:23 -04:00
Francis Lachapelle 24095a464c Update CKEditor to version 4.4.1 2014-05-29 10:50:48 -04:00
Francis Lachapelle 9ce3b8ff8f Merge pull request #40 from dekkers/fix-unit-test
Fix unit test with gnustep 1.24
2014-05-29 10:32:30 -04:00
Jeroen Dekkers efc33d8174 Fix unit test by also checking for the different gnustep 1.24 ordering of elements 2014-05-29 15:53:13 +02:00
Jeroen Dekkers 93971dc434 Add $(TEST_TOOL) as dependency of make check 2014-05-29 15:35:46 +02:00
Francis Lachapelle fac9520f64 Fix update of participation status via CalDAV
Fixes #2786
2014-05-28 11:39:25 -04:00
Francis Lachapelle 9eb075cc3f Rename "Archive" to "Export" in Webmail
Fixes #2758
2014-05-28 11:24:10 -04:00
Francis Lachapelle c5922b07aa Restore options when editing a draft
Fixes #193
2014-05-28 11:21:11 -04:00
Ludovic Marcotte 51e07fc306 Fix over previous commit 2014-05-27 15:33:39 -04:00
Ludovic Marcotte d35c52bb38 Fix for bug #2688 2014-05-27 14:44:57 -04:00
Ludovic Marcotte 6bab4c94f2 Added an empty stub for the Provision command 2014-05-27 09:42:02 -04:00
Ludovic Marcotte c31429a5d5 Also include the BS character in non-safe ones. 2014-05-27 08:45:00 -04:00
Ludovic Marcotte 04bb88a470 Updated NEWS file regarding pull request #39 2014-05-26 13:25:39 -04:00
extrafu c79cd750d8 Merge pull request #39 from alexcloutier/fix/publicFolder_ConfigNaming
Added new SOGo configurable variable
2014-05-26 13:24:50 -04:00
Ludovic Marcotte 6fc81e61ec Fixed documentation: NGImap4ConnectionGroupPrefix -> NGImap4ConnectionGroupIdPrefix 2014-05-23 11:30:28 -04:00
Francis Lachapelle d9ad286650 Fix newline in signature of attachment
Fixes #2787
2014-05-23 11:23:02 -04:00
Alexandre Cloutier dd57d56cf9 remove crufts and applies comments 2014-05-23 10:15:21 -04:00
Ludovic Marcotte ab7780d617 Prevent a crash when someone tries to access /SOGo/Microsoft-Server-ActiveSync directly 2014-05-22 14:39:58 -04:00
Ludovic Marcotte cb9332f240 Updated NEWS file regarding #2775 2014-05-22 10:26:58 -04:00
Ludovic Marcotte 7b60ad4797 Added patch from #2775 2014-05-22 09:20:05 -04:00
Alexandre Cloutier 3261c21549 fix case where the displayed name for the subscribed folders is duplicated 2014-05-21 14:26:08 -04:00
Francis Lachapelle 364b409501 FIx mail templates for Brazilian Portuguese
Fixes #2738
2014-05-21 08:44:35 -04:00
Alexandre Cloutier 064565e1a9 Added new SOGo configurable variable for which you can change the default display when adding a shared calendar or a shared addressBook 2014-05-20 17:05:13 -04:00
Alexandre Cloutier f92d280fbb remove unneeded condition to fix navigation in print preview 2014-05-20 11:24:27 -04:00
Francis Lachapelle ea2bce706c Update NEWS file 2014-05-16 21:15:38 -04:00
Francis Lachapelle d74afaf295 Update French translation 2014-05-16 21:15:28 -04:00
Francis Lachapelle 5e7beb3345 Remove unused localizable strings 2014-05-16 21:14:59 -04:00
Francis Lachapelle 2df5887eec Merge pull request #36 from alexcloutier/feat/calendarPrint
New print option in Calendar module
2014-05-16 16:56:51 -04:00
Francis Lachapelle 3d1bdf1a09 Update French translation 2014-05-16 16:52:44 -04:00
Francis Lachapelle 5de1343506 Remove unused localizable string 2014-05-16 16:44:25 -04:00
Francis Lachapelle 1eaa3f3891 Update NEWS file 2014-05-16 16:34:17 -04:00
Francis Lachapelle c2d3a827bd Merge branch 'alexcloutier-feat/searchCapabilities' 2014-05-16 16:30:24 -04:00
Francis Lachapelle 6b72a8d126 Merge branch 'feat/searchCapabilities' 2014-05-16 16:28:43 -04:00
Francis Lachapelle 819d0641b7 Remove common localizable strings from UI/Contacts 2014-05-16 16:19:40 -04:00
Francis Lachapelle 5d7f4ba6c6 Restore localizable string
To avoid new translation ..
2014-05-16 15:59:52 -04:00
Francis Lachapelle 34a7e28858 Rename 'Properties' button of contacts to 'Edit' 2014-05-16 15:58:34 -04:00
Francis Lachapelle 87b010c700 Indentation 2014-05-16 15:57:33 -04:00
Francis Lachapelle a44b183b7e Merge pull request #38 from alexcloutier/fix/link_address
New AddressBook properties popup window
2014-05-16 15:33:23 -04:00
Alexandre Cloutier b488721f83 Reverse loop to make sure no objects is skipped 2014-05-16 15:00:47 -04:00
Alexandre Cloutier 8a03f3bd63 remove start date in tasks 2014-05-16 14:36:51 -04:00
Alexandre Cloutier f8c8abc989 Function isPublicAccessEnabled was missing 2014-05-16 13:50:52 -04:00
Alexandre Cloutier db8d9bb16c Repair broken logic 2014-05-16 11:29:37 -04:00
Alexandre Cloutier 2794425a3f added last changes from cgx 2014-05-16 10:04:37 -04:00
Ludovic Marcotte 2f7979c796 Fix for bug #2709 2014-05-16 08:33:06 -04:00
Ludovic Marcotte c426afd7f2 New cache subsystem for ActiveSync. 2014-05-15 15:03:24 -04:00
Alexandre Cloutier 07445eb069 Created a window for address book properties and add the cardDav URL 2014-05-15 14:45:53 -04:00
Ludovic Marcotte 93bf98c326 Fixed copyright 2014-05-15 14:45:32 -04:00
Ludovic Marcotte c08c3e27d5 Improved modseq code 2014-05-15 14:44:53 -04:00
Ludovic Marcotte c8860dc92b Dropped old user-settings for ActiveSync 2014-05-15 14:32:46 -04:00
Ludovic Marcotte 1a1543a380 Updated script to reflect new table names 2014-05-15 14:29:39 -04:00
Ludovic Marcotte d2d5467317 Removed unused fluff in the file. 2014-05-14 10:51:16 -04:00
Ludovic Marcotte 18443de9bf Updated copyright info 2014-05-14 09:58:05 -04:00
Ludovic Marcotte be72456a9a Renamed folder cache creation method 2014-05-14 09:56:10 -04:00
Ludovic Marcotte a54b3e4289 Renamed the default table name from socfs_ to sogo_cache_folder_ 2014-05-14 08:56:35 -04:00
Ludovic Marcotte 7a4feae8b8 Updated code to reflect cache regorg. 2014-05-14 06:56:05 -04:00
Ludovic Marcotte 99d49b9bd9 Updated code to use the category 2014-05-13 21:14:57 -04:00
Ludovic Marcotte 5f9fb4e1c4 Big refactor for new caching mechanism. 2014-05-13 21:06:59 -04:00
Ludovic Marcotte ef2188962a Renamed cache files for generalization.
The upcoming commit will rename the content.
2014-05-13 19:58:19 -04:00
Ludovic Marcotte 2922f15ca7 More rename 2014-05-13 18:03:37 -04:00
Ludovic Marcotte 41e6fb89d3 Renamed constants in preparation for the big cache cleanup 2014-05-13 17:54:02 -04:00
Ludovic Marcotte c4a3843695 Removed unused configuration parameters 2014-05-13 13:52:20 -04:00
Alexandre Cloutier bf67b6435f applies comments 2014-05-13 13:21:18 -04:00
Alexandre Cloutier b5319446db display and printing modification 2014-05-13 10:36:26 -04:00
Francis Lachapelle d58184af15 Fix synchronization of seen/unseen status of msgs 2014-05-13 10:15:02 -04:00
Francis Lachapelle fbc6856fd5 Improve contextual menu in events list 2014-05-12 16:06:49 -04:00
Francis Lachapelle 5c41915080 Fix focus of popup windows with FF on Windows 2014-05-12 15:25:50 -04:00
Francis Lachapelle 698524b39f Fix synchronization of seen/unseen status of msgs
Fixes #2715
2014-05-09 17:28:02 -04:00
Ludovic Marcotte 1f5a2a4c62 Fixed IMAP copy/move op between subfolder in different accounts 2014-05-09 15:40:57 -04:00
Alexandre Cloutier fc3cfa5484 applied comments 2014-05-08 19:14:39 -04:00
Alexandre Cloutier 593b44ed01 forgotten code 2014-05-08 17:53:20 -04:00
Alexandre Cloutier b2ed7e3f6b search capabilites 2014-05-08 17:17:05 -04:00
Ludovic Marcotte bc2b41f383 Fixed unit test. 2014-05-08 09:13:37 -04:00
Ludovic Marcotte 7d7961ffcf Fix for bug #2492 2014-05-02 13:35:21 -04:00
Francis Lachapelle 0b9afec635 Fix saving preferences with no Sieve requirements
Fixes #2746
2014-05-01 14:07:25 -04:00
Francis Lachapelle 4e42a6a689 Don't limit Sieve script to 8KB
Fixes #2745
2014-04-30 12:36:51 -04:00
Alexandre Cloutier da8febf138 Printing display appear on one page only, fix issues with browsers 2014-04-29 15:42:50 -04:00
Francis Lachapelle 8c563c2922 Fix possible exception when retrieving reminder
Fixes #2744
2014-04-29 14:26:18 -04:00
Alexandre Cloutier fa5cf55367 Update GNUmakefile 2014-04-28 15:42:17 -04:00
Alexandre Cloutier e43b704858 Update UIxCalViewPrint.js 2014-04-28 15:32:47 -04:00
Alexandre Cloutier 44a4baca7f fix the comments in the headers 2014-04-28 15:30:32 -04:00
Alexandre Cloutier 78447d81ae Code refactoring and retouch 2014-04-28 13:54:29 -04:00
Alexandre Cloutier 9dc07fccc0 It is now possible to print the calendar as a list, dayView or weekView 2014-04-25 18:04:24 -04:00
Ludovic Marcotte ba7b65cf7b Fix for bug #2733 2014-04-24 07:59:07 -04:00
Francis Lachapelle 66bfbeaac1 MailEditor: fix text conversion with HTML entities 2014-04-23 10:55:04 -04:00
Ludovic Marcotte 619cb2c0ec Fix for bug #2721 2014-04-23 09:22:20 -04:00
Alexandre Cloutier f9869d19b4 Finished the view, need to display the eventsblock 2014-04-22 17:47:29 -04:00
Alexandre Cloutier 57b747c24a Events list is done. 2014-04-17 17:33:30 -04:00
Alexandre Cloutier 8f6b0f80a7 Creation of the first version of the printing interface 2014-04-14 10:32:08 -04:00
Alexandre Cloutier cb5e6e7ef2 adding button print calendar toolbar, adding template for the print window, ajusting indentation 2014-04-14 10:32:08 -04:00
Francis Lachapelle 49363cfe36 Update datepicker to latest version
From https://github.com/eternicode/bootstrap-datepicker/
2014-04-11 21:37:55 -04:00
Francis Lachapelle c345fc2b8d Fix display of category of events
Fixes #2703
2014-04-10 12:25:42 -04:00
Francis Lachapelle d200629b01 Fix CSS in contact editor and preferences module 2014-04-10 10:05:28 -04:00
Francis Lachapelle cfc1ac6b3b Add missing localizable string 2014-04-10 10:02:51 -04:00
Ludovic Marcotte e66ceaad07 Fixed gcc warnings and added some rationale around yesterday's fix 2014-04-10 09:40:25 -04:00
Ludovic Marcotte f370ac114a Now include message/rfc822 parts as attachments when forwarding mails 2014-04-10 09:24:43 -04:00
Ludovic Marcotte 75ee6b4806 Fixed once more true/false errors 2014-04-10 08:44:44 -04:00
Ludovic Marcotte 0961fbbab3 Properly escape attendee names in case they contain HTML entities 2014-04-10 06:59:18 -04:00
Ludovic Marcotte 0d1c39ca71 Added new configuration parameter to limit the window size 2014-04-09 20:12:19 -04:00
Ludovic Marcotte 5739356f88 Fix tests to handle list-component 2014-04-09 19:27:38 -04:00
Ludovic Marcotte 33467093c1 Fix for #2695 2014-04-09 18:03:33 -04:00
Ludovic Marcotte 96ece873ca Fix for bug #2654 2014-04-09 14:49:31 -04:00
Ludovic Marcotte 8909775cf6 Fix for #2680 2014-04-09 12:19:23 -04:00
Ludovic Marcotte 0ba59de88e Fixed formatting/warnings in previous commit. 2014-04-09 11:09:13 -04:00
extrafu 4fbe937f6d Merge pull request #22 from alexcloutier/fix/1046
BugFix #1046; Whenever the sieve server is unavailable an error message will appear
2014-04-09 11:01:19 -04:00
Ludovic Marcotte ab80e87a3f Applied patches from #2700 2014-04-09 10:57:56 -04:00
Alexandre Cloutier 068eb921aa rebase and fix comments made by extrafu 2014-04-09 10:48:47 -04:00
Alexandre Cloutier 5c13fade22 Fix merge 2014-04-09 10:35:10 -04:00
Ludovic Marcotte 371e5ead08 Updated the doc in prepration for the release 2014-04-09 10:34:48 -04:00
Alexandre Cloutier c5e6ccf332 Fix function sieveClient and the way the iVar Client is handled. Change behaviour of saveMailAccounts()so sogo wont crash if the user tries to resave his preferences after a connection error. 2014-04-09 10:31:34 -04:00
Alexandre Cloutier ec9d48c3a9 Change the function name getClient to sieveClient 2014-04-09 10:29:23 -04:00
Alexandre Cloutier 877082f042 Added missing functions getClient and IsSieveServerConnected and the changes that comes with it 2014-04-09 10:24:35 -04:00
Alexandre Cloutier 342b68fd44 Erase the merging conflicts writings 2014-04-09 10:23:43 -04:00
Alexandre Cloutier e24c22e3dc BugFix #1046; Whenever the sieve server is unavailable an error message will appear. 2014-04-09 10:23:43 -04:00
Ludovic Marcotte 7997448d41 Fixed issus in previous commits 2014-04-09 06:33:02 -04:00
Ludovic Marcotte 3629670fca Fix for #2489 2014-04-08 15:35:36 -04:00
Alexandre Cloutier c250b9a6d4 Fix deleting calendar
Added a "/" inside the function: deletePersonalCalendarConfirm().
2014-04-08 15:32:13 -04:00
extrafu afa564a6a6 Merge pull request #23 from alexcloutier/fix/1636
BugFix#1636; fix the issue where the user could add any birthday for his contact.
2014-04-08 13:17:54 -04:00
Alexandre Cloutier d9b99f536c Erased strings no longer used 2014-04-08 12:48:59 -04:00
Alexandre Cloutier 5699e5e1b4 Add datepicker for contact birthday 2014-04-08 12:12:30 -04:00
Francis Lachapelle e869406081 Minor CSS improvement in mail headers 2014-04-08 11:51:47 -04:00
Ludovic Marcotte 3e221253ad Fix for feature #1496 2014-04-08 11:19:53 -04:00
Alexandre Cloutier 446ef3467a Fix typo 2014-04-08 09:14:00 -04:00
extrafu bf64076b87 Merge pull request #29 from alexcloutier/feat/1496
New feature : 1496

Don't forget to fix the typo.
2014-04-07 19:42:31 -04:00
Alexandre Cloutier c9cbcf2566 applied Morgan's law 2014-04-07 16:40:44 -04:00
extrafu 4fe0358581 Merge pull request #20 from alexcloutier/fix/2616
bugFix #0002616 : change the behavior of ApplicationBaseURL.
2014-04-07 15:44:07 -04:00
Francis Lachapelle 534e4e3d4d Fix text nodes of message with HTML entitites 2014-04-07 11:21:52 -04:00
Alexandre Cloutier 09bcd2aee2 fix code 2014-04-07 10:59:38 -04:00
extrafu 526e21e837 Merge pull request #32 from dekkers/cleanup-generated-files
Delete generated source files when running "make clean".
2014-04-06 17:34:22 -04:00
Jeroen Dekkers c80e222210 Delete generated source files when running "make clean". 2014-04-06 22:44:50 +02:00
Francis Lachapelle 6e60bbb553 Fix saved HTML content of draft uploading a file 2014-04-04 20:20:32 -04:00
Ludovic Marcotte 846212336a Make use of a local pool to avoid over-memory usage 2014-04-04 16:53:58 -04:00
Alexandre Cloutier 349f4d824a Fix function sieveClient and the way the iVar Client is handled. Change behaviour of saveMailAccounts()so sogo wont crash if the user tries to resave his preferences after a connection error. 2014-04-04 15:04:37 -04:00
Alexandre Cloutier 2f565d2ec9 fix variable name for UIxFilterEditor.js
FolderEncoding to sieveFolderEncoding
2014-04-04 14:56:14 -04:00
extrafu eb7cabac71 Merge pull request #19 from alexcloutier/fix/2622
BugFix #0002622: The server Dovecot use by default an UTF-8 and by doing...
2014-04-04 09:21:49 -04:00
Ludovic Marcotte 2ff4498983 Fixed previous commit 2014-04-04 08:44:50 -04:00
Ludovic Marcotte 3eec753b73 Slightly improved previous pull request merge. 2014-04-04 08:39:13 -04:00
extrafu 7b0ffacff0 Merge pull request #24 from alexcloutier/fix/2612
It is now possible to see the version on the general page of the preferences window
2014-04-04 08:33:39 -04:00
Alexandre Cloutier f999c87d4d added traduction in localstring french, added some specification in function sogoVersion 2014-04-03 17:09:00 -04:00
Francis Lachapelle 48f98ef34e Merge to 2.2.3 2014-04-03 10:06:08 -04:00
Francis Lachapelle 378f2b5876 Preparation for release 2.2.3 2014-04-03 10:05:43 -04:00
Francis Lachapelle d091b3d7cd Update ChangeLog 2014-04-03 10:01:40 -04:00
Francis Lachapelle 370e1e6d26 Update CKEditor to version 4.3.4 2014-04-03 10:01:01 -04:00
Francis Lachapelle e2b3d5a7ff Update translations 2014-04-03 09:54:27 -04:00
Ludovic Marcotte 078b88a396 Fix for #2686 2014-04-02 18:14:17 -04:00
Francis Lachapelle ee09b80fc3 Simplify [UIxContactEditor addressBookDisplayName]
We were trying to translate the default address book name to the user's
language, but the method [SOGoContactFolders defaultFolderName] is
already returning a translated string, making the whole logic useless.
2014-04-02 10:15:59 -04:00
Francis Lachapelle 99d9615c92 Update NEWS file 2014-04-02 10:09:09 -04:00
Francis Lachapelle 79c3fa8ad2 Merge pull request #30 from dekkers/remove-executable-permission-from-jquery
Remove executable permission from jQuery modules
2014-04-01 11:42:07 -04:00
Francis Lachapelle fd07112113 Merge pull request #31 from opensaucesystems/patch-1
Fix email validation regexp to allow gTLDs
2014-04-01 08:18:51 -04:00
opensaucesystems ce5d591d1d Fix email validation regexp to allow gTLDs
New generic TLDs can be as long as 13 characters.
2014-04-01 12:35:18 +01:00
Jeroen Dekkers e603742d71 Remove executable permission from jQuery 2014-03-29 17:11:05 +01:00
Ludovic Marcotte 585d224a15 Fixed the AS bundle common makefile 2014-03-28 16:44:33 -04:00
Ludovic Marcotte 6a39b48a37 Fix for bug #2691 2014-03-28 15:22:45 -04:00
Ludovic Marcotte 633723a470 Fix for bug #2681 2014-03-28 14:44:00 -04:00
Ludovic Marcotte ba32b95308 Fixed the ActiveSync issue marking mails as read when downloading them 2014-03-28 14:18:48 -04:00
Alexandre Cloutier 03d5975be3 Changed strings in french and change the instanciation of dictionary(addressBooksIDWithDisplayName) to release it manually 2014-03-28 10:28:33 -04:00
Alexandre Cloutier 1da1764aae The collected address book will be created only if the user select it in the preferences. Fix labels. 2014-03-27 15:27:48 -04:00
Francis Lachapelle 6e4f776d4b Fix detection of IMAP flags support in JavaScript
Fixes #2664
2014-03-27 12:06:24 -04:00
Alexandre Cloutier 365e271a84 Correct typo 2014-03-25 15:44:28 -04:00
Alexandre Cloutier bce701208a Added the modifications specified by extrafu 2014-03-25 14:53:42 -04:00
Alexandre Cloutier b16911edc1 Modified the displayed name of SOGo version and added the label in the .lproj 2014-03-24 13:55:52 -04:00
Alexandre Cloutier 76307cfaaf New feature : 1496; Unknown outgoing email addresses can now be automatically be added to your address books. 2014-03-24 13:41:57 -04:00
Francis Lachapelle e5fb7dc7b8 Fix JavaScript exception in Contacts module
Fixed calling unescapeHTML on null variables. Also fixed errors on IE7
(and possibly other versions).
2014-03-24 12:43:34 -04:00
Francis Lachapelle 50e7ea7188 Fix possible exception when retrieving reminder
Fixes #2678
2014-03-24 07:42:57 -04:00
Francis Lachapelle ae0c5eae77 Merge to 2.2.2 2014-03-21 15:39:00 -04:00
Ludovic Marcotte 89e61f6d5d Fixed SOPE include path 2014-03-21 15:37:14 -04:00
Francis Lachapelle 0c2d727057 Merge to 2.2.2 2014-03-21 15:33:55 -04:00
Francis Lachapelle 85f4af56e9 Update ChangeLog 2014-03-21 15:22:28 -04:00
Francis Lachapelle 04bdb22b00 Preparation for release 2.2.2 2014-03-21 15:20:45 -04:00
Ludovic Marcotte 874b1d9eba Added NEWS entry for previous commit 2014-03-21 14:08:53 -04:00
Ludovic Marcotte b143688419 Fix for bug #2669 2014-03-21 13:55:59 -04:00
Francis Lachapelle 5f3d2d988e Update translations 2014-03-21 13:51:36 -04:00
Francis Lachapelle 93f1540c17 Update jQuery File Upload to version 9.5.7 2014-03-21 13:47:40 -04:00
Francis Lachapelle 877e44c6d2 Update CKEditor to version 4.3.3 2014-03-21 13:32:28 -04:00
Ludovic Marcotte 4ca3d351e0 Fixed previous commit 2014-03-21 09:05:52 -04:00
Ludovic Marcotte 19b6704955 Only touch text/plain and text/html parts during Outlook sanitization 2014-03-21 09:02:39 -04:00
Francis Lachapelle 64787555ff Fix classification icon of events
Fixes #2664
2014-03-20 22:14:45 -04:00
Francis Lachapelle 27ffcf240f Fix handling of accents when filtering contacts
Fixes #2656
2014-03-20 15:29:32 -04:00
Francis Lachapelle 893d75bd5f Update Transifex configuration
Added new SoObjects/Mailer resource.
2014-03-20 14:18:03 -04:00
Ludovic Marcotte b0f26f1dcc Updated the doc regarding the isAddressBook parameter in sources. 2014-03-20 09:57:19 -04:00
Ludovic Marcotte a196ed210e Removed old values. 2014-03-19 17:04:04 -04:00
Ludovic Marcotte 1c28a4b4d2 Fixed translations for "OtherUsersFolderName" and "SharedFoldersName" (#2657) 2014-03-19 17:02:10 -04:00
Ludovic Marcotte fc56493b78 Added sanitization support for Outlook/ActiveSync 2014-03-19 11:44:36 -04:00
Ludovic Marcotte 3a33010918 Updated NEWS file regarding previous commit 2014-03-19 11:33:00 -04:00
Ludovic Marcotte 83bccda551 Avoid creating duplicates in Outlook on MoveItems (#2650) 2014-03-19 11:31:54 -04:00
Ludovic Marcotte 35d71f6150 Added deviceType capabilities to the code 2014-03-19 11:30:18 -04:00
Ludovic Marcotte e92a145325 Updated NEWS file regarding previous commit 2014-03-19 08:27:36 -04:00
Ludovic Marcotte c3062284e3 Disabled provisionning for now, as we don't support it. 2014-03-18 19:06:41 -04:00
Francis Lachapelle e2f192b793 Fix display of company/department of cards
Fixes #2662
2014-03-14 15:45:12 -04:00
Francis Lachapelle b8f239bf34 Fix construction of mail folders tree 2014-03-14 15:34:43 -04:00
Francis Lachapelle e968be8024 Bump version to 2.2.2 2014-03-14 13:02:27 -04:00
Francis Lachapelle 3c3bebeee3 Fix resource conflict check when creating event
Fixes #2541
2014-03-14 09:23:55 -04:00
Francis Lachapelle 26e9defdbd Update French translation 2014-03-14 09:17:52 -04:00
Francis Lachapelle 8742f28c29 Fix decoding of HTML entitities in reminder alert
Fixes #2659
2014-03-13 08:44:47 -04:00
Francis Lachapelle bd577fd513 Fix unseen count of folders beginning with a digit
Fixes #2652
2014-03-13 08:41:42 -04:00
Francis Lachapelle c8550c8a4a Fix copy/move to folder with numerical prefix
Fixes #2658
2014-03-12 16:35:22 -04:00
Ludovic Marcotte 1bdf88fb67 Don't try to delete an already non-existant object (#2653) 2014-03-11 13:21:05 -04:00
Alexandre Cloutier d108777e89 Display the version at the top of the general tap 2014-03-11 10:25:01 -04:00
Francis Lachapelle 167a06e3e9 Merge pull request #25 from dani/master
Disable file paste support in mail editor
Fixes #2641
2014-03-11 10:16:52 -04:00
Daniel B. af68f10115 Fix #2641
Disabling the pasteZone support (which only works in Chrome or Opera anyway) fixes the problem of unwanted PNG attachment when you paste the recipient list from Excel
2014-03-11 09:23:13 +01:00
Francis Lachapelle cbd22762c3 Fix possible exception when retrieving reminder
Fixes #2647
Fixes #2648
2014-03-10 14:47:01 -04:00
Alexandre Cloutier 8cc352fb28 It is now possible to see the version on the general page of the preferences window 2014-03-10 14:45:10 -04:00
Alexandre Cloutier 0d69a476bc add specific date for limiting the user to today's for his contact birthday 2014-03-10 12:16:12 -04:00
Alexandre Cloutier cee1e529f8 BugFix#1636; fix the issue where the user could add anything for the birthday of his contacts 2014-03-10 12:05:01 -04:00
Alexandre Cloutier 3a681bd5a5 Change the function name getClient to sieveClient 2014-03-10 10:53:44 -04:00
Alexandre Cloutier f5faa60814 Added missing functions getClient and IsSieveServerConnected and the changes that comes with it 2014-03-10 10:33:27 -04:00
Alexandre Cloutier f8939bfb3e Change the variable name for sieveFolderEncoding instead of folderEncoding 2014-03-10 10:07:47 -04:00
Ludovic Marcotte 78636f0396 Added default value for WOListenQueueSize 2014-03-09 15:58:11 -04:00
Ludovic Marcotte 037c2d3ddf Added documentation for WOListenQueueSize 2014-03-09 15:56:38 -04:00
Alexandre Cloutier f4d189ffc8 Erase the merging conflicts writings 2014-03-06 15:20:41 -05:00
Alexandre Cloutier 1b9ac03e94 BugFix #1046; Whenever the sieve server is unavailable an error message will appear. 2014-03-06 14:57:53 -05:00
Alexandre Cloutier 6ad87052ba bugFix #0002616 : change the behavior of ApplicationBaseURL. Now the object return a standard path(without a slash at the end of the path) That means every string added the URL ApplicationBaseURL must start with a Slash. 2014-03-06 14:47:54 -05:00
Alexandre Cloutier e7a16cba0d BugFix #0002622: The server Dovecot use by default an UTF-8 and by doing so it cause a wrong re-encoding in UTF-7 when reaching the sieve server (knowing that the foldername in sieve are encoded in UTF-7). Since it is not the case with a Cyrus server, I created a new variable available in the sogo.conf that let you specified the type of encoding you need. By default the encoding is set to UTF-7. ex : SOGoFolderEncoding = 'UTF-7' 2014-03-06 14:33:31 -05:00
382 changed files with 19624 additions and 7895 deletions

No files matched your search

+3
View File
@@ -1,6 +1,8 @@
config.make
tags
*._*
*/obj/
*._*
*/*/obj/
*/*/*/obj/
*/*/*.SOGo/
@@ -11,3 +13,4 @@ SoObjects/SOGo/SOGo.framework/
SoObjects/SOGo/derived_src/
Tests/*/config.py
*.pyc
._*
+26
View File
@@ -235,6 +235,32 @@ trans.sk = SoObjects/Contacts/Slovak.lproj/Localizable.strings
trans.sv = SoObjects/Contacts/Swedish.lproj/Localizable.strings
trans.uk = SoObjects/Contacts/Ukrainian.lproj/Localizable.strings
[sogo.soobjects-mailer]
source_file = SoObjects/Mailer/English.lproj/Localizable.strings
source_lang = en
trans.ar = SoObjects/Mailer/Arabic.lproj/Localizable.strings
trans.ca = SoObjects/Mailer/Catalan.lproj/Localizable.strings
trans.cs = SoObjects/Mailer/Czech.lproj/Localizable.strings
trans.cy = SoObjects/Mailer/Welsh.lproj/Localizable.strings
trans.da_DK = SoObjects/Mailer/Danish.lproj/Localizable.strings
trans.de = SoObjects/Mailer/German.lproj/Localizable.strings
trans.es_AR = SoObjects/Mailer/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = SoObjects/Mailer/SpanishSpain.lproj/Localizable.strings
trans.fi = SoObjects/Mailer/Finnish.lproj/Localizable.strings
trans.fr = SoObjects/Mailer/French.lproj/Localizable.strings
trans.hu = SoObjects/Mailer/Hungarian.lproj/Localizable.strings
trans.is = SoObjects/Mailer/Icelandic.lproj/Localizable.strings
trans.it = SoObjects/Mailer/Italian.lproj/Localizable.strings
trans.nb_NO = SoObjects/Mailer/NorwegianBokmal.lproj/Localizable.strings
trans.nl = SoObjects/Mailer/Dutch.lproj/Localizable.strings
trans.nn_NO = SoObjects/Mailer/NorwegianNynorsk.lproj/Localizable.strings
trans.pl = SoObjects/Mailer/Polish.lproj/Localizable.strings
trans.pt_BR = SoObjects/Mailer/BrazilianPortuguese.lproj/Localizable.strings
trans.ru = SoObjects/Mailer/Russian.lproj/Localizable.strings
trans.sk = SoObjects/Mailer/Slovak.lproj/Localizable.strings
trans.sv = SoObjects/Mailer/Swedish.lproj/Localizable.strings
trans.uk = SoObjects/Mailer/Ukrainian.lproj/Localizable.strings
[sogo.ui-mailpartviewers]
source_file = UI/MailPartViewers/English.lproj/Localizable.strings
source_lang = en
+7 -4
View File
@@ -9,28 +9,31 @@ ActiveSync_PRINCIPAL_CLASS = ActiveSyncProduct
ActiveSync_OBJC_FILES = \
ActiveSyncProduct.m \
iCalAlarm+ActiveSync.m \
iCalEvent+ActiveSync.m \
iCalRecurrenceRule+ActiveSync.m \
iCalTimeZone+ActiveSync.m \
iCalToDo+ActiveSync.m \
NSCalendarDate+ActiveSync.m \
NSCalendarDate+ActiveSync.m \
NSData+ActiveSync.m \
NSDate+ActiveSync.m \
NGDOMElement+ActiveSync.m \
NGMimeMessage+ActiveSync.m \
NGVCard+ActiveSync.m \
NSArray+SyncCache.m \
NSString+ActiveSync.m \
SOGoActiveSyncDispatcher.m \
SOGoActiveSyncDispatcher+Sync.m \
SOGoMailObject+ActiveSync.m \
SOGoMailObject+ActiveSync.m \
SOGoSyncCacheObject.m \
SoObjectWebDAVDispatcher+ActiveSync.m
ActiveSync_RESOURCE_FILES += \
product.plist
ADDITIONAL_OBJCFLAGS += -Wno-deprecated-declarations
ADDITIONAL_INCLUDE_DIRS += -I../../SOPE/ -I../SoObjects/
ADDITIONAL_LIB_DIRS += -L../../SOPE/GDLContentStore/obj/
ADDITIONAL_INCLUDE_DIRS += -I../SOPE/ -I../SoObjects/
ADDITIONAL_LIB_DIRS += -L../SOPE/GDLContentStore/obj/ -L../SOPE/NGCards/obj/
ADDITIONAL_INCLUDE_DIRS += -I/usr/include/libwbxml-1.0/
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed -lwbxml2
+39 -7
View File
@@ -37,6 +37,28 @@ static NSArray *asElementArray = nil;
@implementation NGDOMElement (ActiveSync)
- (BOOL) isTextNode
{
id <DOMNodeList> children;
id <DOMElement> element;
int i;
if ([self nodeType] == DOM_TEXT_NODE)
return YES;
children = [self childNodes];
for (i = 0; i < [children length]; i++)
{
element = [children objectAtIndex: i];
if ([element nodeType] != DOM_TEXT_NODE)
return NO;
}
return YES;
}
//
// We must handle "inner data" like this:
//
@@ -79,7 +101,7 @@ static NSArray *asElementArray = nil;
int i, count;
if (!asElementArray)
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", nil];
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", @"Category", nil];
data = [NSMutableDictionary dictionary];
@@ -96,9 +118,17 @@ static NSArray *asElementArray = nil;
tag = [element tagName];
count = [(NSArray *)[element childNodes] count];
// We check if the node is a text one or if all its
// children are text nodes. This is important to avoid side-effects
// in SOPE where "foo & bar" would result into 3 childnodes instead
// of just one.
if ([(id)element isTextNode])
{
value = [(id)element textValue];
}
// Handle inner data - see above for samples
if (count > 2)
else
{
NSMutableArray *innerElements;
id <DOMElement> innerElement;
@@ -123,7 +153,10 @@ static NSArray *asElementArray = nil;
if ([innerTag isEqualToString: [innerElement tagName]])
{
[innerElements addObject: [(NGDOMElement *)innerElement applicationData]];
if ([(id)innerElement isTextNode])
[innerElements addObject: [(NGDOMElement *)innerElement textValue]];
else
[innerElements addObject: [(NGDOMElement *)innerElement applicationData]];
}
else
{
@@ -144,12 +177,11 @@ static NSArray *asElementArray = nil;
value = nil;
}
}
else
value = [[element firstChild] textValue];
if (value && tag)
[data setObject: value forKey: tag];
}
} // if ([element nodeType] == DOM_ELEMENT_NODE)
}
return data;
+67 -15
View File
@@ -40,6 +40,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Contacts/NGVCard+SOGo.h>
#import <SOGo/NSString+Utilities.h>
#include "NSDate+ActiveSync.h"
#include "NSString+ActiveSync.h"
@@ -47,9 +49,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSArray *emails, *addresses, *categories, *elements;
CardElement *n, *homeAdr, *workAdr;
NSArray *emails, *addresses;
NSMutableString *s;
NSString *url;
id o;
int i;
@@ -65,10 +68,42 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ((o = [self workCompany]))
[s appendFormat: @"<CompanyName xmlns=\"Contacts:\">%@</CompanyName>", [o activeSyncRepresentationInContext: context]];
if ((o = [[self org] flattenedValueAtIndex: 1 forKey: @""]))
[s appendFormat: @"<Department xmlns=\"Contacts:\">%@</Department>", [o activeSyncRepresentationInContext: context]];
categories = [self categories];
if ([categories count])
{
[s appendFormat: @"<Categories xmlns=\"Contacts:\">"];
for (i = 0; i < [categories count]; i++)
{
[s appendFormat: @"<Category xmlns=\"Contacts:\">%@</Category>", [[categories objectAtIndex: i] activeSyncRepresentationInContext: context]];
}
[s appendFormat: @"</Categories>"];
}
elements = [self childrenWithTag: @"url"
andAttribute: @"type"
havingValue: @"work"];
if ([elements count] > 0)
{
url = [[elements objectAtIndex: 0] flattenedValuesForKey: @""];
[s appendFormat: @"<WebPage xmlns=\"Contacts:\">%@</WebPage>", [url activeSyncRepresentationInContext: context]];
}
if ((o = [[self uniqueChildWithTag: @"x-aim"] flattenedValuesForKey: @""]))
[s appendFormat: @"<IMAddress xmlns=\"Contacts:\">%@</IMAddress>", [o activeSyncRepresentationInContext: context]];
if ((o = [self nickname]))
[s appendFormat: @"<NickName xmlns=\"Contacts:\">%@</NickName>", [o activeSyncRepresentationInContext: context]];
if ((o = [self title]))
[s appendFormat: @"<JobTitle xmlns=\"Contacts:\">%@</JobTitle>", [o activeSyncRepresentationInContext: context]];
if ((o = [self preferredEMail]))
[s appendFormat: @"<Email1Address xmlns=\"Contacts:\">%@</Email1Address>", o];
@@ -154,7 +189,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Other, less important fields
if ((o = [self birthday]))
[s appendFormat: @"<Birthday xmlns=\"Contacts:\">%@</Birthday>", [o activeSyncRepresentationWithoutSeparatorsInContext: context]];
[s appendFormat: @"<Birthday xmlns=\"Contacts:\">%@</Birthday>", [o activeSyncRepresentationInContext: context]];
if ((o = [self note]))
{
@@ -166,6 +201,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
if ((o = [self photo]))
[s appendFormat: @"<Picture xmlns=\"Contacts:\">%@</Picture>", o];
return s;
}
@@ -183,6 +221,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setNote: o];
// Categories
if ((o = [theValues objectForKey: @"Categories"]))
[self setCategories: o];
// Birthday
if ((o = [theValues objectForKey: @"Birthday"]))
{
@@ -238,24 +280,31 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Company's name
if ((o = [theValues objectForKey: @"CompanyName"]))
{
[self setOrg: o units: nil];
}
[self setOrg: o units: nil];
// Department
if ((o = [theValues objectForKey: @"Department"]))
[self setOrg: nil units: [NSArray arrayWithObjects:o,nil]];
// Email addresses
if ((o = [theValues objectForKey: @"Email1Address"]))
{
[self addEmail: o types: [NSArray arrayWithObject: @"pref"]];
element = [self elementWithTag: @"email" ofType: @"work"];
[element setSingleValue: [o pureEMailAddress] forKey: @""];
}
if ((o = [theValues objectForKey: @"Email2Address"]))
{
[self addEmail: o types: nil];
element = [self elementWithTag: @"email" ofType: @"home"];
[element setSingleValue: [o pureEMailAddress] forKey: @""];
}
// SOGo currently only supports 2 email addresses ... but AS clients might send 3
// FIXME: revise this when the GUI revamp is done in SOGo
if ((o = [theValues objectForKey: @"Email3Address"]))
{
[self addEmail: o types: nil];
element = [self elementWithTag: @"email" ofType: @"three"];
[element setSingleValue: [o pureEMailAddress] forKey: @""];
}
// Formatted name
@@ -293,16 +342,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Job's title
if ((o = [theValues objectForKey: @"JobTitle"]))
{
[self setTitle: o];
}
[self setTitle: o];
// WebPage (work)
if ((o = [theValues objectForKey: @"WebPage"]))
{
[[self elementWithTag: @"url" ofType: @"work"]
[[self elementWithTag: @"url" ofType: @"work"]
setSingleValue: o forKey: @""];
}
if ((o = [theValues objectForKey: @"NickName"]))
[self setNickname: o];
if ((o = [theValues objectForKey: @"Picture"]))
[self setPhoto: o];
}
@end
+49
View File
@@ -0,0 +1,49 @@
/*
Copyright (c) 2014, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Inverse inc. nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __NSARRAYSYNCCACHE_H__
#define __NSARRAYSYNCCACHE_H__
#import <Foundation/NSArray.h>
@class NSDictionary;
@interface NSMutableArray (SyncCache)
- (id) initWithDictionary: (NSDictionary *) theDictionary;
@end
@interface NSArray (SyncCache)
- (NSDictionary *) dictionaryValue;
@end
#endif
+84
View File
@@ -0,0 +1,84 @@
/*
Copyright (c) 2014, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Inverse inc. nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "NSArray+SyncCache.h"
#import <Foundation/NSDictionary.h>
#include "SOGoSyncCacheObject.h"
@implementation NSMutableArray (SyncCache)
- (id) initWithDictionary: (NSDictionary *) theDictionary
{
SOGoSyncCacheObject *o;
NSArray *allKeys;
id key;
int i;
self = [self initWithCapacity: [theDictionary count]];
allKeys = [theDictionary allKeys];
for (i = 0; i < [allKeys count]; i++)
{
key = [allKeys objectAtIndex: i];
o = [SOGoSyncCacheObject syncCacheObjectWithUID: key
sequence: [theDictionary objectForKey: key]];
[self addObject: o];
}
return self;
}
@end
//
//
//
@implementation NSArray (SyncCache)
- (NSDictionary *) dictionaryValue
{
NSMutableDictionary *d;
SOGoSyncCacheObject *o;
int i;
d = [NSMutableDictionary dictionary];
for (i = 0; i < [self count]; i++)
{
o = [self objectAtIndex: i];
[d setObject: [o sequence] forKey: [o uid]];
}
return d;
}
@end
+2
View File
@@ -46,6 +46,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSString *) realCollectionIdWithFolderType: (SOGoMicrosoftActiveSyncFolderType *) folderType;
- (NSCalendarDate *) calendarDate;
- (NSString *) deviceId;
- (NSString *) deviceType;
- (NSString *) attachmentName;
- (NSString *) command;
- (NSData *) convertHexStringToBytes;
+35 -1
View File
@@ -139,7 +139,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NSString *s;
int i;
components = [[[self componentsSeparatedByString: @"/"] lastObject] componentsSeparatedByString: @"&"];
components = [[[self componentsSeparatedByString: @"?"] lastObject] componentsSeparatedByString: @"&"];
for (i = 0; i < [components count]; i++)
{
@@ -169,6 +169,40 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
return s;
}
//
// This method extracts the "DeviceType" from a URI:
//
// /SOGo/Microsoft-Server-ActiveSync?Cmd=FolderSync&User=sogo10&DeviceId=SEC17CD1A3E9E3F2&DeviceType=SAMSUNGSGHI317M
//
- (NSString *) deviceType
{
NSString *s;
s = [self _valueForParameter: @"DEVICETYPE="];
if (!s)
s = @"Unknown";
return s;
}
// This method extracts the "AttachmentName" from a URI:
//
// /SOGo/Microsoft-Server-ActiveSync?Cmd=GetAttachment&User=sogo&DeviceId=HTCa04b4932597acd3f2dc1a918b9728&DeviceType=htcvision&AttachmentName=mail/TestFldr/8/2
//
- (NSString *) attachmentName
{
NSString *s;
s = [self _valueForParameter: @"ATTACHMENTNAME="];
if (!s)
s = @"Unknown";
return s;
}
//
//
//
+292 -84
View File
@@ -32,9 +32,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSNull.h>
#import <Foundation/NSProcessInfo.h>
#import <Foundation/NSTimeZone.h>
#import <Foundation/NSURL.h>
#import <Foundation/NSValue.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/SoApplication.h>
@@ -58,18 +60,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGImap4/NSString+Imap4.h>
#import <NGMime/NGMimeBodyPart.h>
#import <NGMime/NGMimeMultipartBody.h>
#import <NGMail/NGMimeMessageParser.h>
#import <NGMail/NGMimeMessage.h>
#import <NGMail/NGMimeMessageGenerator.h>
#import <DOM/DOMElement.h>
#import <DOM/DOMProtocols.h>
#import <EOControl/EOQualifier.h>
#import <SOGo/NSArray+DAV.h>
#import <SOGo/SOGoCache.h>
#import <SOGo/NSDictionary+DAV.h>
#import <SOGo/SOGoDAVAuthenticator.h>
#import <SOGo/SOGoDomainDefaults.h>
@@ -77,6 +74,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <SOGo/SOGoSystemDefaults.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserSettings.h>
#import <SOGo/SOGoCacheGCSObject.h>
#import <Appointments/SOGoAppointmentObject.h>
#import <Appointments/SOGoAppointmentFolder.h>
@@ -106,11 +104,50 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "NSString+ActiveSync.h"
#include "SOGoActiveSyncConstants.h"
#include "SOGoMailObject+ActiveSync.h"
#include "SOGoSyncCacheObject.h"
#include <unistd.h>
@implementation SOGoActiveSyncDispatcher (Sync)
- (void) _setFolderMetadata: (NSDictionary *) theFolderMetadata
forKey: (NSString *) theFolderKey
{
SOGoCacheGCSObject *o;
NSString *key;
key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], theFolderKey];
o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
[o setObjectType: ActiveSyncFolderCacheObject];
[o setTableUrl: [self folderTableURL]];
[o reloadIfNeeded];
[[o properties] removeObjectForKey: @"SyncKey"];
[[o properties] removeObjectForKey: @"SyncCache"];
[[o properties] removeObjectForKey: @"DateCache"];
[[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] addEntriesFromDictionary: theFolderMetadata];
[o save];
}
- (NSMutableDictionary *) _folderMetadataForKey: (NSString *) theFolderKey
{
SOGoCacheGCSObject *o;
NSString *key;
key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], theFolderKey];
o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
[o setObjectType: ActiveSyncFolderCacheObject];
[o setTableUrl: [self folderTableURL]];
[o reloadIfNeeded];
return [o properties];
}
//
// <?xml version="1.0"?>
// <!DOCTYPE ActiveSync PUBLIC "-//MICROSOFT//DTD ActiveSync//EN" "http://www.microsoft.com/">
@@ -392,7 +429,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inContext: context
acquire: NO];
[sogoObject delete];
if (![sogoObject isKindOfClass: [NSException class]])
[sogoObject delete];
}
}
}
@@ -427,7 +465,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[theBuffer appendString: @"</Fetch>"];
}
//
// The method handles <GetChanges/>
//
@@ -441,19 +478,70 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
lastServerKey: (NSString **) theLastServerKey
{
NSMutableDictionary *folderMetadata, *dateCache, *syncCache;
NSMutableString *s;
BOOL more_available;
int i, max;
s = [NSMutableString string];
more_available = NO;
if (theFolderType == ActiveSyncMailFolder && !([theSyncKey isEqualToString: @"-1"]) && theFilterType)
{
NSArray *allKeys;
NSString *key;
int softdelete_count;
softdelete_count = 0;
folderMetadata = [self _folderMetadataForKey: [theCollection nameInContainer]];
dateCache = [folderMetadata objectForKey: @"DateCache"];
syncCache = [folderMetadata objectForKey: @"SyncCache"];
allKeys = [dateCache allKeys];
for (i = 0; i < [allKeys count]; i++)
{
key = [allKeys objectAtIndex: i];
if ([[dateCache objectForKey:key] compare: theFilterType] == NSOrderedAscending)
{
[s appendString: @"<SoftDelete xmlns=\"AirSync:\">"];
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", key];
[s appendString: @"</SoftDelete>"];
[syncCache removeObjectForKey: key];
[dateCache removeObjectForKey: key];
softdelete_count++;
}
if (softdelete_count >= theWindowSize)
{
[folderMetadata setObject: [NSNumber numberWithBool: YES] forKey: @"MoreAvailable"];
[self _setFolderMetadata: folderMetadata forKey: [theCollection nameInContainer]];
more_available = YES;
*theLastServerKey = theSyncKey;
// Since WindowSize is reached don't even try to add more to the response, let's just
// jump to the end and return the response immediately
goto return_response;
}
}
[folderMetadata removeObjectForKey: @"MoreAvailable"];
[self _setFolderMetadata: folderMetadata forKey: [theCollection nameInContainer]];
}
//
// No changes in the collection - 2.2.2.19.1.1 Empty Sync Request.
// We check this and we don't generate any commands if we don't have to.
//
if ([theSyncKey isEqualToString: [theCollection davCollectionTag]])
if ([theSyncKey isEqualToString: [theCollection davCollectionTag]] && !([s length]))
return;
s = [NSMutableString string];
more_available = NO;
switch (theFolderType)
@@ -566,100 +654,209 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendString: @"</Add>"];
}
} // for ...
folderMetadata = [NSDictionary dictionaryWithObject: [theCollection davCollectionTag]
forKey: @"SyncKey"];
[self _setFolderMetadata: folderMetadata
forKey: [NSString stringWithFormat: @"%@/%@", component_name, [theCollection nameInContainer]]];
}
break;
case ActiveSyncMailFolder:
default:
{
NSMutableArray *addedOrChangedMessages;
SOGoSyncCacheObject *lastCacheObject, *aCacheObject;
NSMutableArray *allCacheObjects, *sortedBySequence;
SOGoMailObject *mailObject;
NSString *uid, *command;
NSDictionary *aMessage;
NSArray *allMessages;
int deleted_count;
int j, k, return_count;
BOOL found_in_cache;
allMessages = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType];
addedOrChangedMessages = [NSMutableArray array];
deleted_count = 0;
// Check for the WindowSize.
// FIXME: we should eventually check for modseq and slice the maximum
// amount of messages returned to ensure we don't have the same
// modseq accross contiguous boundaries
max = [allMessages count];
// We first check the number of deleted messages we have
// We do NOT honor the window size here as it seems to be
// impossible to get the modseq of an expunged message so
// we can't iterate in the list of deleted messages.
for (i = 0; i < max; i++)
{
aMessage = [allMessages objectAtIndex: i];
uid = [[[aMessage allKeys] lastObject] stringValue];
command = [[aMessage allValues] lastObject];
if ([command isEqualToString: @"deleted"])
{
[s appendString: @"<Delete xmlns=\"AirSync:\">"];
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", uid];
[s appendString: @"</Delete>"];
deleted_count++;
}
else
{
[addedOrChangedMessages addObject: aMessage];
}
}
// We then "pad" with our added/changed messages. We ALWAYS
// at least return one if available
max = [addedOrChangedMessages count];
allCacheObjects = [NSMutableArray array];
for (i = 0; i < max; i++)
{
aMessage = [addedOrChangedMessages objectAtIndex: i];
uid = [[[aMessage allKeys] lastObject] stringValue];
command = [[aMessage allValues] lastObject];
if ([command isEqualToString: @"added"])
[s appendString: @"<Add xmlns=\"AirSync:\">"];
else
[s appendString: @"<Change xmlns=\"AirSync:\">"];
mailObject = [theCollection lookupName: uid
inContext: context
acquire: 0];
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", uid];
[s appendString: @"<ApplicationData xmlns=\"AirSync:\">"];
[s appendString: [mailObject activeSyncRepresentationInContext: context]];
[s appendString: @"</ApplicationData>"];
if ([command isEqualToString: @"added"])
[s appendString: @"</Add>"];
else
[s appendString: @"</Change>"];
// We check if we must stop padding
if (i+1+deleted_count > theWindowSize)
[allCacheObjects addObject: [SOGoSyncCacheObject syncCacheObjectWithUID: [[[allMessages objectAtIndex: i] allKeys] lastObject]
sequence: [[[allMessages objectAtIndex: i] allValues] lastObject]]];
}
// If it's a new Sync operation, DateCache and SyncCache need to be deleted
// but GUID stored by folderSync shouldn't be touched
folderMetadata = [self _folderMetadataForKey: [theCollection nameInContainer]];
if ([theSyncKey isEqualToString: @"-1"])
{
[folderMetadata setObject: [NSMutableDictionary dictionary] forKey: @"SyncCache"];
[folderMetadata setObject: [NSMutableDictionary dictionary] forKey: @"DateCache"];
}
// Check whether GUID in cache is equal to the GUID from imap - this is to avoid cache corruptions if a folder has been renamed and a new folder
// with the same name has been created but folderSync has not yet updated the cache
if (!([[theCollection nameInContainer] isEqualToString:
[NSString stringWithFormat: @"folder%@", [self globallyUniqueIDToIMAPFolderName: [folderMetadata objectForKey: @"GUID"] type: theFolderType]]]))
{
NSLog(@"GUID mismatch don't sync now!");
return;
}
syncCache = [folderMetadata objectForKey: @"SyncCache"];
dateCache = [folderMetadata objectForKey: @"DateCache"];
sortedBySequence = [[NSMutableArray alloc] initWithDictionary: syncCache];
[sortedBySequence sortUsingSelector: @selector(compareSequence:)];
[sortedBySequence autorelease];
[allCacheObjects sortUsingSelector: @selector(compareSequence:)];
//NSLog(@"sortedBySequence (%d) - lastObject: %@", [sortedBySequence count], [sortedBySequence lastObject]);
//NSLog(@"allCacheObjects (%d) - lastObject: %@", [allCacheObjects count], [allCacheObjects lastObject]);
lastCacheObject = [sortedBySequence lastObject];
if ([folderMetadata objectForKey: @"MoreAvailable"] && lastCacheObject)
{
for (j = 0; j < [allCacheObjects count]; j++)
{
more_available = YES;
break;
if ([[lastCacheObject uid] isEqual: [[allCacheObjects objectAtIndex: j] uid]])
{
// Found out where we're at, let's continue from there...
found_in_cache = YES;
break;
}
}
}
//
else
found_in_cache = NO;
if (found_in_cache)
k = j+1;
else
{
k = 0;
j = 0;
}
//NSLog(@"found in cache: %d k = %d", found_in_cache, k);
return_count = 0;
for (; k < [allCacheObjects count]; k++)
{
// Check for the WindowSize and slice accordingly
if (return_count >= theWindowSize)
{
NSString *lastSequence;
more_available = YES;
lastSequence = ([[aCacheObject sequence] isEqual: [NSNull null]] ? @"1" : [aCacheObject sequence]);
*theLastServerKey = [NSString stringWithFormat: @"%@-%@", [aCacheObject uid], lastSequence];
//NSLog(@"Reached windowSize - lastUID will be: %@", *theLastServerKey);
break;
}
aCacheObject = [allCacheObjects objectAtIndex: k];
// If found in cache, it's either a Change or a Delete
if ([syncCache objectForKey: [aCacheObject uid]])
{
if ([[aCacheObject sequence] isEqual: [NSNull null]])
{
// Deleted
[s appendString: @"<Delete xmlns=\"AirSync:\">"];
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", [aCacheObject uid]];
[s appendString: @"</Delete>"];
[syncCache removeObjectForKey: [aCacheObject uid]];
[dateCache removeObjectForKey: [aCacheObject uid]];
}
else
{
// Changed
outlook_hack:
mailObject = [theCollection lookupName: [aCacheObject uid]
inContext: context
acquire: 0];
[s appendString: @"<Change xmlns=\"AirSync:\">"];
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", [aCacheObject uid]];
[s appendString: @"<ApplicationData xmlns=\"AirSync:\">"];
[s appendString: [mailObject activeSyncRepresentationInContext: context]];
[s appendString: @"</ApplicationData>"];
[s appendString: @"</Change>"];
[syncCache setObject: [aCacheObject sequence] forKey: [aCacheObject uid]];
}
return_count++;
}
else
{
// Added
if (![[aCacheObject sequence] isEqual: [NSNull null]])
{
NSString *key;
// We check for Outlook stupidity to avoid creating duplicates - see the comment
// in SOGoActiveSyncDispatcher.m: -processMoveItems:inResponse: for more details.
key = [NSString stringWithFormat: @"%@+%@+%@+%@",
[[context activeUser] login],
[context objectForKey: @"DeviceType"],
[theCollection displayName],
[aCacheObject uid]];
if ([[SOGoCache sharedCache] valueForKey: key])
{
[[SOGoCache sharedCache] removeValueForKey: key];
goto outlook_hack;
}
mailObject = [theCollection lookupName: [aCacheObject uid]
inContext: context
acquire: 0];
[s appendString: @"<Add xmlns=\"AirSync:\">"];
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", [aCacheObject uid]];
[s appendString: @"<ApplicationData xmlns=\"AirSync:\">"];
[s appendString: [mailObject activeSyncRepresentationInContext: context]];
[s appendString: @"</ApplicationData>"];
[s appendString: @"</Add>"];
[syncCache setObject: [aCacheObject sequence] forKey: [aCacheObject uid]];
[dateCache setObject: [NSCalendarDate date] forKey: [aCacheObject uid]];
return_count++;
}
else
{
//NSLog(@"skipping old deleted UID: %@", [aCacheObject uid]);
}
}
}
if (more_available)
{
*theLastServerKey = uid;
[folderMetadata setObject: [NSNumber numberWithBool: YES] forKey: @"MoreAvailable"];
[folderMetadata setObject: *theLastServerKey forKey: @"SyncKey"];
}
}
else
{
[folderMetadata removeObjectForKey: @"MoreAvailable"];
[folderMetadata setObject: [theCollection davCollectionTag] forKey: @"SyncKey"];
}
[self _setFolderMetadata: folderMetadata
forKey: [theCollection nameInContainer]];
} // default:
break;
} // switch (folderType) ...
return_response:
if ([s length])
{
[theBuffer appendString: @"<Commands>"];
@@ -757,13 +954,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NSMutableString *changeBuffer, *commandsBuffer;
BOOL getChanges, first_sync;
unsigned int windowSize;
unsigned int windowSize, v;
changeBuffer = [NSMutableString string];
commandsBuffer = [NSMutableString string];
collectionId = [[(id)[theDocumentElement getElementsByTagName: @"CollectionId"] lastObject] textValue];
realCollectionId = [collectionId realCollectionIdWithFolderType: &folderType];
realCollectionId = [self globallyUniqueIDToIMAPFolderName: realCollectionId type: folderType];
collection = [self collectionFromId: realCollectionId type: folderType];
syncKey = davCollectionTag = [[(id)[theDocumentElement getElementsByTagName: @"SyncKey"] lastObject] textValue];
@@ -773,6 +971,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (windowSize == 0 || windowSize > 512)
windowSize = 100;
// We check if we must overwrite the windowSize with a system preference. This can be useful
// if the user population has large mailboxes and slow connectivity
if ((v = [[SOGoSystemDefaults sharedSystemDefaults] maximumSyncWindowSize]))
windowSize = v;
lastServerKey = nil;
@@ -845,12 +1048,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ([changeBuffer length] || [commandsBuffer length])
{
if (lastServerKey)
davCollectionTag = [collection davCollectionTagFromId: lastServerKey];
else
davCollectionTag = lastServerKey;
else if (![[self _folderMetadataForKey: [collection nameInContainer]] objectForKey: @"MoreAvailable"])
davCollectionTag = [collection davCollectionTag];
*changeDetected = YES;
}
else
{
if (folderType == ActiveSyncMailFolder && [syncKey isEqualToString: @"-1"])
davCollectionTag = [collection davCollectionTag];
}
// Generate the response buffer
[theBuffer appendString: @"<Collection>"];
+8
View File
@@ -32,17 +32,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "SOGoActiveSyncConstants.h"
@class NSException;
@class NSURL;
@interface SOGoActiveSyncDispatcher : NSObject
{
NSURL *folderTableURL;
id context;
}
- (id) collectionFromId: (NSString *) theCollectionId
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType;
- (id) globallyUniqueIDToIMAPFolderName: (NSString *) theIdToTranslate
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType;
- (NSException *) dispatchRequest: (id) theRequest
inResponse: (id) theResponse
context: (id) theContext;
- (NSURL *) folderTableURL;
- (void) ensureFolderTableExists;
@end
File diff suppressed because it is too large. Load diff
+227 -21
View File
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "SOGoMailObject+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
@@ -42,12 +43,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGCards/iCalTimeZone.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NGQuotedPrintableCoding.h>
#import <NGExtensions/NSString+misc.h>
#import <NGExtensions/NSString+Encoding.h>
#import <NGImap4/NGImap4Envelope.h>
#import <NGImap4/NGImap4EnvelopeAddress.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGMime/NGMimeBodyPart.h>
#import <NGMime/NGMimeFileData.h>
#import <NGMime/NGMimeMultipartBody.h>
#import <NGMime/NGMimeType.h>
#import <NGMail/NGMimeMessageParser.h>
#import <NGMail/NGMimeMessage.h>
#import <NGMail/NGMimeMessageGenerator.h>
#include "iCalTimeZone+ActiveSync.h"
#include "NSData+ActiveSync.h"
#include "NSDate+ActiveSync.h"
@@ -196,7 +206,7 @@ struct GlobalObjectId {
//
- (NSData *) _preferredBodyDataInMultipartUsingType: (int) theType
{
NSString *key, *plainKey, *htmlKey, *type, *subtype;
NSString *encoding, *key, *plainKey, *htmlKey, *type, *subtype;
NSDictionary *textParts, *part;
NSEnumerator *e;
NSData *d;
@@ -219,18 +229,156 @@ struct GlobalObjectId {
plainKey = key;
}
key = nil;
if (theType == 2)
{
d = [[self fetchPlainTextParts] objectForKey: htmlKey];
}
key = htmlKey;
else if (theType == 1)
key = plainKey;
if (key)
{
d = [[self fetchPlainTextParts] objectForKey: plainKey];
NSString *s, *charset;
d = [[self fetchPlainTextParts] objectForKey: key];
encoding = [[self lookupInfoForBodyPart: key] objectForKey: @"encoding"];
if ([encoding caseInsensitiveCompare: @"base64"] == NSOrderedSame)
d = [d dataByDecodingBase64];
else if ([encoding caseInsensitiveCompare: @"quoted-printable"] == NSOrderedSame)
d = [d dataByDecodingQuotedPrintableTransferEncoding];
charset = [[[self lookupInfoForBodyPart: key] objectForKey: @"parameterList"] objectForKey: @"charset"];
if (![charset length])
charset = @"us-ascii";
s = [NSString stringWithData: d usingEncodingNamed: charset];
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
return d;
}
//
//
//
- (void) _sanitizedMIMEPart: (id) thePart
performed: (BOOL *) b
{
if ([thePart isKindOfClass: [NGMimeMultipartBody class]])
{
NGMimeBodyPart *part;
NSArray *parts;
int i;
parts = [thePart parts];
for (i = 0; i < [parts count]; i++)
{
part = [parts objectAtIndex: i];
[self _sanitizedMIMEPart: part
performed: b];
}
}
else if ([thePart isKindOfClass: [NGMimeBodyPart class]])
{
NGMimeFileData *fdata;
id body;
body = [thePart body];
if ([body isKindOfClass: [NGMimeMultipartBody class]])
{
[self _sanitizedMIMEPart: body
performed: b];
}
else if (([body isKindOfClass: [NSData class]] || [body isKindOfClass: [NSString class]]) &&
[[[thePart contentType] type] isEqualToString: @"text"] &&
([[[thePart contentType] subType] isEqualToString: @"plain"] || [[[thePart contentType] subType] isEqualToString: @"html"]))
{
// We make sure everything is encoded in UTF-8
NGMimeType *mimeType;
NSString *s;
if ([body isKindOfClass: [NSData class]])
{
NSString *charset;
charset = [[thePart contentType] valueOfParameter: @"charset"];
if (![charset length])
charset = @"us-ascii";
s = [NSString stringWithData: body usingEncodingNamed: charset];
}
else
{
// Handle situations when SOPE stupidly returns us a NSString
// This can happen for Content-Type: text/plain, Content-Transfer-Encoding: 8bit
s = body;
}
if (s)
{
body = [s dataUsingEncoding: NSUTF8StringEncoding];
}
mimeType = [NGMimeType mimeType: [[thePart contentType] type]
subType: [[thePart contentType] subType]
parameters: [NSDictionary dictionaryWithObject: @"utf-8" forKey: @"charset"]];
[thePart setHeader: mimeType forKey: @"content-type"];
fdata = [[NGMimeFileData alloc] initWithBytes: [body bytes]
length: [body length]];
[thePart setBody: fdata];
RELEASE(fdata);
*b = YES;
}
}
}
//
//
//
- (NSData *) _sanitizedMIMEMessage
{
NGMimeMessageParser *parser;
NGMimeMessage *message;
NSData *d;
BOOL b;
d = [self content];
parser = [[NGMimeMessageParser alloc] init];
AUTORELEASE(parser);
message = [parser parsePartFromData: d];
b = NO;
if (message)
{
[self _sanitizedMIMEPart: [message body]
performed: &b];
if (b)
{
NGMimeMessageGenerator *generator;
generator = [[NGMimeMessageGenerator alloc] init];
AUTORELEASE(generator);
d = [generator generateMimeFromPart: message];
}
}
return d;
}
//
//
//
@@ -258,6 +406,13 @@ struct GlobalObjectId {
{
if ([type isEqualToString: @"text"])
{
NSString *s, *charset;
charset = [[[self lookupInfoForBodyPart: @""] objectForKey: @"parameterList"] objectForKey: @"charset"];
if (![charset length])
charset = @"us-ascii";
d = [[self fetchPlainTextParts] objectForKey: @""];
// We check if we have base64 encoded parts. If so, we just
@@ -266,18 +421,18 @@ struct GlobalObjectId {
if ([encoding caseInsensitiveCompare: @"base64"] == NSOrderedSame)
d = [d dataByDecodingBase64];
else if ([encoding caseInsensitiveCompare: @"quoted-printable"] == NSOrderedSame)
d = [d dataByDecodingQuotedPrintableTransferEncoding];
s = [NSString stringWithData: d usingEncodingNamed: charset];
// Check if we must convert html->plain
if (theType == 1 && [subtype isEqualToString: @"html"])
{
NSString *s;
s = [[NSString alloc] initWithData: d encoding: NSUTF8StringEncoding];
AUTORELEASE(s);
s = [s htmlToText];
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
else if ([type isEqualToString: @"multipart"])
{
@@ -286,7 +441,12 @@ struct GlobalObjectId {
}
else if (theType == 4)
{
d = [self content];
// We sanitize the content *ONLY* for Outlook clients. Outlook has strange issues
// with quoted-printable/base64 encoded text parts. It just doesn't decode them.
if ([[context objectForKey: @"DeviceType"] isEqualToString: @"WindowsOutlook15"])
d = [self _sanitizedMIMEMessage];
else
d = [self content];
}
return d;
@@ -346,7 +506,9 @@ struct GlobalObjectId {
//
- (NSString *) activeSyncRepresentationInContext: (WOContext *) _context
{
NSAutoreleasePool *pool;
NSData *d, *globalObjId;
NSArray *attachmentKeys;
NSMutableString *s;
id value;
@@ -531,11 +693,16 @@ struct GlobalObjectId {
// [s appendFormat: @"<Reply-To xmlns=\"Email:\">%@</Reply-To>", [addressFormatter stringForArray: replyTo]];
// InternetCPID - 65001 == UTF-8, we use this all the time for now.
// - 20127 == US-ASCII
[s appendFormat: @"<InternetCPID xmlns=\"Email:\">%@</InternetCPID>", @"65001"];
// Body - namespace 17
preferredBodyType = [[context objectForKey: @"BodyPreferenceType"] intValue];
// Make use of a local pool here as _preferredBodyDataUsingType:nativeType: will consume
// a significant amout of RAM and file descriptors
pool = [[NSAutoreleasePool alloc] init];
nativeBodyType = 1;
d = [self _preferredBodyDataUsingType: preferredBodyType nativeType: &nativeBodyType];
@@ -549,6 +716,10 @@ struct GlobalObjectId {
// FIXME: This is a hack. We should normally avoid doing this as we might get
// broken encodings. We should rather tell that the data was truncated and expect
// a ItemOperations call to download the whole base64 encoding multipart.
//
// See http://social.msdn.microsoft.com/Forums/en-US/b9944e49-9bc9-4ab8-ba33-a9fc08557c5b/mime-raw-data-in-eas-sync-response?forum=os_exchangeprotocols
// for an "interesting" discussion around this.
//
if (!content)
content = [[NSString alloc] initWithData: d encoding: NSISOLatin1StringEncoding];
@@ -561,15 +732,21 @@ struct GlobalObjectId {
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", preferredBodyType];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", len];
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
[s appendFormat: @"<Truncated>%d</Truncated>", truncated];
[s appendFormat: @"<Preview></Preview>"];
if (!truncated)
[s appendFormat: @"<Data>%@</Data>", content];
{
[s appendFormat: @"<Data>%@</Data>", content];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", len];
}
[s appendString: @"</Body>"];
}
DESTROY(pool);
// Attachments -namespace 16
NSArray *attachmentKeys = [self fetchFileAttachmentKeys];
attachmentKeys = [self fetchFileAttachmentKeys];
if ([attachmentKeys count])
{
int i;
@@ -599,7 +776,7 @@ struct GlobalObjectId {
// Flags
[s appendString: @"<Flag xmlns=\"Email:\">"];
[s appendFormat: @"<FlagStatus>%d</FlagStatus>", 0];
[s appendFormat: @"<FlagStatus>%d</FlagStatus>", ([self flagged] ? 2 : 0)];
[s appendString: @"</Flag>"];
// FIXME - support these in the future
@@ -620,6 +797,16 @@ struct GlobalObjectId {
//
//
//
// Exemple for a message being marked as read:
//
// <Change>
// <ServerId>607</ServerId>
// <ApplicationData>
// <Read xmlns="Email:">1</Read>
// </ApplicationData>
// </Change>
// </Commands>
//
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) _context
{
@@ -627,13 +814,32 @@ struct GlobalObjectId {
if ((o = [theValues objectForKey: @"Flag"]))
{
o = [o objectForKey: @"FlagStatus"];
if ([o intValue])
[self addFlags: @"\\Flagged"];
// We must handle empty flags -> {Flag = ""; } - some ActiveSync clients, like the HTC Desire
// will send an empty Flag message when "unflagging" a mail.
if (([o isKindOfClass: [NSMutableDictionary class]]))
{
if ((o = [o objectForKey: @"FlagStatus"]))
{
// 0 = The flag is cleared.
// 1 = The status is set to complete.
// 2 = The status is set to active.
if (([o isEqualToString: @"2"]))
[self addFlags: @"\\Flagged"];
else
[self removeFlags: @"\\Flagged"];
}
}
else
[self removeFlags: @"\\Flagged"];
}
if ((o = [theValues objectForKey: @"Read"]))
{
if ([o intValue])
[self addFlags: @"seen"];
else
[self removeFlags: @"seen"];;
}
}
@end
+55
View File
@@ -0,0 +1,55 @@
/*
Copyright (c) 2014, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Inverse inc. nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __SOGOSYNCCACHEOBJECT_H__
#define __SOGOSYNCCACHEOBJECT_H__
#import <Foundation/NSObject.h>
@class NSNull;
@interface SOGoSyncCacheObject : NSObject
{
id _uid;
id _sequence;
}
+ (id) syncCacheObjectWithUID: (id) theUID sequence: (id) theSequence;
- (id) uid;
- (void) setUID: (id) theUID;
- (id) sequence;
- (void) setSequence: (id) theSequence;
- (NSComparisonResult) compareUID: (SOGoSyncCacheObject *) theSyncCacheObject;
- (NSComparisonResult) compareSequence: (SOGoSyncCacheObject *) theSyncCacheObject;
@end
#endif
+122
View File
@@ -0,0 +1,122 @@
/*
Copyright (c) 2014, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Inverse inc. nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "SOGoSyncCacheObject.h"
#import <Foundation/NSNull.h>
#import <Foundation/NSString.h>
@implementation SOGoSyncCacheObject
- (id) init
{
if ((self = [super init]))
{
_uid = nil;
_sequence = nil;
}
return self;
}
+ (id) syncCacheObjectWithUID: (id) theUID sequence: (id) theSequence;
{
id o;
o = [[self alloc] init];
[o setUID: theUID];
[o setSequence: theSequence];
return o;
}
- (void) dealloc
{
RELEASE(_uid);
RELEASE(_sequence);
[super dealloc];
}
- (id) uid
{
return _uid;
}
- (void) setUID: (id) theUID
{
ASSIGN(_uid, theUID);
}
- (id) sequence
{
return _sequence;
}
- (void) setSequence: (id) theSequence
{
ASSIGN(_sequence, theSequence);
}
- (NSComparisonResult) compareUID: (SOGoSyncCacheObject *) theSyncCacheObject
{
return [[self uid] compare: [theSyncCacheObject uid]];
}
//
// We might get NSNull values here, so if both are NSNull instances,
// we sort by UID. If both sequences are equal, we also sort by UID.
//
- (NSComparisonResult) compareSequence: (SOGoSyncCacheObject *) theSyncCacheObject
{
if ([[self sequence] isEqual: [NSNull null]] &&
[[theSyncCacheObject sequence] isEqual: [NSNull null]])
return [self compareUID: theSyncCacheObject];
if (![[self sequence] isEqual: [NSNull null]] && [[theSyncCacheObject sequence] isEqual: [NSNull null]])
return NSOrderedDescending;
if ([[self sequence] isEqual: [NSNull null]] && ![[theSyncCacheObject sequence] isEqual: [NSNull null]])
return NSOrderedAscending;
// Must check this here, to avoid comparing NSNull objects
if ([[self sequence] compare: [theSyncCacheObject sequence]] == NSOrderedSame)
return [self compareUID: theSyncCacheObject];
return [[self sequence] compare: [theSyncCacheObject sequence]];
}
- (NSString *) description
{
return [NSString stringWithFormat: @"%@-%@", _uid, _sequence];
}
@end
@@ -62,7 +62,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[response setHeader: @"OPTIONS, POST" forKey: @"Allow"];
[response setHeader: @"14.1" forKey: @"MS-Server-ActiveSync"];
[response setHeader: @"2.0,2.1,2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
[response setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,Provision,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
[response setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
[response setHeader: @"OPTIONS, POST" forKey: @"Public"];
}
else
+4 -6
View File
@@ -1,5 +1,3 @@
# common make file for SoObject bundles
include ../config.make
include $(GNUSTEP_MAKEFILES)/common.make
include ../Version
@@ -18,10 +16,10 @@ ADDITIONAL_INCLUDE_DIRS += \
-I../../SOPE
ADDITIONAL_LIB_DIRS += \
-L../SOGo/SOGo.framework/ \
-L../../SOGo/$(GNUSTEP_OBJ_DIR)/ \
-L../../OGoContentStore/$(GNUSTEP_OBJ_DIR)/ \
-L../../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \
-L../SoObjects/SOGo/SOGo.framework/ \
-L../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR)/ \
-L../OGoContentStore/$(GNUSTEP_OBJ_DIR)/ \
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \
-L/usr/local/lib
BUNDLE_LIBS += \
+46
View File
@@ -0,0 +1,46 @@
/*
Copyright (c) 2014, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Inverse inc. nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ICALALARMACTIVESYNC_H__
#define __ICALALARMACTIVESYNC_H__
#import <NGCards/iCalAlarm.h>
@class NSString;
@class WOContext;
@interface iCalAlarm (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
@end
#endif
+106
View File
@@ -0,0 +1,106 @@
/*
Copyright (c) 2014, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Inverse inc. nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "iCalAlarm+ActiveSync.h"
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <NGExtensions/NSString+misc.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGCards/iCalAlarm.h>
#import <NGCards/iCalEvent.h>
#import <NGCards/iCalTrigger.h>
@implementation iCalAlarm (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSMutableString *s;
s = [NSMutableString string];
if ([[self action] caseInsensitiveCompare: @"DISPLAY"] == NSOrderedSame)
{
NSCalendarDate *nextAlarmDate;
NSInteger delta;
nextAlarmDate = [self nextAlarmDate];
delta = (int)(([[(iCalEvent *)parent startDate] timeIntervalSince1970] - [nextAlarmDate timeIntervalSince1970])/60);
// don't send negative reminder - not supported
if (delta > 0)
[s appendFormat: @"<Reminder xmlns=\"Calendar:\">%d</Reminder>", delta];
}
return s;
}
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context
{
iCalTrigger *trigger;
id o;
o = [theValues objectForKey: @"Reminder"];
// Outlook: if reminder is set to 0 minutes before start save it as 1 minute since -> 0 minutes in not accepted by SOGo
if ([o isEqualToString: @"0"])
o = @"1";
trigger = [iCalTrigger elementWithTag: @"TRIGGER"];
[trigger setValueType: @"DURATION"];
[self setTrigger: trigger];
[self setAction: @"DISPLAY"];
// SOGo web ui only supports 1w but not 2w (custom reminder only supports min/hours/days)
// 1week = -P1W
// 2weeks > -PxD
// xdays > -PxD
// xhours -> -PTxH
// xmin -> -PTxM
if ([o intValue] == 10080)
[trigger setSingleValue: [NSString stringWithFormat: @"-P1W" ] forKey: @""];
else
{
if (([o intValue] % 1440) == 0)
[trigger setSingleValue: [NSString stringWithFormat: @"-P%dD", ([o intValue] / 1440)] forKey: @""];
else
{
if (([o intValue] % 60) == 0)
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%dH", ([o intValue] / 60)] forKey: @""];
else
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%@M", o] forKey: @""];
}
}
}
@end
+72 -6
View File
@@ -50,6 +50,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Appointments/iCalEntityObject+SOGo.h>
#include "iCalAlarm+ActiveSync.h"
#include "iCalRecurrenceRule+ActiveSync.h"
#include "iCalTimeZone+ActiveSync.h"
#include "NSDate+ActiveSync.h"
@@ -83,6 +84,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
int v;
NSTimeZone *userTimeZone;
userTimeZone = [[[context activeUser] userDefaults] timeZone];
s = [NSMutableString string];
[s appendFormat: @"<AllDayEvent xmlns=\"Calendar:\">%d</AllDayEvent>", ([self isAllDay] ? 1 : 0)];
@@ -95,12 +99,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// StartTime -- http://msdn.microsoft.com/en-us/library/ee157132(v=exchg.80).aspx
if ([self startDate])
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>", [[self startDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
{
if ([self isAllDay])
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>",
[[[self startDate] dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: ([userTimeZone secondsFromGMTForDate: [self startDate]])*-1]
activeSyncRepresentationWithoutSeparatorsInContext: context]];
else
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>", [[self startDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
}
// EndTime -- http://msdn.microsoft.com/en-us/library/ee157945(v=exchg.80).aspx
if ([self endDate])
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>", [[self endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
{
if ([self isAllDay])
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>",
[[[self endDate] dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: ([userTimeZone secondsFromGMTForDate: [self endDate]])*-1]
activeSyncRepresentationWithoutSeparatorsInContext: context]];
else
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>", [[self endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
}
// Timezone
tz = [(iCalDateTime *)[self firstChildWithTag: @"dtstart"] timeZone];
@@ -138,7 +160,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
attendee = [attendees objectAtIndex: i];
[s appendFormat: @"<Attendee_Email xmlns=\"Calendar:\">%@</Attendee_Email>", [attendee rfc822Email]];
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [attendee cn]];
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee cn] activeSyncRepresentationInContext: context]];
attendee_status = [self _attendeeStatus: attendee];
@@ -209,7 +231,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendFormat: @"<Sensitivity xmlns=\"Calendar:\">%d</Sensitivity>", v];
// Reminder -- http://msdn.microsoft.com/en-us/library/ee219691(v=exchg.80).aspx
// TODO
// TODO: improve this to handle more alarm types
if ([self hasAlarms])
{
iCalAlarm *alarm;
alarm = [[self alarms] objectAtIndex: 0];
[s appendString: [alarm activeSyncRepresentationInContext: context]];
}
// Recurrence rules
if ([self isRecurrent])
@@ -356,6 +385,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (isAllDay)
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[start setDate: o];
[start setTimeZone: nil];
}
@@ -377,6 +410,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (isAllDay)
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[end setDate: o];
[end setTimeZone: nil];
}
@@ -390,6 +427,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
}
//
// If an alarm is deinfed with an action != DISPLAY, we ignore the alarm - don't want to overwrite.
//
if ([self hasAlarms] && [[[[self alarms] objectAtIndex: 0] action] caseInsensitiveCompare: @"DISPLAY"] != NSOrderedSame)
{
// Ignore the alarm for now
}
else if ((o = [theValues objectForKey: @"Reminder"]))
{
// NOTE: Outlook sends a 15 min reminder (18 hour for allday) if no reminder is specified
// although no default reminder is defined (File -> Options -> Clendar -> Calendar Options - > Default Reminders)
//
// http://answers.microsoft.com/en-us/office/forum/office_2013_release-outlook/desktop-outlook-calendar-creates-entries-with/9aef72d8-81bb-4a32-a6ab-bf7d216fb811?page=5&tm=1395690285088
//
iCalAlarm *alarm;
alarm = [[iCalAlarm alloc] init];
[alarm takeActiveSyncValues: theValues inContext: context];
[self removeAllAlarms];
[self addToAlarms: alarm];
RELEASE(alarm);
}
else
{
// We remove existing alarm since no reminder in the ActiveSync payload
[self removeAllAlarms];
}
// Recurrence
if ((o = [theValues objectForKey: @"Recurrence"]))
{
+20 -3
View File
@@ -34,6 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <NGCards/iCalEvent.h>
#import <NGCards/iCalByDayMask.h>
#import "NSCalendarDate+ActiveSync.h"
@@ -77,10 +78,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
occurrences = [[self byDayMask] weekDayOccurrences];
v = 0;
for (i = 0; i < 7; i++)
if (occurrences)
{
if (occurrences[i])
v += (1 << i);
for (i = 0; i < 7; i++)
{
if (occurrences[0][i])
v += (1 << i);
}
}
else
{
// No byDayMask, we take the event's start date to compute the DayOfWeek
// 0 == Sunday, 6 == Saturday
v = (1 << [[[self parent] startDate] dayOfWeek]);
}
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", v];
@@ -125,6 +135,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// FIXME
}
}
else
{
// Simple reccurrence rule of type "Monthly"
type = 2;
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"Calendar:\">%d</Recurrence_DayOfMonth>",
[[[self parent] startDate] dayOfMonth]];
}
}
else if ([self frequency] == iCalRecurrenceFrequenceYearly)
{
+3380
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
Binary file not shown.
+153 -3
View File
@@ -1,3 +1,153 @@
2.2.7 (2014-07-30)
------------------
New features
- new user preference to prevent event invitations
Enhancements
- improved badges of active tasks count
- refresh draft folder after sending a message
- now possible to DnD events in the calendar list
- improved handling of SOGoSubscriptionFolderFormat
- JSON'ified folder subscription interface
- updated Finnish, French, German, and Spanish (Spain) translations
- updated CKEditor to version 4.4.3
Bug fixes
- fixed weekdays translation in the datepicker
- fixed event categories display
- fixed all-day events display in IE
- fixed rename of calendars
- we now correctly add the "METHOD:REPLY" when sending out ITIP messages from DAV clients
- fixed refresh of message headers when forwarding a message (#2818)
- we now correctly escape all charset= in <meta> tags, not only in the <head>
- we now destroy cache objects of vanished folders
2.2.6 (2014-07-02)
------------------
New features
- add new 'multi-columns' calendar view (#1948)
Enhancements
- contacts photos are now synchronized using ActiveSync (#2807)
- implemented the GetAttachment ActiveSync command (#2808)
- implemented the Ping ActiveSync command
- added "soft deletes" support for ActiveSync (#2734)
- now display the active tasks count next to calendar names (#2760)
Bug fixes
- better handling of empty "Flag" messages over ActiveSync (#2806)
- fixed Chinese charset handling (#2809)
- fixed folder name (calendars and contacts) of new subscriptions (#2801)
- fixed the reply/forward operation over ActiveSync (#2805)
- fixed regression when attaching files to a reply
- wait 20 seconds (instead of 2) before deleting temporary download forms (#2811)
- avoid raising exceptions when the db is down and we try to access the preferences module (#2813)
- we now ignore the SCHEDULE-AGENT property when Thunderbird/Lightning sends it to avoid
not-generating invitation responses for externally received IMIP messages
- improved charset handling over ActiveSync (#2810)
2.2.5 (2014-06-05)
------------------
Enhancements
- new meta tag to tell IE to use the highest mode available
- updated Dutch, Finnish, German, and Polish translations
Bug fixes
- avoid crashing when we forward an email with no Subject header
- we no longer try to include attachments when replying to a mail
- fixed ActiveSync repetitive events issues with "Weekly" and "Monthly" ones
- fixed ActiveSync text/plain parts re-encoding issues for Outlook
2.2.4 (2014-05-29)
------------------
New features
- new print option in Calendar module
- now able to save unknown recipient emails to address book on send (#1496)
Enhancements
- Sieve folder encoding is now configurable (#2622)
- SOGo version is now displayed in preferences window (#2612)
- report Sieve error when saving preferences (#1046)
- added the SOGoMaximumSyncWindowSize system default to overwrite the
maximum number of items returned during an ActiveSync sync operation
- updated datepicker
- addressbooks properties are now accessible from a popup window
- extended events and tasks searches
- updated Czech, French, Hungarian, Polish, Russian, Slovak, Spanish (Argentina), and Spanish (Spain) translations
- added more sycned contact properties when using ActiveSync (#2775)
- now possible to configure the default subscribed resource name using SOGoSubscriptionFolderFormat
- now handle server-side folder updates using ActiveSync (#2688)
- updated CKEditor to version 4.4.1
Bug fixes
- fixed saved HTML content of draft when attaching a file
- fixed text nodes of HTML content handler by encoding HTML entities
- fixed iCal7 delegation issue with the "inbox" folder (#2489)
- fixed birth date validity checks (#1636)
- fixed URL handling (#2616)
- improved folder rename operations using ActiveSync (#2700)
- fixed SmartReply/Forward when ReplaceMime was omitted (#2680)
- fixed wrong generation of weekly repetitive events with ActiveSync (#2654)
- fixed incorrect XML data conversion with ActiveSync (#2695)
- fixed display of events having a category with HTML entities (#2703)
- fixed display of images in CSS background (#2437)
- fixed limitation of Sieve script size (#2745)
- fixed sync-token generation when no change was returned (#2492)
- fixed the IMAP copy/move operation between subfolders in different accounts
- fixed synchronization of seen/unseen status of msgs in Webmail (#2715)
- fixed focus of popup windows open through a contextual menu with Firefox on Windows 7
- fixed missing characters in shared folder names over ActiveSync (#2709)
- fixed reply and forward mail templates for Brazilian Portuguese (#2738)
- fixed newline in signature when forwarding a message as attachment in HTML mode (#2787)
- fixed restoration of options (priority & return receipt) when editing a draft (#193)
- fixed update of participation status via CalDAV (#2786)
2.2.3 (2014-04-03)
------------------
Enhancements
- updated Dutch, Hungarian, Russian and Spanish (Argentina) translations
- initial support for ActiveSync event reminders support (#2681)
- updated CKEditor to version 4.3.4
Bug fixes
- fixed possible exception when retrieving the default event reminder value on 64bit architectures (#2678)
- fixed calling unescapeHTML on null variables to avoid JavaScript exceptions in Contacts module
- fixed detection of IMAP flags support on the client side (#2664)
- fixed the ActiveSync issue marking all mails as read when downloading them
- fixed ActiveSync's move operations not working for multiple selections (#2691)
- fixed email validation regexp to allow gTLDs
- improved all-day events support for ActiveSync (#2686)
2.2.2 (2014-03-21)
------------------
Enhancements
- updated French, Finnish, German and Spanish (Spain) translations
- added sanitization support for Outlook/ActiveSync to circumvent Outlook bugs (#2667)
- updated CKEditor to version 4.3.3
- updated jQuery File Upload to version 9.5.7
Bug fixes
- fixed possible exception when retrieving the default event reminder value on 64bit architectures (#2647, #2648)
- disable file paste support in mail editor (#2641)
- fixed copying/moving messages to a mail folder begining with a digit (#2658)
- fixed unseen count for folders beginning with a digit and used in Sieve filters (#2652)
- fixed decoding of HTML entities in reminder alerts (#2659)
- fixed check for resource conflict when creating an event in the resource's calendar (#2541)
- fixed construction of mail folders tree
- fixed parsing of ORG attribute in cards (#2662)
- disabled ActiveSync provisioning for now (#2663)
- fixed messages move in Outlook which would create duplicates (#2650)
- fixed translations for OtherUsersFolderName and SharedFoldersName folders (#2657)
- fixed handling of accentuated characters when filtering contacts (#2656)
- fixed classification icon of events (#2651)
- fixed ActiveSync's SendMail with client version <= 12.1 (#2669)
2.2.1 (2014-03-07)
------------------
@@ -13,9 +163,9 @@ Bug fixes
- fixed wrong date format leading to Android email syncing issues (#2609)
- fixed possible exception when retrieving the default event reminder value (#2624)
- fixed encoding of mail folder name when creating a subfolder (#2637)
- fixed returned date format for email messages in Active Sync
- fixed missing 'name part' in address for email messages in Active Sync
- fixed race condition when syncing huge amount of deleted messages over Active Sync
- fixed returned date format for email messages in ActiveSync
- fixed missing 'name part' in address for email messages in ActiveSync
- fixed race condition when syncing huge amount of deleted messages over ActiveSync
- fixed encoding of string as CSS identifier when the string starts with a digit
- fixed auto-completion popupmenu when UID is a digit
+1 -11
View File
@@ -46,11 +46,8 @@ $(SOGOBACKEND)_OBJC_FILES += \
MAPIStoreSamDBUtils.m \
MAPIStoreUserContext.m \
\
SOGoMAPIObject.m \
\
SOGoMAPIDBObject.m \
SOGoMAPIDBMessage.m \
SOGoMAPIDBFolder.m \
SOGoCacheGCSObject+MAPIStore.m \
\
MAPIStoreAppointmentWrapper.m \
MAPIStoreAttachment.m \
@@ -123,13 +120,6 @@ $(SOGOBACKEND)_OBJC_FILES += \
iCalEvent+MAPIStore.m \
iCalTimeZone+MAPIStore.m \
\
GCSSpecialQueries+OpenChange.m\
\
EOQualifier+MAPI.m \
\
EOBitmaskQualifier.m \
\
BSONCodec.m \
RTFHandler.m
+3
View File
@@ -3,3 +3,6 @@ all:: MAPIStorePropertySelectors.m MAPIStorePropertySelectors.h
MAPIStorePropertySelectors.m MAPIStorePropertySelectors.h: gen-property-selectors.py code-MAPIStorePropertySelectors.m code-MAPIStorePropertySelectors.h
@echo " Auto-generating MAPIStorePropertySelectors.[hm]..."
@$(PYTHON) ./gen-property-selectors.py -o MAPIStorePropertySelectors $(LIBMAPISTORE_CFLAGS)
distclean clean::
-rm -f MAPIStorePropertySelectors.m MAPIStorePropertySelectors.h
+6 -8
View File
@@ -1,8 +1,6 @@
/* MAPIStoreDBBaseContext.m - this file is part of SOGo
*
* Copyright (C) 2012 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2012-2014 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,7 +30,7 @@
#import "MAPIStoreDBFolder.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreUserContext.h"
#import "SOGoMAPIDBFolder.h"
#import <SOGo/SOGoCacheGCSFolder.h>
#import "MAPIStoreDBBaseContext.h"
@@ -60,7 +58,7 @@ static Class MAPIStoreDBFolderK;
- (void) ensureContextFolder
{
SOGoMAPIDBFolder *currentFolder;
SOGoCacheGCSFolder *currentFolder;
NSArray *parts;
NSMutableArray *folders;
NSString *folderName;
@@ -78,7 +76,7 @@ static Class MAPIStoreDBFolderK;
folderName = [parts objectAtIndex: count];
if ([folderName length] > 0)
{
currentFolder = [SOGoMAPIDBFolder objectWithName: folderName
currentFolder = [SOGoCacheGCSFolder objectWithName: folderName
inContainer: currentFolder];
[folders addObject: currentFolder];
}
@@ -98,11 +96,11 @@ static Class MAPIStoreDBFolderK;
- (id) rootSOGoFolder
{
SOGoMAPIDBFolder *folder;
SOGoCacheGCSFolder *folder;
[userContext ensureFolderTableExists];
folder = [SOGoMAPIDBFolder objectWithName: [isa MAPIModuleName]
folder = [SOGoCacheGCSFolder objectWithName: [isa MAPIModuleName]
inContainer: nil];
[folder setTableUrl: [userContext folderTableURL]];
// [folder reloadIfNeeded];
+9 -9
View File
@@ -32,7 +32,7 @@
#import <EOControl/EOQualifier.h>
#import <SOGo/SOGoFolder.h>
#import <SOGo/SOGoUser.h>
#import "EOQualifier+MAPI.h"
#import <SOGo/EOQualifier+SOGoCacheObject.h>
#import "MAPIStoreContext.h"
#import "MAPIStoreDBFolderTable.h"
#import "MAPIStoreDBMessage.h"
@@ -40,7 +40,7 @@
#import "MAPIStoreMapping.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
#import "SOGoMAPIDBFolder.h"
#import <SOGo/SOGoCacheGCSFolder.h>
#import "SOGoMAPIDBMessage.h"
#import "MAPIStoreDBFolder.h"
@@ -49,7 +49,7 @@
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
static Class EOKeyValueQualifierK, SOGoMAPIDBFolderK, MAPIStoreDBFolderK;
static Class EOKeyValueQualifierK, SOGoCacheGCSFolderK, MAPIStoreDBFolderK;
static NSString *MAPIStoreRightReadItems = @"RightsReadItems";
static NSString *MAPIStoreRightCreateItems = @"RightsCreateItems";
@@ -66,7 +66,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
+ (void) initialize
{
EOKeyValueQualifierK = [EOKeyValueQualifier class];
SOGoMAPIDBFolderK = [SOGoMAPIDBFolder class];
SOGoCacheGCSFolderK = [SOGoCacheGCSFolder class];
MAPIStoreDBFolderK = [MAPIStoreDBFolder class];
}
@@ -92,7 +92,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
{
enum mapistore_error rc;
NSString *folderName, *nameInContainer;
SOGoMAPIDBFolder *newFolder;
SOGoCacheGCSFolder *newFolder;
struct SPropValue *value;
value = get_SPropValue_SRow (aRow, PidTagDisplayName);
@@ -111,7 +111,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
{
nameInContainer = [NSString stringWithFormat: @"0x%.16"PRIx64,
(unsigned long long) newFID];
newFolder = [SOGoMAPIDBFolderK objectWithName: nameInContainer
newFolder = [SOGoCacheGCSFolderK objectWithName: nameInContainer
inContainer: sogoObject];
[newFolder reloadIfNeeded];
[[newFolder properties] setObject: folderName
@@ -181,7 +181,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
[SOGoObject globallyUniqueObjectId]];
fsObject = [SOGoMAPIDBMessage objectWithName: newKey
inContainer: sogoObject];
[fsObject setObjectType: MAPIDBObjectTypeMessage];
[fsObject setObjectType: MAPIMessageCacheObject];
[fsObject reloadIfNeeded];
newMessage = [MAPIStoreDBMessage mapiStoreObjectWithSOGoObject: fsObject
inContainer: self];
@@ -198,7 +198,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
ownerUser = [[self userContext] sogoUser];
if ([[context activeUser] isEqual: ownerUser]
|| [self subscriberCanReadMessages])
keys = [(SOGoMAPIDBFolder *) sogoObject childKeysOfType: MAPIDBObjectTypeMessage
keys = [(SOGoCacheGCSFolder *) sogoObject childKeysOfType: MAPIMessageCacheObject
includeDeleted: NO
matchingQualifier: qualifier
andSortOrderings: sortOrderings];
@@ -211,7 +211,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
- (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings
{
return [dbFolder childKeysOfType: MAPIDBObjectTypeFolder
return [dbFolder childKeysOfType: MAPIFolderCacheObject
includeDeleted: NO
matchingQualifier: qualifier
andSortOrderings: sortOrderings];
+4 -6
View File
@@ -1,8 +1,6 @@
/* MAPIStoreFallbackContext.m - this file is part of SOGo
*
* Copyright (C) 2011-2012 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2011-2014 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,7 +24,7 @@
#import "MAPIStoreUserContext.h"
#import "NSString+MAPIStore.h"
#import "SOGoMAPIDBFolder.h"
#import <SOGo/SOGoCacheGCSFolder.h>
#import "MAPIStoreFallbackContext.h"
@@ -51,7 +49,7 @@
inMemCtx: (TALLOC_CTX *) memCtx
{
struct mapistore_contexts_list *firstContext = NULL, *context;
SOGoMAPIDBFolder *root;
SOGoCacheGCSFolder *root;
NSArray *names;
NSUInteger count, max;
NSString *baseURL, *url, *name;
@@ -70,7 +68,7 @@
/* Maybe emsmdbp_provisioning should be fixed in order to only take the uri
returned above to avoid deleting its entries... */
root = [SOGoMAPIDBFolder objectWithName: [self MAPIModuleName]
root = [SOGoCacheGCSFolder objectWithName: [self MAPIModuleName]
inContainer: nil];
[root setOwner: userName];
userContext = [MAPIStoreUserContext userContextWithUsername: userName
+4 -6
View File
@@ -1,8 +1,6 @@
/* MAPIStoreFolder.h - this file is part of SOGo
*
* Copyright (C) 2011-2012 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2011-2014 Inverse inc
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,7 +36,7 @@
@class MAPIStoreMessageTable;
@class MAPIStorePermissionsTable;
@class SOGoFolder;
@class SOGoMAPIDBFolder;
@class SOGoCacheGCSFolder;
@class SOGoMAPIDBMessage;
#import "MAPIStoreSOGoObject.h"
@@ -50,7 +48,7 @@
// NSArray *faiMessageKeys;
// NSArray *folderKeys;
SOGoMAPIDBFolder *dbFolder;
SOGoCacheGCSFolder *dbFolder;
// SOGoMAPIDBFolder *faiFolder;
// SOGoMAPIDBFolder *propsFolder;
// SOGoMAPIDBMessage *propsMessage;
@@ -60,7 +58,7 @@
- (void) setupAuxiliaryObjects;
- (SOGoMAPIDBFolder *) dbFolder;
- (SOGoCacheGCSFolder *) dbFolder;
- (NSArray *) activeMessageTables;
- (NSArray *) activeFAIMessageTables;
+8 -9
View File
@@ -1,8 +1,6 @@
/* MAPIStoreFolder.m - this file is part of SOGo
*
* Copyright (C) 2011-2012 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2011-2014 Inverse inc
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -51,8 +49,9 @@
#import "NSDate+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "SOGoMAPIDBFolder.h"
#import <SOGo/SOGoCacheGCSFolder.h>
#import "SOGoMAPIDBMessage.h"
#import "SOGoCacheGCSObject+MAPIStore.h"
#include <gen_ndr/exchange.h>
@@ -120,7 +119,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
[userContext ensureFolderTableExists];
ASSIGN (dbFolder,
[SOGoMAPIDBFolder objectWithName: folderName
[SOGoCacheGCSFolder objectWithName: folderName
inContainer: [container dbFolder]]);
[dbFolder setTableUrl: [userContext folderTableURL]];
if (!container && [path length] > 0)
@@ -138,7 +137,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
// ASSIGN (propsMessage,
// [SOGoMAPIDBMessage objectWithName: @"properties.plist"
// inContainer: dbFolder]);
// [propsMessage setObjectType: MAPIDBObjectTypeInternal];
// [propsMessage setObjectType: MAPIInternalCacheObject];
// [propsMessage reloadIfNeeded];
[properties release];
properties = [dbFolder properties];
@@ -192,7 +191,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
[super dealloc];
}
- (SOGoMAPIDBFolder *) dbFolder
- (SOGoCacheGCSFolder *) dbFolder
{
return dbFolder;
}
@@ -1221,7 +1220,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
- (NSArray *) faiMessageKeysMatchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings
{
return [dbFolder childKeysOfType: MAPIDBObjectTypeFAI
return [dbFolder childKeysOfType: MAPIFAICacheObject
includeDeleted: NO
matchingQualifier: qualifier
andSortOrderings: sortOrderings];
@@ -1531,7 +1530,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
newKey = [NSString stringWithFormat: @"%@.plist",
[SOGoObject globallyUniqueObjectId]];
dbObject = [SOGoMAPIDBMessage objectWithName: newKey inContainer: dbFolder];
[dbObject setObjectType: MAPIDBObjectTypeFAI];
[dbObject setObjectType: MAPIFAICacheObject];
[dbObject setIsNew: YES];
newMessage = [MAPIStoreFAIMessageK mapiStoreObjectWithSOGoObject: dbObject
inContainer: self];
+1 -1
View File
@@ -74,7 +74,7 @@ static Class NSNumberK;
ASSIGN (versionsMessage,
[SOGoMAPIDBMessage objectWithName: @"versions.plist"
inContainer: dbFolder]);
[versionsMessage setObjectType: MAPIDBObjectTypeInternal];
[versionsMessage setObjectType: MAPIInternalCacheObject];
}
- (void) dealloc
+4 -4
View File
@@ -59,7 +59,7 @@
#import "NSData+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import "SOGoMAPIDBMessage.h"
#import "SOGoMAPIDBFolder.h"
#import <SOGo/SOGoCacheGCSFolder.h>
#import "MAPIStoreMailVolatileMessage.h"
@@ -106,7 +106,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
ASSIGN (versionsMessage,
[SOGoMAPIDBMessage objectWithName: @"versions.plist"
inContainer: dbFolder]);
[versionsMessage setObjectType: MAPIDBObjectTypeInternal];
[versionsMessage setObjectType: MAPIInternalCacheObject];
}
- (BOOL) ensureFolderExists
@@ -1172,9 +1172,9 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
- (MAPIStoreMessage *) createMessage
{
SOGoMAPIObject *childObject;
SOGoCacheObject *childObject;
childObject = [SOGoMAPIObject objectWithName: [SOGoMAPIObject
childObject = [SOGoCacheObject objectWithName: [SOGoCacheObject
globallyUniqueObjectId]
inContainer: sogoObject];
return [MAPIStoreMailVolatileMessage
+1 -1
View File
@@ -62,7 +62,7 @@
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import "SOGoMAPIObject.h"
#import <SOGo/SOGoCacheObject.h>
#import "MAPIStoreMailVolatileMessage.h"
+1 -1
View File
@@ -25,7 +25,7 @@
#import <NGExtensions/NSObject+Logs.h>
#import <EOControl/EOQualifier.h>
#import "EOBitmaskQualifier.h"
#import <SOGo/EOBitmaskQualifier.h>
#import "MAPIStoreActiveTables.h"
#import "MAPIStoreObject.h"
#import "MAPIStoreTypes.h"
+8 -5
View File
@@ -42,7 +42,7 @@
#import <Mailer/SOGoMailAccount.h>
#import <Mailer/SOGoMailAccounts.h>
#import "GCSSpecialQueries+OpenChange.h"
#import <SOGo/GCSSpecialQueries+SOGoCacheObject.h>
#import "MAPIApplication.h"
#import "MAPIStoreAuthenticator.h"
#import "MAPIStoreMapping.h"
@@ -294,9 +294,12 @@ static NSMapTable *contextsTable = nil;
if ([parts count] == 5)
{
/* If "OCSFolderInfoURL" is properly configured, we must have 5
parts in this url. */
ocFSTableName = [NSString stringWithFormat: @"socfs_%@",
[username asCSSIdentifier]];
parts in this url. We strip the '-' character in case we have
this in the domain part - like foo@bar-zot.com */
ocFSTableName = [NSString stringWithFormat: @"sogo_cache_folder_%@",
[[[user loginInDomain] asCSSIdentifier]
stringByReplacingOccurrencesOfString: @"-"
withString: @"_"]];
[parts replaceObjectAtIndex: 4 withObject: ocFSTableName];
folderTableURL
= [NSURL URLWithString: [parts componentsJoinedByString: @"/"]];
@@ -329,7 +332,7 @@ static NSMapTable *contextsTable = nil;
tableName]])
{
queries = [channel specialQueries];
query = [queries createOpenChangeFSTableWithName: tableName];
query = [queries createSOGoCacheGCSFolderTableWithName: tableName];
if ([channel evaluateExpressionX: query])
[NSException raise: @"MAPIStoreIOException"
format: @"could not create special table '%@'", tableName];
+2 -4
View File
@@ -1,8 +1,6 @@
/* dbmsgdump.m - this file is part of SOGo
*
* Copyright (C) 2011-2012 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2011-2014 Inverse inc
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,7 +31,7 @@
#import <Foundation/NSValue.h>
#import <NGExtensions/NSNull+misc.h>
#import "BSONCodec.h"
#import <SOGo/BSONCodec.h>
const char *indentationStep = " ";
+32
View File
@@ -0,0 +1,32 @@
/* SOGoCacheGCSObject+MAPIStore.h - this file is part of SOGo
*
* Copyright (C) 2014 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef SOGOCACHEGCSOBJECTMAPISTORE
#define SOGOCACHEGCSOBJECTMAPISTORE
#include <SOGo/SOGoCacheGCSObject.h>
@interface SOGoCacheGCSObject (MAPIStore)
- (Class) mapistoreMessageClass;
@end
#endif // SOGOCACHEGCSOBJECTMAPISTORE
+68
View File
@@ -0,0 +1,68 @@
/* SOGoCacheGCSObject+MAPIStore.m - this file is part of SOGo
*
* Copyright (C) 2014 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
#import <Foundation/NSString.h>
#include "MAPIStoreTypes.h"
#include "SOGoCacheGCSObject+MAPIStore.h"
@implementation SOGoCacheGCSObject (MAPIStore)
- (Class) mapistoreMessageClass
{
NSString *className, *mapiMsgClass;
switch (objectType)
{
case MAPIMessageCacheObject:
mapiMsgClass = [properties
objectForKey: MAPIPropertyKey (PidTagMessageClass)];
if (mapiMsgClass)
{
if ([mapiMsgClass isEqualToString: @"IPM.StickyNote"])
className = @"MAPIStoreNotesMessage";
else
className = @"MAPIStoreDBMessage";
//[self logWithFormat: @"PidTagMessageClass = '%@', returning '%@'",
// mapiMsgClass, className];
}
else
{
//[self warnWithFormat: @"PidTagMessageClass is not set, falling back"
// @" to 'MAPIStoreDBMessage'"];
className = @"MAPIStoreDBMessage";
}
break;
case MAPIFAICacheObject:
className = @"MAPIStoreFAIMessage";
break;
default:
[NSException raise: @"MAPIStoreIOException"
format: @"message class should not be queried for objects"
@" of type '%d'", objectType];
}
return NSClassFromString (className);
}
@end
+3 -5
View File
@@ -1,8 +1,6 @@
/* SOGoMAPIDBMessage.h - this file is part of SOGo
*
* Copyright (C) 2012 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2012-2014 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,12 +21,12 @@
#ifndef SOGOMAPIDBMESSAGE_H
#define SOGOMAPIDBMESSAGE_H
#import "SOGoMAPIDBObject.h"
#import <SOGo/SOGoCacheGCSObject.h>
@class NSDate;
@class NSString;
@interface SOGoMAPIDBMessage : SOGoMAPIDBObject
@interface SOGoMAPIDBMessage : SOGoCacheGCSObject
@end
#endif /* SOGOMAPIDBMESSAGE_H */
+1 -1
View File
@@ -30,7 +30,7 @@
#import <NGExtensions/NSObject+Logs.h>
#import "SOGoMAPIDBFolder.h"
#import <SOGo/SOGoCacheGCSFolder.h>
#import "SOGoMAPIDBMessage.h"
+1 -1
View File
@@ -34,7 +34,7 @@
#import <SOGo/SOGoSystemDefaults.h>
#import "MAPIStoreUserContext.h"
#import "SOGoMAPIDBObject.h"
#import <SOGo/SOGoCacheGCSObject.h>
#import "NSObject+PropertyList.m"
+2 -2
View File
@@ -46,7 +46,7 @@ static NSArray *privilegedTagNames = nil;
if (!privilegedTagNames)
{
privilegedTagNames = [NSArray arrayWithObjects: @"ADR", @"N", @"RRULE", nil];
privilegedTagNames = [NSArray arrayWithObjects: @"ADR", @"N", @"RRULE", @"ORG", nil];
RETAIN(privilegedTagNames);
}
@@ -232,7 +232,7 @@ static NSArray *privilegedTagNames = nil;
}
- (void) characters: (unichar *) _chars
length: (int) _len
length: (NSUInteger) _len
{
if (_len && _chars)
{
+3
View File
@@ -126,6 +126,9 @@ typedef enum
- (void) setCategories: (NSArray *) newCategories;
- (NSArray *) categories;
- (NSString *) photo;
- (void) setPhoto: (NSString *) _value;
// - (void) setN: (NGVCardName *) _v;
// - (NGVCardName *) n;
+19
View File
@@ -288,6 +288,25 @@
return [self uniqueChildWithTag: @"n"];
}
- (NSString *) photo
{
NGVCardPhoto *photo;
photo = (NGVCardPhoto *)[self uniqueChildWithTag: @"photo"];
return [[photo valuesAtIndex: 0 forKey: @""] objectAtIndex: 0];
}
- (void) setPhoto: (NSString *) _value
{
CardElement *photo;
photo = [self uniqueChildWithTag: @"photo"];
[photo setValue: 0 ofAttribute: @"encoding" to: @"BASE64"];
[photo setSingleValue: _value forKey: @""];
}
- (void) setOrg: (NSString *) anOrg
units: (NSArray *) someUnits
{
+4 -4
View File
@@ -217,10 +217,10 @@
printf("</%s>\n", [_localName cString]);
}
- (void)characters:(unichar *)_chars length:(int)_len {
- (void)characters:(unichar *)_chars length:(NSUInteger)_len {
NSString *str;
id tmp;
unsigned i, len;
NSUInteger i, len;
if (_len == 0) {
[self indent];
@@ -228,7 +228,7 @@
return;
}
for (i = 0; i < (unsigned)_len; i++) {
for (i = 0; i < _len; i++) {
if (_chars[i] > 255) {
NSLog(@"detected large char: o%04o d%03i h%04X",
_chars[i], _chars[i], _chars[i]);
@@ -246,7 +246,7 @@
[self indent];
printf("\"%s\"\n", [str cString]);
}
- (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
- (void)ignorableWhitespace:(unichar *)_chars length:(NSUInteger)_len {
NSString *data;
id tmp;
+4 -4
View File
@@ -22,7 +22,7 @@ sogoUserDefaultsFile = os.path.expanduser("~sogo/GNUstep/Defaults/.GNUstepDefaul
# - removes the entry in samba's ldap tree via ldbedit (NOTYET)
# - remove the user's directory under mapistore/ and mapistore/SOGo
# - cleanup Junk Folders and Sync Issues imap folders
# - Delete the socfs_ table for the username.
# - Delete the sogo_cache_folder_ table for the username.
def usage():
print """
@@ -210,7 +210,7 @@ On RHEL, install it using 'yum install MySQL-python'"""
conn = MySQLdb.connect(host=dbhost, port=int(dbport), user=dbuser, passwd=dbpass, db=dbname)
c=conn.cursor()
tablename="socfs_%s" % (username)
tablename="sogo_cache_folder_%s" % (username)
c.execute("TRUNCATE TABLE %s" % tablename)
print "Table %s emptied"
@@ -225,7 +225,7 @@ On RHEL, install it using 'yum install python-pgsql'"""
raise Exception(msg)
conn = pg.connect(host=dbhost, port=int(dbport), user=dbuser, passwd=dbpass, dbname=dbname)
tablename = "socfs_%s" % username
tablename = "sogo_cache_folder_%s" % username
conn.query("DELETE FROM %s" % tablename)
print "Table '%s' emptied" % tablename
@@ -278,7 +278,7 @@ def sqlCleanup(username):
print "Starting SQL cleanup"
OCSFolderInfoURL = getOCSFolderInfoURL()
if OCSFolderInfoURL is None:
raise Exception("Couldn't fetch OCSFolderInfoURL or it is not set. the socfs_%s table should be truncated manually" % (username))
raise Exception("Couldn't fetch OCSFolderInfoURL or it is not set. the sogo_cache_folder_%s table should be truncated manually" % (username))
# postgresql://sogo:sogo@127.0.0.1:5432/sogo/sogo_folder_info
m = re.search("(.+)://(.+):(.+)@(.+):(\d+)/(.+)/(.+)", OCSFolderInfoURL)
@@ -1,3 +1,4 @@
"Inviting the following persons is prohibited:" = "Inviting the following persons is prohibited:";
"Personal Calendar" = "Personal Calendar";
vevent_class0 = "(Public event)";
vevent_class1 = "(Private event)";
@@ -1,3 +1,4 @@
"Inviting the following persons is prohibited:" = "Seuraavien henkilöiden kutsuminen on estetty:";
"Personal Calendar" = "Henkilökohtainen kalenteri";
vevent_class0 = "(Julkinen tapahtuma)";
vevent_class1 = "(Yksityinen tapahtuma)";
@@ -1,3 +1,4 @@
"Inviting the following persons is prohibited:" = "L'invitation des personnes suivantes est interdite :";
"Personal Calendar" = "Agenda personnel";
vevent_class0 = "(Événement public)";
vevent_class1 = "(Événement privé)";
@@ -1,3 +1,4 @@
"Inviting the following persons is prohibited:" = "Das Einladen von folgenden Personen ist verboten:";
"Personal Calendar" = "Persönlicher Kalender";
vevent_class0 = "(Öffentlicher Termin)";
vevent_class1 = "(Privater Termin)";
@@ -80,6 +80,8 @@ typedef enum {
- (NSArray *) calendarUIDs;
- (NSNumber *) activeTasks;
/* vevent UID handling */
- (NSString *) resourceNameForEventUID: (NSString *) _uid;
+102 -7
View File
@@ -1,5 +1,5 @@
/*
Copyright (C) 2007-2013 Inverse inc.
Copyright (C) 2007-2014 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of SOGo.
@@ -230,6 +230,8 @@ static iCalEvent *iCalEventK = nil;
abstract: NO
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
/* read-acl and write-acl are defined in RFC3744 */
[aclManager registerDAVPermission: davElement (@"admin", nsI)
abstract: YES
withEquivalent: nil
@@ -242,6 +244,72 @@ static iCalEvent *iCalEventK = nil;
abstract: YES
withEquivalent: SoPerm_ChangePermissions
asChildOf: davElement (@"admin", nsI)];
/* Default permissions for calendars. These are very important so that DAV client can
detect permission changes on calendars and reload all items, if necessary */
/* Public ones */
[aclManager registerDAVPermission: davElement (@"viewwhole-public-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ViewWholePublicRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"viewdant-public-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ViewDAndTOfPublicRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"modify-public-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ModifyPublicRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"respondto-public-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_RespondToPublicRecords
asChildOf: davElement (@"admin", nsI)];
/* Private ones */
[aclManager registerDAVPermission: davElement (@"viewwhole-private-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ViewWholePrivateRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"viewdant-private-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ViewDAndTOfPrivateRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"modify-private-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ModifyPrivateRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"respondto-private-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_RespondToPrivateRecords
asChildOf: davElement (@"admin", nsI)];
/* Condifential ones */
[aclManager registerDAVPermission: davElement (@"viewwhole-confidential-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ViewWholeConfidentialRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"viewdant-confidential-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ViewDAndTOfConfidentialRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"modify-confidential-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_ModifyConfidentialRecords
asChildOf: davElement (@"admin", nsI)];
[aclManager registerDAVPermission: davElement (@"respondto-confidential-records", nsI)
abstract: YES
withEquivalent: SOGoCalendarPerm_RespondToConfidentialRecords
asChildOf: davElement (@"admin", nsI)];
}
return aclManager;
@@ -522,7 +590,6 @@ static iCalEvent *iCalEventK = nil;
{
/* this is used for group calendars (this folder just returns itself) */
NSString *s;
s = [[self container] nameInContainer];
// [self logWithFormat:@"CAL UID: %@", s];
return [s isNotNull] ? [NSArray arrayWithObjects:&s count:1] : nil;
@@ -1280,13 +1347,20 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
[baseWhere addObject: privacySQLString];
if ([title length])
[baseWhere
addObject: [NSString stringWithFormat: @"c_title isCaseInsensitiveLike: '%%%@%%'",
if ([filters length])
{
if ([filters isEqualToString:@"title_Category_Location"] || [filters isEqualToString:@"entireContent"])
{
[baseWhere addObject: [NSString stringWithFormat: @"(c_title isCaseInsensitiveLike: '%%%@%%' OR c_category isCaseInsensitiveLike: '%%%@%%' OR c_location isCaseInsensitiveLike: '%%%@%%')",
[title stringByReplacingString: @"'" withString: @"\\'\\'"],
[title stringByReplacingString: @"'" withString: @"\\'\\'"],
[title stringByReplacingString: @"'" withString: @"\\'\\'"]]];
}
}
else
[baseWhere addObject: [NSString stringWithFormat: @"c_title isCaseInsensitiveLike: '%%%@%%'",
[title stringByReplacingString: @"'" withString: @"\\'\\'"]]];
if ([filters length])
[baseWhere addObject: [NSString stringWithFormat: @"(%@)", filters]];
/* prepare mandatory fields */
fields = [NSMutableArray arrayWithArray: _fields];
@@ -3263,4 +3337,25 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
return users;
}
- (NSNumber *) activeTasks
{
NSArray *tasksList;
NSMutableArray *fields;
NSNumber *activeTasks;
fields = [NSMutableArray arrayWithObjects: @"c_component", @"c_status", nil];
tasksList = [self bareFetchFields: fields
from: nil
to: nil
title: nil
component: @"vtodo"
additionalFilters: @"c_status != 1 AND c_status != 3"];
activeTasks = [NSNumber numberWithInt:[tasksList count]];
return activeTasks;
}
@end /* SOGoAppointmentFolder */
@@ -1,7 +1,7 @@
/* SOGoAppointmentFolders.m - this file is part of SOGo
*
* Copyright (C) 2007-2013 Inverse inc.
* Copyright (C) 2007-2014 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -56,13 +56,6 @@
#import "SOGoAppointmentFolders.h"
@interface SOGoParentFolder (Private)
- (NSException *) _fetchPersonalFolders: (NSString *) sql
withChannel: (EOAdaptorChannel *) fc;
@end
static SoSecurityManager *sm = nil;
@implementation SOGoAppointmentFolders
@@ -596,8 +589,9 @@ static SoSecurityManager *sm = nil;
}
}
- (NSException *) _fetchPersonalFolders: (NSString *) sql
withChannel: (EOAdaptorChannel *) fc
- (NSException *) fetchSpecialFolders: (NSString *) sql
withChannel: (EOAdaptorChannel *) fc
andFolderType: (SOGoFolderType) folderType
{
BOOL isWebRequest;
NSException *error;
@@ -607,7 +601,7 @@ static SoSecurityManager *sm = nil;
SOGoWebAppointmentFolder *webFolder;
NSString *name;
error = [super _fetchPersonalFolders: sql withChannel: fc];
error = [super fetchSpecialFolders: sql withChannel: fc andFolderType: folderType];
if (!error)
{
isWebRequest = [[context request] handledByDefaultHandler];
@@ -756,7 +750,8 @@ static SoSecurityManager *sm = nil;
for (userCount = 0; userCount < userMax; userCount++)
[currentFolder
subscribeUserOrGroup: [proxySubscribers objectAtIndex: userCount]
reallyDo: YES];
reallyDo: YES
response: nil];
}
}
}
@@ -781,7 +776,8 @@ static SoSecurityManager *sm = nil;
for (userCount = 0; userCount < userMax; userCount++)
[currentFolder
subscribeUserOrGroup: [proxySubscribers objectAtIndex: userCount]
reallyDo: NO];
reallyDo: NO
response: nil];
}
}
}
@@ -1,8 +1,6 @@
/* SOGoAppointmentInboxFolder.m - this file is part of SOGo
*
* Copyright (C) 2010 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2010-2014 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
File diff suppressed because it is too large. Load diff
@@ -1,3 +1,4 @@
"Inviting the following persons is prohibited:" = "Esta prohibido invitar las siguientes personas:";
"Personal Calendar" = "Calendario personal";
vevent_class0 = "(Evento público)";
vevent_class1 = "(Evento privado)";
+1 -1
View File
@@ -67,7 +67,7 @@
SOGoAppointmentInboxFolder = {
superclass = "SOGoAppointmentFolder";
defaultRoles = {
"Access Contents Information" = ( "Owner" );
"Access Contents Information" = ( "Owner", "AuthorizedSubscriber" );
};
};
SOGoCalendarComponent = {
@@ -1 +1,2 @@
"Personal Address Book" = "Osobní kontakty";
"Collected Address Book" = "Sebrané kontakty";
@@ -1 +1,2 @@
"Personal Address Book" = "Persoonlijk adresboek";
"Collected Address Book" = "Verzamelde adressen";
@@ -1 +1,2 @@
"Personal Address Book" = "Personal Address Book";
"Collected Address Book" = "Collected Address Book";
@@ -1 +1,2 @@
"Personal Address Book" = "Henkilökohtainen osoitekirja";
"Collected Address Book" = "Kerätty osoitekirja";
@@ -1 +1,2 @@
"Personal Address Book" = "Carnet d'adresses personnel";
"Collected Address Book" = "Adresses collectées";
@@ -1 +1,2 @@
"Personal Address Book" = "Persönliches Adressbuch";
"Collected Address Book" = "Gesammelte Adressen";
@@ -1 +1,2 @@
"Personal Address Book" = "Személyes címjegyzék";
"Collected Address Book" = "Összegyűjtöt címek jegyzéke";
@@ -1 +1,2 @@
"Personal Address Book" = "Osobista książka adresowa";
"Collected Address Book" = "Książka zebranych adresów";
@@ -1 +1,2 @@
"Personal Address Book" = "Личная адресная книга";
"Collected Address Book" = "Собранные адреса";
+7
View File
@@ -25,12 +25,19 @@
@interface SOGoContactFolders : SOGoParentFolder
- (NSString *) defaultFolderName;
- (NSString *) collectedFolderName;
- (NSException *) renameLDAPAddressBook: (NSString *) sourceID
withDisplayName: (NSString *) newDisplayName;
- (NSException *) removeLDAPAddressBook: (NSString *) sourceID;
- (NSDictionary *) systemSources;
- (NSArray *) allContactsFromFilter: (NSString *) theFilter
excludeGroups: (BOOL) excludeGroups
excludeLists: (BOOL) excludeLists;
@end
#endif /* SOGOCONTACTFOLDERS_H */
+136 -1
View File
@@ -22,12 +22,18 @@
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSSortDescriptor.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <DOM/DOMElement.h>
#import <DOM/DOMProtocols.h>
#import <GDLContentStore/GCSChannelManager.h>
#import <GDLContentStore/GCSFolderManager.h>
#import <GDLContentStore/NSURL+GCS.h>
#import <GDLAccess/EOAdaptorChannel.h>
#import <SOGo/NSObject+DAV.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
@@ -40,10 +46,17 @@
#import "SOGoContactFolders.h"
Class SOGoContactSourceFolderK;
#define XMLNS_INVERSEDAV @"urn:inverse:params:xml:ns:inverse-dav"
@implementation SOGoContactFolders
+ (void) initialize
{
SOGoContactSourceFolderK = [SOGoContactSourceFolder class];
}
+ (NSString *) gcsFolderType
{
return @"Contact";
@@ -110,6 +123,38 @@
return result;
}
- (NSException *) appendCollectedSources
{
GCSChannelManager *cm;
EOAdaptorChannel *fc;
NSURL *folderLocation;
NSString *sql, *gcsFolderType;
NSException *error;
cm = [GCSChannelManager defaultChannelManager];
folderLocation = [[GCSFolderManager defaultFolderManager] folderInfoLocation];
fc = [cm acquireOpenChannelForURL: folderLocation];
if ([fc isOpen])
{
gcsFolderType = [[self class] gcsFolderType];
sql = [NSString stringWithFormat: (@"SELECT c_path4 FROM %@"
@" WHERE c_path2 = '%@'"
@" AND c_folder_type = '%@'"),
[folderLocation gcsTableName], owner, gcsFolderType];
error = [super fetchSpecialFolders: sql withChannel: fc andFolderType: SOGoCollectedFolder];
[cm releaseChannel: fc];
}
else
error = [NSException exceptionWithName: @"SOGoDBException"
reason: @"database connection could not be open"
userInfo: nil];
return error;
}
- (NSDictionary *) systemSources
{
NSMutableDictionary *systemSources;
@@ -225,7 +270,7 @@
if ([sourceID isEqualToString: @"personal"])
result = [NSException exceptionWithHTTPStatus: 403
reason: @"folder 'personal' cannot be deleted"];
reason: (@"folder '%@' cannot be deleted", sourceID)];
else
{
result = nil;
@@ -250,6 +295,11 @@
return [self labelForKey: @"Personal Address Book"];
}
- (NSString *) collectedFolderName
{
return [self labelForKey: @"Collected Address Book"];
}
- (NSArray *) toManyRelationshipKeys
{
NSMutableArray *keys;
@@ -371,4 +421,89 @@
asWebDAVValue];
}
- (NSArray *) allContactsFromFilter: (NSString *) theFilter
excludeGroups: (BOOL) excludeGroups
excludeLists: (BOOL) excludeLists
{
SOGoFolder <SOGoContactFolder> *folder;
NSString *mail, *domain;
NSArray *folders, *contacts, *descriptors, *sortedContacts;
NSMutableArray *sortedFolders;
NSMutableDictionary *contact, *uniqueContacts;
unsigned int i, j, max;
NSSortDescriptor *commonNameDescriptor;
// NSLog(@"Search all contacts: %@", searchText);
domain = [[context activeUser] domain];
folders = nil;
NS_DURING
folders = [self subFolders];
NS_HANDLER
/* We need to specifically test for @"SOGoDBException", which is
raised explicitly in SOGoParentFolder. Any other exception should
be re-raised. */
if ([[localException name] isEqualToString: @"SOGoDBException"])
folders = nil;
else
[localException raise];
NS_ENDHANDLER;
max = [folders count];
sortedFolders = [NSMutableArray arrayWithCapacity: max];
uniqueContacts = [NSMutableDictionary dictionary];
for (i = 0; i < max; i++)
{
folder = [folders objectAtIndex: i];
/* We first search in LDAP folders (in case of duplicated entries in GCS folders) */
if ([folder isKindOfClass: SOGoContactSourceFolderK])
[sortedFolders insertObject: folder atIndex: 0];
else
[sortedFolders addObject: folder];
}
for (i = 0; i < max; i++)
{
folder = [sortedFolders objectAtIndex: i];
//NSLog(@" Address book: %@ (%@)", [folder displayName], [folder class]);
contacts = [folder lookupContactsWithFilter: theFilter
onCriteria: @"name_or_address"
sortBy: @"c_cn"
ordering: NSOrderedAscending
inDomain: domain];
for (j = 0; j < [contacts count]; j++)
{
contact = [contacts objectAtIndex: j];
mail = [contact objectForKey: @"c_mail"];
//NSLog(@" found %@ (%@) ? %@", [contact objectForKey: @"c_name"], mail,
// [contact description]);
if (!excludeLists && [[contact objectForKey: @"c_component"]
isEqualToString: @"vlist"])
{
[contact setObject: [folder nameInContainer]
forKey: @"container"];
[uniqueContacts setObject: contact
forKey: [contact objectForKey: @"c_name"]];
}
else if ([mail length]
&& [uniqueContacts objectForKey: mail] == nil
&& !(excludeGroups && [contact objectForKey: @"isGroup"]))
[uniqueContacts setObject: contact forKey: mail];
}
}
if ([uniqueContacts count] > 0)
{
// Sort the contacts by display name
commonNameDescriptor = [[NSSortDescriptor alloc] initWithKey: @"c_cn"
ascending:YES];
descriptors = [NSArray arrayWithObjects: commonNameDescriptor, nil];
[commonNameDescriptor release];
sortedContacts = [[uniqueContacts allValues]
sortedArrayUsingDescriptors: descriptors];
}
else
sortedContacts = [NSArray array];
return sortedContacts;
}
@end
@@ -1 +1,2 @@
"Personal Address Book" = "Osobné kontakty";
"Collected Address Book" = "Pozbierané osobné kontakty";
@@ -1 +1,2 @@
"Personal Address Book" = "Libreta personal de direcciones";
"Collected Address Book" = "Direcciones recopiladas";
@@ -1 +1,2 @@
"Personal Address Book" = "Libreta personal de direcciones";
"Collected Address Book" = "Libreta de direcciones recogidas";
@@ -0,0 +1,2 @@
"SieveFolderName" = "فلاتر";
"OtherUsersFolderName" = "مستخدمين أخرين";
@@ -0,0 +1,2 @@
"SieveFolderName" = "Filtros";
"OtherUsersFolderName" = "Outros Usuários";
@@ -0,0 +1,2 @@
"SieveFolderName" = "Filtres";
"OtherUsersFolderName" = "Altres usuaris";
@@ -0,0 +1,2 @@
"OtherUsersFolderName" = "Ostatní uživatelé";
"SharedFoldersName" = "Sdílené složky";
@@ -0,0 +1,2 @@
"SieveFolderName" = "Filtre";
"OtherUsersFolderName" = "Andre brugere";
@@ -0,0 +1,2 @@
"OtherUsersFolderName" = "Andere Gebruikers";
"SharedFoldersName" = "Gedeelde Mappen";
@@ -0,0 +1,2 @@
"OtherUsersFolderName" = "Other Users";
"SharedFoldersName" = "Shared Folders";
@@ -0,0 +1,2 @@
"OtherUsersFolderName" = "Muut käyttäjät";
"SharedFoldersName" = "Jaetut kansiot";
@@ -0,0 +1,2 @@
"OtherUsersFolderName" = "Autres utilisateurs";
"SharedFoldersName" = "Dossiers partagés";
+1 -1
View File
@@ -92,7 +92,7 @@ Mailer_RESOURCE_FILES += \
SOGoMailWelshReply.wo
Mailer_LANGUAGES = English French
Mailer_LANGUAGES = Arabic BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
Mailer_LOCALIZED_RESOURCE_FILES = Localizable.strings
@@ -0,0 +1,2 @@
"OtherUsersFolderName" = "Andere Benutzer";
"SharedFoldersName" = "Gemeinsame Ordner";
@@ -0,0 +1,2 @@
"OtherUsersFolderName" = "Egyéb felhasználók";
"SharedFoldersName" = "Megosztott mappák";
@@ -0,0 +1,2 @@
"SieveFolderName" = "Síur";
"OtherUsersFolderName" = "Aðrir Notendur";
@@ -0,0 +1,2 @@
"SieveFolderName" = "Filtri";
"OtherUsersFolderName" = "Altri Utenti";
+10 -2
View File
@@ -417,12 +417,20 @@
{
if (!ignoreContent)
{
[result appendString: [NSString stringWithCharacters: characters length: length]];
// Append a text node
if (ignoreContentTags)
// We are converting a HTML message to plain text (htmlToTextContentHandler):
// include the HTML tags in the text
[result appendString: [NSString stringWithCharacters: characters length: length]];
else
// We are sanitizing an HTML message (sanitizerContentHandler):
// escape the HTML entitites so they are visible
[result appendString: [[NSString stringWithCharacters: characters length: length] stringByEscapingHTMLString]];
}
}
- (void) ignorableWhitespace: (unichar *) whitespaces
length: (int) length
length: (NSUInteger) length
{
showWhoWeAre();
}
@@ -0,0 +1,2 @@
"SieveFolderName" = "Filter";
"OtherUsersFolderName" = "Andre brukere";
@@ -0,0 +1,2 @@
"SieveFolderName" = "Filter";
"OtherUsersFolderName" = "Other Users";
@@ -0,0 +1,2 @@
"OtherUsersFolderName" = "Inni użytkownicy";
"SharedFoldersName" = "Foldery współdzielone";
@@ -0,0 +1,2 @@
"OtherUsersFolderName" = "Другие пользователи";
"SharedFoldersName" = "Общие папки";
+14 -4
View File
@@ -1,20 +1,21 @@
/*
Copyright (C) 2007-2014 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of OpenGroupware.org.
This file is part of SOGo.
OGo is free software; you can redistribute it and/or modify it under
SOGo is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
OGo is distributed in the hope that it will be useful, but WITHOUT ANY
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public
License along with OGo; see the file COPYING. If not, write to the
License along with SOGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
@@ -52,6 +53,7 @@
{
NSString *path;
int IMAP4ID;
int sourceIMAP4ID;
NSMutableDictionary *headers;
NSString *inReplyTo;
NSString *text;
@@ -78,11 +80,17 @@
- (BOOL) isHTML;
/* for replies and forwards */
- (NSString *) inReplyTo;
- (void) setInReplyTo: (NSString *) newInReplyTo;
- (void) setSourceURL: (NSString *) newSurceURL;
- (void) setSourceFlag: (NSString *) newSourceFlag;
- (void) setSourceFolder: (NSString *) newSourceFolder;
- (NSString *) sourceFolder;
- (void) setSourceIMAP4ID: (int) newSourceIMAPID;
- (int) sourceIMAP4ID;
- (void) setIMAP4ID: (int) newIMAPID;
- (int) IMAP4ID;
@@ -102,6 +110,8 @@
- (NSData *) mimeMessageAsData;
/* operations */
- (NSArray *) allRecipients;
- (NSArray *) allBareRecipients;
- (NSException *) delete;
- (NSException *) sendMail;
+184 -36
View File
@@ -45,6 +45,7 @@
#import <NGImap4/NGImap4Client.h>
#import <NGImap4/NGImap4Envelope.h>
#import <NGImap4/NGImap4EnvelopeAddress.h>
#import <NGMail/NGMailAddressParser.h>
#import <NGMail/NGMimeMessage.h>
#import <NGMail/NGMimeMessageGenerator.h>
#import <NGMime/NGMimeBodyPart.h>
@@ -63,6 +64,11 @@
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <NGCards/NGVCard.h>
#import <Contacts/SOGoContactFolders.h>
#import <Contacts/SOGoContactGCSEntry.h>
#import "NSData+Mail.h"
#import "NSString+Mail.h"
#import "SOGoMailAccount.h"
@@ -191,6 +197,7 @@ static NSString *userAgent = nil;
{
if ((self = [super init]))
{
sourceIMAP4ID = -1;
IMAP4ID = -1;
headers = [NSMutableDictionary new];
text = @"";
@@ -228,8 +235,7 @@ static NSString *userAgent = nil;
{
if (!path)
{
path = [[self userSpoolFolderPath] stringByAppendingPathComponent:
nameInContainer];
path = [[self userSpoolFolderPath] stringByAppendingPathComponent: nameInContainer];
[path retain];
}
@@ -260,7 +266,7 @@ static NSString *userAgent = nil;
{
id headerValue;
unsigned int count;
NSString *messageID, *priority, *pureSender, *replyTo;
NSString *messageID, *priority, *pureSender, *replyTo, *receipt;
for (count = 0; count < 8; count++)
{
@@ -279,26 +285,57 @@ static NSString *userAgent = nil;
[headers setObject: messageID forKey: @"message-id"];
}
priority = [newHeaders objectForKey: @"priority"];
if (!priority || [priority isEqualToString: @"NORMAL"])
priority = [newHeaders objectForKey: @"X-Priority"];
if (priority)
{
[headers removeObjectForKey: @"X-Priority"];
}
else if ([priority isEqualToString: @"HIGHEST"])
{
[headers setObject: @"1 (Highest)" forKey: @"X-Priority"];
}
else if ([priority isEqualToString: @"HIGH"])
{
[headers setObject: @"2 (High)" forKey: @"X-Priority"];
}
else if ([priority isEqualToString: @"LOW"])
{
[headers setObject: @"4 (Low)" forKey: @"X-Priority"];
// newHeaders come from MIME message; convert X-Priority to Web representation
[headers setObject: priority forKey: @"X-Priority"];
[headers removeObjectForKey: @"priority"];
if ([priority isEqualToString: @"1 (Highest)"])
{
[headers setObject: @"HIGHEST" forKey: @"priority"];
}
else if ([priority isEqualToString: @"2 (High)"])
{
[headers setObject: @"HIGH" forKey: @"priority"];
}
else if ([priority isEqualToString: @"4 (Low)"])
{
[headers setObject: @"LOW" forKey: @"priority"];
}
else if ([priority isEqualToString: @"5 (Lowest)"])
{
[headers setObject: @"LOWEST" forKey: @"priority"];
}
}
else
{
[headers setObject: @"5 (Lowest)" forKey: @"X-Priority"];
// newHeaders come from Web form; convert priority to MIME header representation
priority = [newHeaders objectForKey: @"priority"];
if (!priority || [priority isEqualToString: @"NORMAL"])
{
[headers removeObjectForKey: @"X-Priority"];
}
else if ([priority isEqualToString: @"HIGHEST"])
{
[headers setObject: @"1 (Highest)" forKey: @"X-Priority"];
}
else if ([priority isEqualToString: @"HIGH"])
{
[headers setObject: @"2 (High)" forKey: @"X-Priority"];
}
else if ([priority isEqualToString: @"LOW"])
{
[headers setObject: @"4 (Low)" forKey: @"X-Priority"];
}
else
{
[headers setObject: @"5 (Lowest)" forKey: @"X-Priority"];
}
if (priority)
{
[headers setObject: priority forKey: @"priority"];
}
}
replyTo = [headers objectForKey: @"replyTo"];
@@ -308,14 +345,30 @@ static NSString *userAgent = nil;
}
[headers removeObjectForKey: @"replyTo"];
if ([[newHeaders objectForKey: @"receipt"] isEqualToString: @"true"])
receipt = [newHeaders objectForKey: @"Disposition-Notification-To"];
if ([receipt length] > 0)
{
pureSender = [[newHeaders objectForKey: @"from"] pureEMailAddress];
if (pureSender)
[headers setObject: pureSender forKey: @"Disposition-Notification-To"];
[headers setObject: @"true" forKey: @"receipt"];
[headers setObject: receipt forKey: @"Disposition-Notification-To"];
}
else
[headers removeObjectForKey: @"Disposition-Notification-To"];
{
receipt = [newHeaders objectForKey: @"receipt"];
if ([receipt isEqualToString: @"true"])
{
[headers setObject: receipt forKey: @"receipt"];
pureSender = [[newHeaders objectForKey: @"from"] pureEMailAddress];
if (pureSender)
{
[headers setObject: pureSender forKey: @"Disposition-Notification-To"];
}
}
else
{
[headers removeObjectForKey: @"receipt"];
[headers removeObjectForKey: @"Disposition-Notification-To"];
}
}
}
- (NSDictionary *) headers
@@ -343,6 +396,11 @@ static NSString *userAgent = nil;
return isHTML;
}
- (NSString *) inReplyTo
{
return inReplyTo;
}
- (void) setInReplyTo: (NSString *) newInReplyTo
{
ASSIGN (inReplyTo, newInReplyTo);
@@ -408,6 +466,9 @@ static NSString *userAgent = nil;
forKey: @"isHTML"];
if (inReplyTo)
[infos setObject: inReplyTo forKey: @"inReplyTo"];
if (sourceIMAP4ID > -1)
[infos setObject: [NSString stringWithFormat: @"%i", sourceIMAP4ID]
forKey: @"sourceIMAP4ID"];
if (IMAP4ID > -1)
[infos setObject: [NSString stringWithFormat: @"%i", IMAP4ID]
forKey: @"IMAP4ID"];
@@ -455,6 +516,10 @@ static NSString *userAgent = nil;
[self setText: value];
isHTML = [[infoDict objectForKey: @"isHTML"] boolValue];
value = [infoDict objectForKey: @"sourceIMAP4ID"];
if (value)
[self setSourceIMAP4ID: [value intValue]];
value = [infoDict objectForKey: @"IMAP4ID"];
if (value)
[self setIMAP4ID: [value intValue]];
@@ -506,6 +571,22 @@ static NSString *userAgent = nil;
[self debugWithFormat: @"Note: info object does not yet exist: %@", p];
}
//
//
//
- (void) setSourceIMAP4ID: (int) newSourceIMAP4ID
{
sourceIMAP4ID = newSourceIMAP4ID;
}
//
//
//
- (int) sourceIMAP4ID
{
return sourceIMAP4ID;
}
//
//
//
@@ -552,7 +633,7 @@ static NSString *userAgent = nil;
{
if (IMAP4ID > -1)
error = [imap4 markURLDeleted: [self imap4URL]];
IMAP4ID = [self IMAP4IDFromAppendResult: result];
[self setIMAP4ID: [self IMAP4IDFromAppendResult: result]];
if (imap4URL)
{
// Invalidate the IMAP message URL since the message ID has changed
@@ -799,8 +880,10 @@ static NSString *userAgent = nil;
{
NSString *subject, *msgid;
NSMutableDictionary *info;
NSDictionary *h;
NSMutableArray *addresses;
NGImap4Envelope *sourceEnvelope;
id priority, receipt;
[sourceMail fetchCoreInfos];
@@ -830,12 +913,19 @@ static NSString *userAgent = nil;
[self _addEMailsOfAddresses: [sourceEnvelope replyTo] toArray: addresses];
if ([addresses count] > 0)
[info setObject: addresses forKey: @"replyTo"];
h = [sourceMail mailHeaders];
priority = [h objectForKey: @"x-priority"];
if ([priority isNotEmpty] && [priority isKindOfClass: [NSString class]])
[info setObject: (NSString*)priority forKey: @"X-Priority"];
receipt = [h objectForKey: @"disposition-notification-to"];
if ([receipt isNotEmpty] && [receipt isKindOfClass: [NSString class]])
[info setObject: (NSString*)receipt forKey: @"Disposition-Notification-To"];
[self setHeaders: info];
[self setText: [sourceMail contentForEditing]];
[self setSourceURL: [sourceMail imap4URLString]];
[self setIMAP4ID: [[sourceMail nameInContainer] intValue]];
[self setSourceFolderWithMailObject: sourceMail];
[self storeInfo];
}
@@ -857,7 +947,7 @@ static NSString *userAgent = nil;
sourceEnvelope = [sourceMail envelope];
[self _fillInReplyAddresses: info replyToAll: toAll
envelope: sourceEnvelope];
envelope: sourceEnvelope];
msgID = [sourceEnvelope messageID];
if ([msgID length] > 0)
[self setInReplyTo: msgID];
@@ -865,7 +955,7 @@ static NSString *userAgent = nil;
[self setHeaders: info];
[self setSourceURL: [sourceMail imap4URLString]];
[self setSourceFlag: @"Answered"];
[self setIMAP4ID: [[sourceMail nameInContainer] intValue]];
[self setSourceIMAP4ID: [[sourceMail nameInContainer] intValue]];
[self setSourceFolderWithMailObject: sourceMail];
[self storeInfo];
@@ -888,7 +978,7 @@ static NSString *userAgent = nil;
[self setSourceURL: [sourceMail imap4URLString]];
[self setSourceFlag: @"$Forwarded"];
[self setIMAP4ID: [[sourceMail nameInContainer] intValue]];
[self setSourceIMAP4ID: [[sourceMail nameInContainer] intValue]];
[self setSourceFolderWithMailObject: sourceMail];
/* attach message */
@@ -913,7 +1003,7 @@ static NSString *userAgent = nil;
@"message/rfc822", @"mimetype",
nil];
[self saveAttachment: [sourceMail content]
withMetadata: attachment];
withMetadata: attachment];
}
[self storeInfo];
@@ -1538,10 +1628,11 @@ static NSString *userAgent = nil;
/* add subject */
if ([(s = [headers objectForKey: @"subject"]) length] > 0)
[map setObject: [s asQPSubjectString: @"utf-8"]
forKey: @"subject"];
[map setObject: [headers objectForKey: @"message-id"]
forKey: @"message-id"];
forKey: @"subject"];
if ([(s = [headers objectForKey: @"message-id"]) length] > 0)
[map setObject: s
forKey: @"message-id"];
/* add standard headers */
dateString = [[NSCalendarDate date] rfc822DateString];
@@ -1660,7 +1751,7 @@ static NSString *userAgent = nil;
{
recipients = [headers objectForKey: fieldNames[count]];
if ([recipients count] > 0)
[allRecipients addObjectsFromArray: recipients];
[allRecipients addObjectsFromArray: recipients];
}
return allRecipients;
@@ -1689,6 +1780,63 @@ static NSString *userAgent = nil;
//
- (NSException *) sendMail
{
SOGoUserDefaults *ud;
ud = [[context activeUser] userDefaults];
if ([ud mailAddOutgoingAddresses])
{
Class contactGCSEntry;
SOGoContactFolders *contactFolders;
SOGoContactFolder *folder;
SOGoContactGCSEntry *newContact;
NGVCard *card;
NGMailAddressParser *parser;
NSArray *matchingContacts;
NSMutableArray *recipients;
NSString *recipient, *emailAddress, *addressBook, *uid;
id parsedRecipient;
int i;
// Get all the addressbooks
contactFolders = [[[context activeUser] homeFolderInContext: context]
lookupName: @"Contacts"
inContext: context
acquire: NO];
// Get all the recipients from the current email
recipients = [self allRecipients];
for (i = 0; i < [recipients count]; i++)
{
// The address contains a string. ex: "John Doe <sogo1@exemple.com>"
recipient = [recipients objectAtIndex: i];
parser = [NGMailAddressParser mailAddressParserWithString: recipient];
parsedRecipient = [parser parse];
emailAddress = [parsedRecipient address];
matchingContacts = [contactFolders allContactsFromFilter: emailAddress
excludeGroups: YES
excludeLists: YES];
}
// If we don't get any results from the autocompletion code, we add it..
if ([matchingContacts count] == 0)
{
// Get the selected addressbook from the user preferences where the new address will be added
addressBook = [ud selectedAddressBook];
folder = [contactFolders lookupName: addressBook inContext: context acquire: NO];
uid = [folder globallyUniqueObjectId];
if (folder && uid)
{
card = [NGVCard cardWithUid: uid];
[card addEmail: emailAddress types: nil];
contactGCSEntry = NSClassFromString(@"SOGoContactGCSEntry");
newContact = [contactGCSEntry objectWithName: uid
inContainer: folder];
[newContact setIsNew: YES];
[newContact saveContentString: [card versitString]];
}
}
}
return [self sendMailAndCopyToSent: YES];
}
+1 -3
View File
@@ -1,8 +1,6 @@
/* SOGoDraftsFolder.m - this file is part of SOGo
*
* Copyright (C) 2007 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2007-2014 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+2
View File
@@ -84,6 +84,8 @@ typedef enum {
- (NSArray *) allFolderPaths;
- (NSArray *) allFoldersMetadata;
- (NSDictionary *) imapFolderGUIDs;
- (BOOL) isInDraftsFolder;
/* special folders */
+58
View File
@@ -60,6 +60,8 @@
#import "SOGoUser+Mailer.h"
#import "SOGoMailAccount.h"
#import <Foundation/NSProcessInfo.h>
#define XMLNS_INVERSEDAV @"urn:inverse:params:xml:ns:inverse-dav"
@@ -659,6 +661,62 @@ static NSString *inboxFolderName = @"INBOX";
return password;
}
- (NSDictionary *) imapFolderGUIDs
{
NSDictionary *result, *nresult, *folderData;
NSMutableDictionary *folders;
NGImap4Client *client;
SOGoUserDefaults *ud;
NSArray *folderList;
NSEnumerator *e;
NSString *guid;
id object;
BOOL subscribedOnly;
ud = [[context activeUser] userDefaults];
subscribedOnly = [ud mailShowSubscribedFoldersOnly];
folderList = [[self imap4Connection] allFoldersForURL: [self imap4URL]
onlySubscribedFolders: subscribedOnly];
folders = [NSMutableDictionary dictionary];
client = [[self imap4Connection] client];
result = [client annotation: @"*" entryName: @"/comment" attributeName: @"value.priv"];
e = [folderList objectEnumerator];
while (object = [e nextObject])
{
guid = [[[[result objectForKey: @"FolderList"] objectForKey: [object substringFromIndex: 1]] objectForKey: @"/comment"] objectForKey: @"value.priv"];
if (!guid)
{
guid = [[NSProcessInfo processInfo] globallyUniqueString];
nresult = [client annotation: [object substringFromIndex: 1] entryName: @"/comment" attributeName: @"value.priv" attributeValue: guid];
if (![[nresult objectForKey: @"result"] boolValue])
{
// Need to implement X-GUID query for Dovecot - this requires modification in SOPE to support following command:
// 1 list "" "*" return (status (x-guid)) -> this would avoid firing a command per folder to IMAP
nresult = [client status: [object substringFromIndex: 1] flags: [NSArray arrayWithObject: @"x-guid"]];
guid = [nresult objectForKey: @"x-guid"];
if (!guid)
{
guid = [NSString stringWithFormat: @"%@", [object substringFromIndex: 1]];
}
}
}
[folders setObject: guid forKey: [object substringFromIndex: 1]];
}
return folders;
}
/* name lookup */
- (id) lookupName: (NSString *) _key
+4 -3
View File
@@ -1,14 +1,15 @@
/*
Copyright (C) 2007-2014 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of OpenGroupware.org.
This file is part of SOGo.
OGo is free software; you can redistribute it and/or modify it under
SOGo is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
OGo is distributed in the hope that it will be useful, but WITHOUT ANY
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
Loaded 100 of 382 files, more files were not shown because too many files have changed in this diff. Show more