Compare commits

...
444 Commits
Author SHA1 Message Date
Francis Lachapelle 072f5f5a15 Merge to 2.2.1 2014-03-07 14:03:41 -05:00
Francis Lachapelle 41fe9195f2 Update ChangeLog 2014-03-07 14:00:51 -05:00
Francis Lachapelle 23789b48bc Update Dutch translation 2014-03-07 14:00:08 -05:00
Francis Lachapelle 142296f71e Preparation for release 2.2.1 2014-03-07 10:53:17 -05:00
Francis Lachapelle 3bae2387d4 Fix contact autocompletion when UID is a digit 2014-03-06 22:13:17 -05:00
Francis Lachapelle 6cecca6c4f Fix CSS id for string prefixed with a digit
When encoding a string as a CSS identifier, we must add an underscore if
the strings starts with a digit.
2014-03-06 21:32:36 -05:00
Francis Lachapelle 28b1938bd9 Show folder name in dialog when renaming folder 2014-03-06 21:25:48 -05:00
Ludovic Marcotte 31ace947cb Fixed race condition when syncing huge amount of deleted messages using AS 2014-03-06 14:16:08 -05:00
Ludovic Marcotte 0cea36df2e Updated NEWS regarding previous commit 2014-03-06 14:10:47 -05:00
Ludovic Marcotte afd7452323 Fixed returned date format and fixing missing 'name part' in address 2014-03-06 14:05:59 -05:00
Francis Lachapelle e4a21bcef5 Webmail: fix encoding of subfolder name
Fixes #2637
2014-03-06 09:50:53 -05:00
Francis Lachapelle 0c99323db3 Fix possible exception when retrieving reminder
Fixes #2624
2014-03-05 13:42:38 -05:00
Ludovic Marcotte da208d5b4a Updated NEWS regarding previous commit 2014-03-05 09:09:33 -05:00
Ludovic Marcotte 158af71152 Fix for bug #2609 2014-03-05 09:07:39 -05:00
Francis Lachapelle 163bce39b5 Fix list sorting of events by calendar name
Fixes #2629
2014-03-04 22:03:28 -05:00
Francis Lachapelle 02c72fee6a Fix unsubscription when renaming an IMAP folder
Fixes #2630
2014-03-04 21:32:57 -05:00
Francis Lachapelle 8bef84bded Update translations 2014-03-04 09:23:17 -05:00
Francis Lachapelle 8db3b22eb9 Bump version to 2.2.0a 2014-03-03 22:08:29 -05:00
Francis Lachapelle 1aabcf04b5 Fix sogo-tool operations on Sieve script
Fixes #2617
2014-03-03 22:07:24 -05:00
Francis Lachapelle 1db85743a0 Merge to 2.2.0 2014-02-24 16:54:11 -05:00
Francis Lachapelle c6b227160c Update ChangeLog 2014-02-24 16:53:46 -05:00
Francis Lachapelle 5f2920db9b Update translations 2014-02-24 16:49:16 -05:00
Francis Lachapelle 761a7e2be1 Update Microsoft Outlook Configuration guide 2014-02-24 16:42:59 -05:00
Francis Lachapelle 9ed1d57ec2 Fix auto-acceptation of resources as attendees
Fixes #2541
2014-02-24 16:07:55 -05:00
Francis Lachapelle 2b6428efd0 Always check resource conflict for new events
Fixes #2541
2014-02-24 07:57:11 -05:00
Francis Lachapelle be36e0ceea Fix view changes in calendar module
Fixes #2613
2014-02-21 20:37:44 -05:00
Francis Lachapelle 070d3dd825 Extract node value with 'textValue' 2014-02-21 15:48:41 -05:00
Francis Lachapelle 96f2552b45 Preparation for release 2.2.0 2014-02-19 21:57:01 -05:00
Francis Lachapelle 2948920e0b Improve display of contact
Fixes #2350
2014-02-18 16:15:06 -05:00
Francis Lachapelle 212d7149ed Fix display of a contact's birthday
Fixes #2503
2014-02-18 10:13:34 -05:00
Ludovic Marcotte 668c7e8b49 Correctly handle email invitations as attendee/organizer 2014-02-17 16:08:29 -05:00
Ludovic Marcotte 9851c32a1e Fixed the handling of organizers 2014-02-17 15:49:22 -05:00
Francis Lachapelle e7f27427c8 Add missing import in UIxPreferences.m 2014-02-17 15:42:55 -05:00
Francis Lachapelle f0a29d3ca2 Fix debian dependencies for sogo-activesync 2014-02-17 15:05:31 -05:00
Ludovic Marcotte ec0a5ac4bf Properly handle event updates/pull when we are or not an attendee/organizer 2014-02-17 11:30:41 -05:00
Ludovic Marcotte 4ca8b9d0aa Copyright updates 2014-02-17 11:30:00 -05:00
Ludovic Marcotte d560d0e470 Always return a response avoiding iOS crashes on no-changes 2014-02-17 11:28:06 -05:00
Francis Lachapelle 401320e08b Contact: fix display of urls 2014-02-17 11:12:09 -05:00
Ludovic Marcotte 8083b41092 Added the context everywhere 2014-02-17 10:01:44 -05:00
Ludovic Marcotte 9218c7f253 Added missing recurrences support, improved MeetingResponse, added WindowSize support.
Also more bug fixes regarding event invitations, and ServerId handling for
calendar objects.
2014-02-17 08:46:05 -05:00
Ludovic Marcotte 4d1fdb33f5 Deleted wrongly added file 2014-02-17 08:42:35 -05:00
Ludovic Marcotte 2356562778 Added method to get synctag starting from an other one.
We also no longer fetch vanished items of modseq == 0
2014-02-17 08:41:12 -05:00
Ludovic Marcotte c686e3294d Added method to sanitize calendar "ServerId" 2014-02-17 08:39:48 -05:00
Ludovic Marcotte 1ff91f7b59 Added -activeSyncRepresentation to NSData objects 2014-02-17 08:38:34 -05:00
Francis Lachapelle b34c6324cd Fix custom mail labels in Sieve filter editor 2014-02-14 21:32:33 -05:00
Ludovic Marcotte 75c8362df8 Avoid over-using LDAP connections when decomposing groups 2014-02-14 16:39:26 -05:00
Ludovic Marcotte ae07de5f6f Updated the Active Sync documentation 2014-02-14 13:46:21 -05:00
Francis Lachapelle 06d2364ea2 Improve display of toolboor menus with checkmarks 2014-02-13 12:56:24 -05:00
Francis Lachapelle 29e081ec56 Add more parameters examples to sogo.conf 2014-02-13 12:53:07 -05:00
Francis Lachapelle 113b02fd71 Fix encoding of contact ID in Ajax requests 2014-02-13 12:12:31 -05:00
Francis Lachapelle 35b108e645 Contact: fix display of links 2014-02-13 12:11:25 -05:00
Ludovic Marcotte 70266155d3 Fix double return 2014-02-12 21:55:09 -05:00
Francis Lachapelle fcfd8be771 Improve URL handling in popup of events 2014-02-10 22:05:35 -05:00
Francis Lachapelle b91032db8e Cleanup common English Localizable.strings 2014-02-10 22:05:35 -05:00
Ludovic Marcotte f4874600fe Bumped to v14.1 2014-02-10 20:17:54 -05:00
Ludovic Marcotte b14e99b32a New prefs for intervals, fixed missing events in meeting requests, bumped v14.1 2014-02-10 20:16:43 -05:00
Francis Lachapelle ea4b21e991 Decode HTML entities in JSON of calendar module 2014-02-10 13:49:02 -05:00
Francis Lachapelle 0307b8339a Detect URLs in popup of events 2014-02-10 13:45:51 -05:00
Francis Lachapelle b5f1d3a19a Guide: add SOGoCalendarDefaultReminder paramter 2014-02-10 11:25:38 -05:00
Ludovic Marcotte 8225f76279 Fixed globalobjid so it doesn't contain \n characters! 2014-02-07 16:17:11 -05:00
Francis Lachapelle c94595ea7f Escape HTML in CSS dialogs 2014-02-07 16:12:14 -05:00
Francis Lachapelle 3a5e44e7eb Decode HTML entities in JSON of calendar module 2014-02-07 15:53:39 -05:00
Francis Lachapelle 80a0940765 Escape HTML in JSON of contacts module 2014-02-07 15:52:43 -05:00
Francis Lachapelle 7118bbe0ab Replace '/' by '-' in filenames of attachments
Fixes #2537
2014-02-07 14:00:36 -05:00
Francis Lachapelle eee5beb698 Add message-id header to appointment notification
Fixes #2535
2014-02-07 10:52:06 -05:00
Ludovic Marcotte 3363b253ac Set additional properties on meeting requests 2014-02-07 10:45:09 -05:00
Francis Lachapelle 4070b9222d Rework HTML of appointment notifications
Needed to simplify the HTML so it displays properly in Outlook.

Fixes #2233
2014-02-07 09:59:45 -05:00
Francis Lachapelle 5ea56a6f8a Enlarge the note field of the contact editor 2014-02-06 21:55:28 -05:00
Ludovic Marcotte 379258de59 Pimped the doc for AS support and dropped all references to Funambol. 2014-02-06 21:25:08 -05:00
Ludovic Marcotte 93b3685aa4 Added birthday support 2014-02-06 19:35:23 -05:00
Ludovic Marcotte c4dc4d4eda Fixed compilation warning 2014-02-06 17:59:33 -05:00
Ludovic Marcotte c6d104fac5 Fixed contact sync'ing on Android 2014-02-06 17:57:01 -05:00
Francis Lachapelle ef79c09642 Don't use the HTML editor with Internet Explorer 7 2014-02-06 14:43:05 -05:00
Francis Lachapelle aeb712083a Fix static array retain 2014-02-06 14:37:43 -05:00
Francis Lachapelle 2c678101fc Fix handling of ACLs with multiple groups
Fixes #1854
2014-02-06 14:23:09 -05:00
Ludovic Marcotte b95362f963 Now make use of a NGMimeFileData object to avoid broken SOPE behaviour 2014-02-06 14:05:00 -05:00
Ludovic Marcotte 3175a9169f Mapped lots of contact properties 2014-02-05 20:56:01 -05:00
Ludovic Marcotte 9311f05cc0 Fixed the non-filtering of recurrence exceptions 2014-02-05 17:30:34 -05:00
Francis Lachapelle 78cbcfb560 Update translations 2014-02-05 16:15:30 -05:00
Ludovic Marcotte b8610b3eca Extended GetItemEstimate to GCS collections 2014-02-05 16:12:08 -05:00
Francis Lachapelle 1a7fc2a0e9 Escape HTML in JSON of calendar module
Fixes #2598
2014-02-05 16:06:20 -05:00
Ludovic Marcotte f7a20d0a83 Fixed broken encoding of single-value element 2014-02-05 15:23:09 -05:00
Francis Lachapelle a1cf066828 Update translations 2014-02-05 11:43:25 -05:00
Francis Lachapelle 359b6a99aa Encode HTML entities for inline forwards in text
Fixes #2411
2014-02-05 11:17:22 -05:00
Francis Lachapelle 826537ed01 Fix caching of DN in LDAP source 2014-02-05 09:04:00 -05:00
Ludovic Marcotte 3950e9d4c3 Moved DN cache to SOGoCache 2014-02-04 21:03:11 -05:00
Francis Lachapelle 9885211a5b Replace VARCHAR(1000000) by TEXT field type
Fixes #2516
2014-02-04 17:55:49 -05:00
Francis Lachapelle ef1be5dc5f Improve deleting occurences of recurrent events 2014-02-04 17:55:49 -05:00
Ludovic Marcotte 4e42d5d410 Disabled debugging... 2014-02-04 15:07:23 -05:00
Ludovic Marcotte 31969d162d Properly escape some control chars (and generalized it) 2014-02-04 15:03:02 -05:00
Ludovic Marcotte 2ff3b5ef5f First pass at 'push' support for Ping and Sync 2014-02-04 11:19:33 -05:00
Ludovic Marcotte 7fe48a1555 Fix for bug #2544 2014-02-04 09:02:40 -05:00
Francis Lachapelle fcddeb4224 Visually identify users with no freebusy
Fixes #2565
2014-02-03 15:15:14 -05:00
Francis Lachapelle f1cb87aa02 Convert JS alerts to CSS dialogs in aptmt editor 2014-02-03 12:03:51 -05:00
Francis Lachapelle a6424680cc Respect max bookings of resources in freebusy data
Fixes #2560
2014-02-03 11:56:00 -05:00
Francis Lachapelle b3dc645282 Warn user when dnd failed with resource conflict
Fixes #1613
2014-02-03 11:09:03 -05:00
Francis Lachapelle 2f0419c18a Warn user when overbooking a resource
Fixes #2541
2014-02-03 11:03:23 -05:00
Ludovic Marcotte 9e9407cf30 First pass at event invitations support + few bug fixes. 2014-02-03 10:24:33 -05:00
Ludovic Marcotte d709a1216b Updated NEWS file 2014-02-03 09:54:21 -05:00
Ludovic Marcotte 588352be7d Fix for bug #2587 2014-02-03 09:53:47 -05:00
Ludovic Marcotte a40d7ca342 Updated NEWS file 2014-01-31 15:11:13 -05:00
Ludovic Marcotte e4ce687e29 Update the content when the request is from Active Sync 2014-01-31 15:05:33 -05:00
Ludovic Marcotte bcb0764b19 Fix for bug #2505 2014-01-31 15:04:49 -05:00
Ludovic Marcotte ddd7be4333 Fix for bug #2187 2014-01-31 15:03:40 -05:00
Ludovic Marcotte d9f4a9935a Properly escape all foldernames 2014-01-31 10:33:36 -05:00
Francis Lachapelle ae75fee512 Update NEWS file 2014-01-30 10:37:36 -05:00
Ludovic Marcotte 8cdacd065f Properly escape the filename 2014-01-30 08:25:55 -05:00
Ludovic Marcotte af6a69c9fc Expunge immediately after MoveItems to force the Delete response 2014-01-29 11:21:36 -05:00
Ludovic Marcotte dc41e29f05 Fixed the MoveItems response 2014-01-29 11:16:58 -05:00
Ludovic Marcotte afc7519beb Properly escape values 2014-01-29 10:30:31 -05:00
Ludovic Marcotte f2d5a76911 Type fix for recurrence rules. 2014-01-29 09:48:18 -05:00
Francis Lachapelle 342ad84a24 Fix issues with contextual menu in calendars
Creating an event or a task using the contextual menu will now consider
the day and hour of the menu position (fixes #2557).
The next/previous day/month menu options have been fixed.
The menu will now disappear when clicking outside the contextual menu on
the calendar area.
2014-01-28 15:42:02 -05:00
Ludovic Marcotte 9580a8f8ee Added initial support for recurring events. 2014-01-28 14:26:35 -05:00
Ludovic Marcotte a96380a0dc Fixed SyncKey issue not being updated during the sync operation 2014-01-28 13:51:21 -05:00
Ludovic Marcotte 2fed02da59 When creating a new object, mark it as new. 2014-01-28 13:21:34 -05:00
Francis Lachapelle 84dc08adb6 Fix display of folder names in filter editor
Fixes #2569
2014-01-27 15:43:48 -05:00
Francis Lachapelle c160edf20a Add support for Sieve body extension 2014-01-27 15:09:22 -05:00
Ludovic Marcotte 3b7a3c94d4 Properly escape fields and improved data dumps. 2014-01-27 11:30:43 -05:00
Ludovic Marcotte 7b97e28cff Fixed compiler warning 2014-01-24 16:33:31 -05:00
Ludovic Marcotte 81bf1b41e9 Fixed the rename operation to force a FolderSync 2014-01-24 16:28:08 -05:00
Ludovic Marcotte ea86f136b7 Properly escape folder/file names and fixed date representation in emails 2014-01-24 14:10:19 -05:00
Francis Lachapelle fc0c580fe1 Fix validation of subscribed folders
Fixes #2583
2014-01-24 13:48:01 -05:00
Ludovic Marcotte 42a7bcb9ac Added verbosity in case wbxml <-> xml conversions fail 2014-01-24 11:44:12 -05:00
Ludovic Marcotte 9669f2bbba Added more props and fixed the NativeBodyType preventing OL2013 to work 2014-01-24 11:09:37 -05:00
Ludovic Marcotte 2563408872 Improved the README regarding MS licensing 2014-01-24 07:38:03 -05:00
Ludovic Marcotte dbea244f49 Merge branch 'master' of https://github.com/inverse-inc/sogo 2014-01-24 07:37:52 -05:00
Francis Lachapelle 0f9d8cdd2c Remove xml tag before doctype declaration 2014-01-23 14:48:36 -05:00
Francis Lachapelle 5105dbb342 Make all attachments available when re/fwd'ing
To do so, we save the draft to the mailstore.
2014-01-23 14:39:03 -05:00
Francis Lachapelle b26e767a10 Respect signature placement when forwarding a msg 2014-01-23 14:34:44 -05:00
Francis Lachapelle 940f85fde2 Add missing localizable string to webmail 2014-01-23 11:25:14 -05:00
Ludovic Marcotte adee80529e Added more event props and fixed date issues 2014-01-23 11:09:32 -05:00
Francis Lachapelle 295dfcfdd5 Webmail: allow the backspace on any platform 2014-01-23 10:21:22 -05:00
Ludovic Marcotte aa18abd842 Added more props and cleaned up the code 2014-01-23 09:41:41 -05:00
Francis Lachapelle feb398d59c Fix IE11 issue with mail editor 2014-01-23 09:15:34 -05:00
Francis Lachapelle 19b404de45 Update French translation 2014-01-23 08:17:16 -05:00
Jean Raby d1a384e539 Send IMIP responses if the event is in the future
Avoids sending responses for past events when importing events into
a new calendar from thunderbird or any DAV client.
2014-01-22 11:40:04 -05:00
Ludovic Marcotte e7f38f940e Moved the cards' logic into a category and added support for more AS ones 2014-01-22 11:27:27 -05:00
Ludovic Marcotte f7ba5d2346 Don't add DateCompleted if none exist 2014-01-22 11:25:18 -05:00
Ludovic Marcotte eeddf43a78 Add the milliseconds 2014-01-22 11:22:52 -05:00
Ludovic Marcotte eabe829236 Don't add empty <Commands> and specify the folder Class 2014-01-22 11:02:12 -05:00
Ludovic Marcotte 762b841249 Avoid crashes on broken configurations 2014-01-21 16:40:57 -05:00
Francis Lachapelle 3090448fcb Update prototype.js to fix IE 10 issues
Updated to commit @8c9ead49ec of
https://github.com/sstephenson/prototype/
2014-01-20 15:43:33 -05:00
Ludovic Marcotte a3e1d4813a Removed debug + refactored NSDate class 2014-01-20 10:21:33 -05:00
Ludovic Marcotte 046a645119 Refactored the code and added support for FilterType 2014-01-20 10:13:16 -05:00
Ludovic Marcotte 07d4b2bae2 Merge branch 'master' of https://github.com/inverse-inc/sogo 2014-01-16 15:13:29 -05:00
Ludovic Marcotte 343f2d8bfe Fixed the GetChanges detection and added FilterType decoding 2014-01-16 15:13:09 -05:00
Jean Raby 65276f7dc0 Add dependency on tmpwatch. The cronjob uses it.
Fixes #2577
2014-01-15 16:37:24 -05:00
Jean Raby 24663682d6 New package: sogo-activesync + sogo-tool fixes
Added dependency on sogo = %version for sogo-tool
2014-01-15 12:08:29 -05:00
Jean Raby 57cd315f2a explicitly list all *.SOGo folders
Otherwise, ActiveSync.SOGo would be listed twice, once in sogo-activesync and
once in sogo.
2014-01-15 11:07:14 -05:00
Ludovic Marcotte 29fcfda118 Implemented FolderDelete for mail folders 2014-01-15 09:36:25 -05:00
Ludovic Marcotte ada90677e1 Correctly update the SyncKey when creating or updating folders 2014-01-14 16:08:04 -05:00
Ludovic Marcotte 4c9c07e358 Merge branch 'master' of https://github.com/inverse-inc/sogo 2014-01-14 15:47:52 -05:00
Ludovic Marcotte b71180b006 Use the right DeviceId 2014-01-14 15:47:33 -05:00
Jean Raby 1ed41e2831 New deb package: sogo-activesync 2014-01-14 14:39:51 -05:00
Ludovic Marcotte 948553dce3 Properly extract the foldername 2014-01-14 13:50:17 -05:00
Jean Raby 74adf78446 Fix include directories for libwbxml 2014-01-14 13:37:51 -05:00
Ludovic Marcotte ee0ae8a1c0 Correctly add the folder type prefix when creating them 2014-01-14 11:44:33 -05:00
Ludovic Marcotte 38c649751c If GetChanges is omitted, consider it as YES 2014-01-14 11:41:26 -05:00
Ludovic Marcotte 645c718dfa Fixed broken comparison and added stub for processMeeting... 2014-01-14 10:49:55 -05:00
Ludovic Marcotte 02992a7018 Correctly decode base64 text parts before returning them 2014-01-14 10:42:15 -05:00
Ludovic Marcotte 0ffa0649c5 Wrap Fetch responses into <Responses> tags so iOS works correctly 2014-01-14 10:09:10 -05:00
Ludovic Marcotte 7c7cabe432 First pass at organizer/attendees support 2014-01-13 16:25:14 -05:00
Ludovic Marcotte bb9c4cf039 Handle not found objects and correctly get all "Collection" 2014-01-13 16:24:15 -05:00
Ludovic Marcotte c252f5b7a8 Fixed the license indent 2014-01-13 11:46:32 -05:00
Ludovic Marcotte 2e44ac0f9b Fixed MoveItems and also fixed Ping with no content 2014-01-13 10:19:00 -05:00
Ludovic Marcotte 2a9ccf8122 Now able to grab the command from the URI 2014-01-13 10:18:20 -05:00
Ludovic Marcotte f74066c9a6 Support for more props 2014-01-11 19:31:39 -05:00
Ludovic Marcotte ee49836f2e Disabled debugging... 2014-01-10 16:49:40 -05:00
Ludovic Marcotte bf798061d3 Fixed timezones support for events and added more supported props 2014-01-10 16:48:39 -05:00
Ludovic Marcotte 834e05bab1 Fixed typo messing up adds 2014-01-10 15:29:57 -05:00
Ludovic Marcotte e8438a6235 Don't write decoded stuff if not needed 2014-01-10 14:53:49 -05:00
Ludovic Marcotte 68dafdfdeb Removed old comments 2014-01-10 14:25:00 -05:00
Ludovic Marcotte e5bc46710c Initial Active Sync Support! 2014-01-10 14:12:53 -05:00
Ludovic Marcotte 7355eae1dc Now able to set Active Sync metadata in the user settings 2014-01-10 14:10:53 -05:00
Ludovic Marcotte 1d9febb511 Correctly handle the Active Sync requests 2014-01-10 14:10:16 -05:00
Ludovic Marcotte e21b30d768 Code cleanups 2014-01-10 14:09:32 -05:00
Ludovic Marcotte ae200360ba Code cleanups 2014-01-10 14:09:02 -05:00
Ludovic Marcotte e217ffb6c4 Code generalization to be usable from the ActiveSync bundle 2014-01-10 14:08:12 -05:00
Ludovic Marcotte a4a3a735b4 Moved the folder metadata generation to SoObject and added 'tag based' sync'ing support for IMAP 2014-01-10 14:06:53 -05:00
Ludovic Marcotte 13721b961b Add an easy way to get the personal contact folder, just like we have for calendars 2014-01-10 14:03:50 -05:00
Ludovic Marcotte 689a1e94e0 Sample Active Sync configuration 2014-01-10 14:02:32 -05:00
Ludovic Marcotte afcd92fb71 Load the ActiveSync bundle code and bind it 2014-01-10 14:01:39 -05:00
Ludovic Marcotte 7260c07628 More cleanups 2014-01-09 21:10:48 -05:00
Ludovic Marcotte a24d809e40 Minor code/copyright/authors cleanups 2014-01-09 21:06:31 -05:00
Ludovic Marcotte ed97407578 Dropped old data types 2014-01-09 20:42:16 -05:00
Ludovic Marcotte ca541d7299 Cleanups in conf file 2014-01-09 20:41:16 -05:00
Ludovic Marcotte 2d683ffc77 Always capitalize HTTP headers 2014-01-09 20:40:25 -05:00
Francis Lachapelle d603a8672e Consider 'background' attribute as unsafe
When loading a message, background attributes will be disabled if the
user as chosen to not automatically load external images.

Fixes #2437
2014-01-09 09:15:49 -05:00
Francis Lachapelle d51e1da57f Increase height of signature editor 2014-01-08 15:02:41 -05:00
Francis Lachapelle 80fd439dea Fix message forwarding as attachment
Restored the filename of the message source in the body part
content-disposition header.
Also forced the mail to be saved to the mailstore immediately in order
to have a clickable link to the attached message.
2014-01-08 14:40:39 -05:00
Francis Lachapelle a0d7f184fe Update French translation 2014-01-07 11:51:35 -05:00
Francis Lachapelle fe2826ca76 Draft: Improve error handling when attaching files 2014-01-07 11:11:39 -05:00
Francis Lachapelle ff9ea3b779 Don't alter the draft when saving it
We must not extract inline HTML images when simply saving a draft. The
images extraction process must only be performed when sending the
message.
2014-01-07 10:28:53 -05:00
Francis Lachapelle e70793e7ae Don't follow link of attachment not yet uploaded 2014-01-06 15:09:09 -05:00
Francis Lachapelle 0fdea48ce8 Restore CSS of disabled menu options 2014-01-06 15:08:45 -05:00
Francis Lachapelle 2b53705d44 Untabify 2014-01-06 14:32:58 -05:00
Francis Lachapelle b716331d8e Append tags when using a sanitizerContentHandler 2014-01-06 14:23:11 -05:00
Jean Raby 586d66b113 Updated description of SOGoUIAdditionalJSFiles
Document that the files must be placed under the  WebServerResources directory
2014-01-06 13:28:47 -05:00
Francis Lachapelle 5756defbf1 Mail editor: don't give focus to file input field. 2014-01-06 11:10:28 -05:00
Francis Lachapelle 7130cec4d1 Move & copy messages between different accounts 2014-01-03 16:57:37 -05:00
Francis Lachapelle 009cfccb2c Fix JS error when saving/sending plain text msg 2014-01-03 14:33:27 -05:00
Francis Lachapelle 09e14df79b Preferences: fix display of calendar categories 2014-01-03 14:32:48 -05:00
Francis Lachapelle ba29e7620d Update French translation 2014-01-03 14:32:01 -05:00
Francis Lachapelle 32516b162e Update textarea before saving/sending HTML message 2013-12-31 15:52:15 -05:00
Francis Lachapelle a8e780516b Fix display of "edit draft" and "load images"
The buttons were placed one over the other.
2013-12-23 15:54:22 -05:00
Francis Lachapelle bd7ad5be16 Fix initialization of arrays in NSString+Mail.m 2013-12-23 15:51:36 -05:00
Francis Lachapelle bed57af015 Improve display of linked attachments 2013-12-20 16:18:19 -05:00
Francis Lachapelle 5f369f201d Add links to download one or all attachments
Also removed the contextual menu over file attachments and changed the
label color when moving over the file attachments.
2013-12-20 15:41:18 -05:00
Francis Lachapelle dc21c723f6 Move method fetchFileAttachmentKeys from category
Moved fetchFileAttachmentKeys from SOGoDraftObjectExtensions to
SOGoDraftObject. Renamed fetchAttachmentIds to fetchFileAttachmentIds
for consistency.
2013-12-20 15:20:16 -05:00
Francis Lachapelle 1f7994d1bf Respect locale in time format of attendees window 2013-12-18 22:18:08 -05:00
Francis Lachapelle 7369a82bab Improve upload of attachments to messages 2013-12-18 22:18:08 -05:00
Francis Lachapelle 1a900b05d9 DraftObject: return more attachments attributes 2013-12-18 22:18:08 -05:00
Francis Lachapelle a8e3418a4c Use the UIxMailSizeFormatter in messages listing 2013-12-18 22:18:08 -05:00
Francis Lachapelle 59ce12a51b Load XMLHttpRequest conditionally (< IE9) 2013-12-18 22:18:08 -05:00
Ludovic Marcotte a1bec0e995 Merge branch 'master' of https://github.com/inverse-inc/sogo 2013-12-16 17:48:50 -05:00
Ludovic Marcotte 08ab36244c Improved the logic behind refusing too-many submitted mails. 2013-12-16 17:48:23 -05:00
Jean Raby 9ea880e80b fix backup path 2013-12-11 14:36:28 -05:00
Ludovic Marcotte 7d0a9aa1b7 Cleanups. 2013-12-10 20:09:32 -05:00
Jean Raby 2fa654fadb sogo.conf: fix typo and add AD/Samba4 example 2013-12-10 15:55:44 -05:00
Ludovic Marcotte 4a98e5b521 Don't append unknown objects to the REPORT result. 2013-12-09 10:31:34 -05:00
Francis Lachapelle e5103faed4 Update Finnish translation 2013-12-05 21:33:09 -05:00
Francis Lachapelle f9ad9ea815 Bump version to 2.1.2 2013-12-05 21:10:03 -05:00
Francis Lachapelle cfbd53e374 Fix initialization of preferences module
Don't try to initialize the tabs controller on the mail options tab if
the mail module is disabled.
2013-12-05 09:00:01 -05:00
Jean Raby f2beabec88 document organization and country ldap mapping 2013-12-04 19:50:22 -05:00
Jean Raby eaa0fb3cf1 Update NEWS CKEditor is in 2.1.1b 2013-12-04 11:11:10 -05:00
Jean Raby db56d1fa6c Bump version to 2.1.1b + adjust NEWS 2013-12-04 10:33:48 -05:00
Francis Lachapelle 37de8c6141 CKEditor: don't filter tags 2013-12-02 13:42:34 -05:00
Francis Lachapelle b0eb34f6b7 Add 'div' plugin to CKEditor 2013-12-02 11:58:28 -05:00
Francis Lachapelle 1cf696f57c Mail composition: add text part before html part
Fixes #2512
2013-11-25 09:52:18 -05:00
Francis Lachapelle 2114a48222 Update NEWS file 2013-11-22 15:03:57 -05:00
Francis Lachapelle 384d998c47 Cleanup wox templates 2013-11-22 14:42:16 -05:00
Francis Lachapelle 2211f6d168 Move mail tags strings to UI/Common 2013-11-22 14:39:24 -05:00
Ludovic Marcotte 32ba01315f Init local variable to avoid potential crasher. 2013-11-22 11:29:24 -05:00
Francis Lachapelle 682ed767d9 Fix the Sieve filters editor with new mail flags 2013-11-21 08:52:55 -05:00
Jean Raby 5536f8967e don't escape html in label names 2013-11-21 07:11:05 -05:00
Ludovic Marcotte df3e9033f3 Added calendar default reminder support. 2013-11-20 17:42:11 -05:00
Francis Lachapelle f167475c91 Update CKEditor to version 4.3.0 2013-11-20 11:17:42 -05:00
Ludovic Marcotte e4aedbac08 <img src=data...> conversion to file attachments + CIDs. 2013-11-20 08:56:29 -05:00
Jean Raby 2cf66e037d Merge to 2.1.1 2013-11-19 14:00:22 -05:00
Jean Raby 6587f4f193 Update ChangeLog 2013-11-19 13:59:20 -05:00
Francis Lachapelle c8a4ea5548 Update translations 2013-11-19 13:57:18 -05:00
Jean Raby 148fd4936c Update Version to 2.1.1 and update news 2013-11-19 13:43:45 -05:00
Jean Raby a7fef39448 Update to 2.1.1 2013-11-19 13:43:22 -05:00
Francis Lachapelle 5a3d0d27e0 Fix bug following mail tags management CSS changes 2013-11-19 13:39:48 -05:00
Ludovic Marcotte eb9111b5fa Updated news for the recent bug fix 2013-11-19 11:40:33 -05:00
Ludovic Marcotte eb7d1f08bc Fix for bug #2482 2013-11-19 11:39:45 -05:00
Ludovic Marcotte 854fed529c Added SOGoMailAuxiliaryUserAccountsEnabled 2013-11-19 09:52:53 -05:00
Jean Raby 3c29e0724d update news file 2013-11-15 16:12:15 -05:00
Jean Raby cebaed9059 Merge branch 'master' of https://github.com/inverse-inc/sogo 2013-11-15 16:09:52 -05:00
Jean Raby aae26602b0 Use raw (utf7) name when checking folder type 2013-11-15 16:04:09 -05:00
Jean Raby 05233d9c53 Use modified utf7 for special folder names 2013-11-15 16:02:59 -05:00
Francis Lachapelle e862194b32 Convert color picker to an inline widget
The colors are now limited to the colors offered in Thunderbird.
2013-11-15 15:50:46 -05:00
Jean Raby 884fbfdb73 Bump copyright and fix whitespace (tab kill) 2013-11-15 13:17:37 -05:00
Ludovic Marcotte c05cf00db7 Update standard tag colors to match TB and improve tags id generation. 2013-11-14 09:00:19 -05:00
Ludovic Marcotte 198db855f6 Specify color in which TB can grok it. 2013-11-13 15:55:25 -05:00
Ludovic Marcotte 1c439c866e Added DAV support for mails labels. 2013-11-13 15:44:57 -05:00
Francis Lachapelle 616ee7c6e4 GUI changes for mail labels management 2013-11-13 14:46:08 -05:00
Ludovic Marcotte 37d3234b60 Added support for dynamic mail labels/tags management.
The CSS in the UIxPreferences remains to be done.
2013-11-11 10:49:58 -05:00
Francis Lachapelle 449d838dc2 Merge to 2.1.0 2013-11-07 14:43:19 -05:00
Francis Lachapelle 6a9bcfda68 Update ChangeLog 2013-11-07 14:42:48 -05:00
Francis Lachapelle d0b09ebe35 Update translations 2013-11-07 14:14:39 -05:00
Francis Lachapelle 0361b7dfdb Documentation - bump version to 2.1.0 2013-11-07 11:09:41 -05:00
Francis Lachapelle 38b350382a Update NEWS file 2013-11-07 10:13:30 -05:00
Francis Lachapelle 73141a645e Update translations 2013-11-06 21:36:09 -05:00
Francis Lachapelle f07526423f Fix display of ICal event in message 2013-11-06 15:25:36 -05:00
Francis Lachapelle ba35a4b003 Update CKEditor to version 4.2.2 2013-11-06 11:29:15 -05:00
Ludovic Marcotte 47c4ad5807 Make sure the var is initilized to nil. 2013-10-29 20:58:26 -04:00
Ludovic Marcotte 0f3e31ebf1 Added more tags to skip 2013-10-23 16:37:03 -04:00
Ludovic Marcotte 87261f3280 Fix for bug #2468. 2013-10-23 16:04:37 -04:00
Ludovic Marcotte bd2759ecdf Fix for bug #2433 2013-10-22 11:44:26 -04:00
Ludovic Marcotte be1bcf3c9b Fix for bug #2461 2013-10-22 11:25:24 -04:00
Ludovic Marcotte 053b090aff Fix for bug #2235 2013-10-21 15:37:01 -04:00
Ludovic Marcotte 189f2218a8 Fix for bug #2459 2013-10-21 15:26:43 -04:00
Ludovic Marcotte 656869a4a2 Fix for bug #1328 2013-10-18 13:16:30 -04:00
Ludovic Marcotte 16f62e2393 Fix for bug #2434 2013-10-18 10:30:43 -04:00
Jean Raby 9289615996 Added https vhost example for apple carddav 2013-10-17 11:45:07 -04:00
Jean Raby fdea04c08c Added some verbose logging for expire-autoreply 2013-10-15 10:49:21 -04:00
Jean Raby edca3638ec Fixup backup_dir to use sogo's home directory 2013-10-11 13:41:44 -04:00
Ludovic Marcotte 05990e9a14 Fix for bug 2007 2013-09-30 10:50:27 -04:00
Jean Raby 3cce9b2012 Fix file permissions 2013-09-30 09:39:29 -04:00
Ludovic Marcotte 7dc65af300 Fix for bug #2386 2013-09-27 15:54:11 -04:00
Ludovic Marcotte 84e999229b Fix for bug #2270 2013-09-27 15:36:46 -04:00
Francis Lachapelle 3dbfb0ed2d Add Underline option to HTML editor 2013-09-27 14:43:05 -04:00
Francis Lachapelle d1f3417c3a Update CKEditor to version 4.2.1
And added the table-related modules.
2013-09-27 14:25:22 -04:00
Ludovic Marcotte 7c7031333e Fix for bug #2221 2013-09-27 10:00:39 -04:00
Jean Raby 1e48481426 Updated description/default value for WOPort 2013-09-26 08:51:42 -04:00
Jean Raby 8ae1624604 Added --noexpiry for administrator 2013-09-26 08:49:17 -04:00
Ludovic Marcotte 7166f5a597 Fix for bug #2399 2013-09-25 16:02:13 -04:00
Ludovic Marcotte 55052ea36f Fix for bug #2240 2013-09-25 14:40:48 -04:00
Ludovic Marcotte 99d38417cc Fix for bug #2354 2013-09-25 13:51:42 -04:00
Ludovic Marcotte 29eed182a7 Updated the OpenChange code related to UTF-7 changes for IMAP folders 2013-09-25 10:41:07 -04:00
Ludovic Marcotte 744610dbe1 Fixed tests regarding new WebDAV sync responses 2013-09-25 08:46:34 -04:00
Ludovic Marcotte d2b739d261 Fix for bug #2318 2013-09-24 16:01:23 -04:00
Ludovic Marcotte 2ba8254ecc Fix for bug #1275 2013-09-24 09:29:46 -04:00
Jean Raby 28e600a4e6 Set default listening address to 127.0.0.1:20000
No reason to listen on 0.0.0.0 by default
2013-09-20 15:37:34 -04:00
Ludovic Marcotte ab6e4841ba Merge branch 'master' of https://github.com/inverse-inc/sogo
Conflicts:
	NEWS
2013-09-19 16:14:41 -04:00
Ludovic Marcotte 91f1ab6a60 Fix for bug #2217 2013-09-19 16:14:08 -04:00
Jean Raby 32a534919d update NEWS. ldap fixes 2013-09-19 11:11:29 -04:00
Ludovic Marcotte 5b77c2b724 Stability fix when we're untable to determine the message class type 2013-09-19 10:49:42 -04:00
Ludovic Marcotte 70086e5ee6 Fix for bug #1935 2013-09-19 09:56:28 -04:00
Ludovic Marcotte 7ddc1b9e2d Avoid type-issues generating wrong GlobCnt - leading to OpenChange crashes during the sync process. 2013-09-18 14:03:07 -04:00
Francis Lachapelle 6d93db96e4 Update NEWS file 2013-09-17 11:17:40 -04:00
Jean Raby 27445d3b85 update news 2013-09-17 09:27:46 -04:00
Jean Raby 60d6abe542 Use HTTP/1.0 to avoid chunked replies
Fixes^WWorkaround #2408
2013-09-17 09:07:53 -04:00
Ludovic Marcotte baacf8516d Updated NEWS file regarding previous commit 2013-09-16 11:21:23 -04:00
Ludovic Marcotte 46a48faf23 Merge branch 'master' of https://github.com/inverse-inc/sogo 2013-09-16 11:00:40 -04:00
Ludovic Marcotte 193720cfbb Fix for s/mime verification issues with some openssl versions 2013-09-16 10:59:45 -04:00
Jean Raby f40580d632 Merge branch 'master' of https://github.com/inverse-inc/sogo 2013-09-13 11:25:08 -04:00
Jean Raby ca4d89fb08 update with latest fixes 2013-09-13 11:24:16 -04:00
Jean Raby 906985c1f3 Call MSExchangeHostname on SOGoDNSource only
Fixes #2418
2013-09-13 11:19:44 -04:00
Jean Raby de8bf64c70 Local pool when appending contacts to response
Avoids using too much memory when doing a contact lookup with many matches
2013-09-13 11:16:28 -04:00
Jean Raby 0c38a9e555 whitespace tabkill 2013-09-13 11:13:02 -04:00
Francis Lachapelle 3c6c90d434 Reload webmail when changing "remote images" pref 2013-09-13 09:33:28 -04:00
Francis Lachapelle 72a4b075d6 Mail popup: respect "remote inline images" prefs
Fixes #2417
2013-09-12 17:08:02 -04:00
Francis Lachapelle 24c0fb1cc4 Fix change listener on calendar list select input
Fixes #2353
2013-09-12 16:33:44 -04:00
Jean Raby 7241e3e30e Added rewrite rule for apple autoconfiguration url
Rewrite rules are no inherited by virtualhosts when they are declared in conf.d
This means that you'll have to explicitly include SOGo.conf from 000-default
on debian/ubuntu for this redirection to work properly.
2013-09-12 10:14:47 -04:00
Jean Raby 1d705dc00b Next version: 2.1.0 2013-09-10 13:58:04 -04:00
Jean Raby df42ab2a46 Run 3 sogod process by default instead on only 1 2013-09-09 10:07:07 -04:00
Ludovic Marcotte 53f9d0d7f5 Merge branch 'master' of https://github.com/inverse-inc/sogo 2013-09-06 13:49:25 -04:00
Jean Raby f59c77a950 Update news 2013-09-06 13:49:04 -04:00
Ludovic Marcotte cd4abe4b5b Fix for bug 2398 2013-09-06 13:48:44 -04:00
Francis Lachapelle 69b0f9fcbf Mail notifications: Escape HTML in wox templates
We don't escape the values in the classes but in the templates.
2013-09-03 12:05:13 -04:00
Jean Raby dceead3997 Fixup sogo spool cleanup cronjob
Add -user sogo to be on the safe side.
Change call to /bin/rmdir by -delete to avoid error messages.
Find would call rmdir and then do an openat() on the deleted directory,
which would obviously fail.

Fixes #2372
2013-09-03 09:59:01 -04:00
Jean Raby 573c2ec114 updated News 2013-08-29 15:51:05 -04:00
Jean Raby 6a68c255bd Merge branch 'fix/ldap-password-change' 2013-08-29 15:15:07 -04:00
Jean Raby e9d8b729b6 Bump version file to 2.0.8 for nightly builds 2013-08-29 14:34:25 -04:00
Jean Raby 1e7dfc0934 Updated cron sections for credentials files
Added a note regarding password change against AD/Samba4
2013-08-29 14:32:34 -04:00
Jean Raby d7e6648396 Reworked password change logic and add AD support 2013-08-28 17:11:07 -04:00
Jean Raby 65603201f7 ignore pyc files and config.py 2013-08-28 10:05:36 -04:00
Jean Raby 9fd6f75c4e Update crontab for SMTP AUTH credentials 2013-08-28 09:47:10 -04:00
Jean Raby b96f25f99f updated NEWS 2013-08-27 14:44:28 -04:00
Jean Raby d7851999da Merge branch 'fix/email-notif-auth' 2013-08-27 14:37:52 -04:00
Jean Raby e6ab0a590a Support using SMTP AUTH creds for email alarms
Credentials must be supplied using '-p /path/to/credsFile'.
The credentials file should contain a single line with the format 'user:pass'

While there, add a usage message
2013-08-27 13:12:03 -04:00
Jean Raby be531100c6 Use SOGoCredentialsFile to avoid duplicated code 2013-08-27 13:04:08 -04:00
Jean Raby e946a67ddf Special case for auth with SOGoStaticAuthenticator 2013-08-27 13:02:06 -04:00
Jean Raby 2fe87f14fd Add SOGoStaticAuthenticator
New authenticator that is not linked to a SOGoUser.
Will be used for SMTP AUTH by sogo-elalarm-notify.
2013-08-27 12:59:03 -04:00
Jean Raby b2f012cae2 Add SOGoCredentialsFile
New class to read credentials files as used by sogo-tool and sogo-ealarm-notify
2013-08-27 12:56:07 -04:00
Francis Lachapelle 33659aa947 Increase height of alarm editor
Only when email alarms are enabled.
2013-08-27 12:01:41 -04:00
Francis Lachapelle df1ab29872 Fix position of red "now" line
Fixes #2373
2013-08-27 09:06:48 -04:00
Jean Raby 61e59b864e Bump copyright 2013-08-27 08:33:50 -04:00
Francis Lachapelle 0a590ba388 Fix Finnish mail reply/forward templates 2013-08-26 08:59:43 -04:00
Ludovic Marcotte ab92516dd0 Fix for bug #1431 2013-08-09 11:39:15 -04:00
Ludovic Marcotte 7b90b892fc Fix for bug #2385 2013-08-07 08:49:59 -04:00
Jean Raby b654ffb806 add webdavsync-tool.py
first draft of a small tool to simulate a TB calendar sync
2013-08-02 16:56:36 -04:00
Jean Raby 6de689bbe2 Add depth support to CalendarMultiget 2013-08-02 15:41:24 -04:00
Jean Raby 7eb8b9c2c3 Add SxVMemLimit to sogo.conf 2013-08-02 09:51:41 -04:00
Jean Raby 3877f3001f replace xml.dom.ext by xml.dom.minidom 2013-08-01 12:48:42 -04:00
Ludovic Marcotte 4d2c734781 Revert "Try to use a local pool to avoid huge memory consumption"
This reverts commit e57d875e0a.
2013-07-29 14:32:58 -04:00
Ludovic Marcotte e57d875e0a Try to use a local pool to avoid huge memory consumption 2013-07-29 09:43:21 -04:00
Ludovic Marcotte b1df03adc7 Fix for old runtimes. 2013-07-24 10:54:55 -04:00
Francis Lachapelle c4bc215a47 Merge to 2.0.7 2013-07-23 10:02:39 -04:00
Francis Lachapelle bd776152db Update ChangeLog 2013-07-23 10:02:13 -04:00
Ludovic Marcotte c6374b52ec Merge branch 'master' of https://github.com/inverse-inc/sogo 2013-07-23 09:26:55 -04:00
Ludovic Marcotte 734c164ae0 Reverted broken patch in #2360 and tried to fix it cleanly 2013-07-23 09:25:24 -04:00
Francis Lachapelle c9936d7ecf Merge to 2.0.7 2013-07-23 08:38:44 -04:00
Francis Lachapelle 9f381e768d Update ChangeLog 2013-07-23 08:38:09 -04:00
Ludovic Marcotte b531b6160c Fixed compilation ordering to avoid bug in gnustep-make 2013-07-23 08:31:38 -04:00
Francis Lachapelle 885e59a2af Merge to 2.0.7 2013-07-19 13:46:37 -04:00
Francis Lachapelle 8a041860a0 Update ChangeLog 2013-07-19 13:40:33 -04:00
Francis Lachapelle d5f76ac832 Improve CSS print media 2013-07-19 13:39:18 -04:00
Francis Lachapelle 12b7fea825 Documentation - bump version to 2.0.7 2013-07-19 13:37:13 -04:00
Francis Lachapelle 1c82af8842 Updated pt_BR, cs, nl, de, pl and ru translations 2013-07-19 11:29:10 -04:00
Francis Lachapelle 6cef5245e1 Bump version to 2.0.7 2013-07-19 11:27:17 -04:00
Francis Lachapelle 0069a4200b Handle possible jQuery error with DnD of contacts 2013-07-19 10:51:41 -04:00
Ludovic Marcotte e24c20c48a Reverted patch 2013-07-19 10:11:08 -04:00
Ludovic Marcotte 256b679798 Bug fix for #2366 2013-07-18 11:46:49 -04:00
Francis Lachapelle b85ed0db1c Fix blur of active element on click on a draggable
This bug has yet to be officially part of jQuery UI, therefore this
commit updates jquery-ui to version 1.10.3 patched with commit fcd1caf:

https://github.com/jquery/jquery-ui/commit/fcd1cafac8afe3a947676ec018e844eeada5b9de
2013-07-18 11:32:29 -04:00
Ludovic Marcotte 048bae2fc5 Applied patch from bug #2235 2013-07-18 10:52:37 -04:00
Ludovic Marcotte 19e542396b Applied patch from bug #2360 2013-07-18 10:25:39 -04:00
Francis Lachapelle 249a1fcf14 Bubble box of event should not overlap event cell 2013-07-17 14:57:07 -04:00
Ludovic Marcotte 7dad5ad84e Updated for v2.0.7 2013-07-16 15:20:26 -04:00
Ludovic Marcotte 16105d37b8 Properly handle RFC2231 everywhere 2013-07-16 15:18:04 -04:00
Ludovic Marcotte e08ebd2390 Fix for bugs #2368 and #2369 2013-07-16 11:31:08 -04:00
Francis Lachapelle 03553980fd Update NEWS file and add missing image 2013-07-11 13:55:03 -04:00
Francis Lachapelle 33fd60efb3 Calendar: print gridlines to 15-minute intervals 2013-07-11 13:50:44 -04:00
Francis Lachapelle b8e2255a07 Set the events/tasks list collapsable 2013-07-11 13:46:38 -04:00
Ludovic Marcotte e687dbf155 If the organizer's name is non-existent, use the email address 2013-07-04 13:11:02 -04:00
Jean Raby bf398889bf Merge to 2.0.6b 2013-06-27 11:36:30 -04:00
Jean Raby f42d52743d bump version to 2.0.6b 2013-06-27 11:35:17 -04:00
Jean Raby 70cd64a626 Update ChangeLog 2013-06-27 11:34:06 -04:00
Jean Raby 4359b05da8 updated NEWS 2013-06-27 11:33:44 -04:00
Ludovic Marcotte e26e3d7307 Revert "Properly escape the foldername to avoid XSS issues"
This reverts commit 045b275b27.
2013-06-27 11:15:41 -04:00
Ludovic Marcotte 25dbd4849d Properly escape the foldername to avoid XSS issues 2013-06-27 11:14:50 -04:00
Ludovic Marcotte 045b275b27 Properly escape the foldername to avoid XSS issues 2013-06-27 11:06:07 -04:00
Jean Raby a2a89e8720 Fix loading of MSExchangeFreeBusySOAPResponseMap 2013-06-26 16:55:39 -04:00
Jean Raby 7ec1973e0f Merge to 2.0.6a 2013-06-25 09:22:35 -04:00
Jean Raby 2581f6c568 Update for 2.0.6a 2013-06-25 09:19:37 -04:00
Jean Raby 20369631c9 Update ChangeLog 2013-06-25 09:17:03 -04:00
Jean Raby 1221da2443 Add CASLogoutRequestMap.plist 2013-06-25 09:12:27 -04:00
Jean Raby f27b8b6a54 Document SOGoCASLogoutEnabled 2013-06-25 09:06:28 -04:00
Ludovic Marcotte a79a9c4eff Merge to 2.0.6
Conflicts:
	Documentation/SOGo Installation Guide.odt
2013-06-21 12:44:35 -04:00
Ludovic Marcotte a6b393c2c1 Update ChangeLog 2013-06-21 11:26:42 -04:00
Ludovic Marcotte faf228022a Updated for the release 2013-06-21 11:25:55 -04:00
Ludovic Marcotte 3e87ba92db Updated french translation 2013-06-21 10:45:03 -04:00
Jean Raby 0a87ff97b6 cosmetic fix, no functional change
added a POST payload to test this code
2013-06-21 09:36:54 -04:00
Ludovic Marcotte 031cd210f7 Better description 2013-06-20 20:29:16 -04:00
Ludovic Marcotte 9d9a434fdc Avoid crashing when reading fcs crap. 2013-06-20 15:44:35 -04:00
Jean Raby 41ed498d65 Add support for CAS LogoutRequests
Fixes #2346
This changes the serviceURL sent by SOGo to the CAS server:
  /SOGo/so/ -> /SOGo/so/index
2013-06-20 14:32:14 -04:00
Ludovic Marcotte d28482557f Fix for bug 2285 2013-06-20 13:43:45 -04:00
Ludovic Marcotte 4c97d54939 Fix for bug #2119 2013-06-20 09:10:09 -04:00
Ludovic Marcotte c08263d1c3 Updated patch 2013-06-19 17:36:43 -04:00
Ludovic Marcotte dc96466462 Updated for the release 2013-06-19 16:06:12 -04:00
Ludovic Marcotte 1734b387a3 Fix for bug #2237 2013-06-19 15:45:40 -04:00
Ludovic Marcotte 871115e349 Fixed bug #2294 2013-06-19 15:07:19 -04:00
Ludovic Marcotte a764286879 Fix for bug #2313 2013-06-19 14:09:20 -04:00
Ludovic Marcotte 5304461e4c now possible to see who created a event/task in a delegated calendar 2013-06-19 10:23:47 -04:00
Jean Raby 6b25f08943 Use domainDefaults to get imapCASServiceName 2013-06-18 19:33:36 -04:00
Jean Raby a0022e06f7 New preference: SOGoIMAPCASServiceName
Reworked CAS section a bit and add some information regarding casifying sieve.
2013-06-18 17:57:17 -04:00
Jean Raby f24e65b6d8 Merge branch 'fix/cas-service-names' 2013-06-18 16:44:05 -04:00
Jean Raby 0fb006c19f New domain preference: SOGoIMAPCASServiceName
Set this to the service name expected by the CAS server if it differs
from SOGoIMAPServer. This is useful to request a CAS ticket for service
imap://imap.domain.com while connecting through imapproxy on imap://127.0.0.1:1143

SOGoDAVAuthenticator is not updated since it doesn't really use the imap code.
2013-06-18 16:36:11 -04:00
Ludovic Marcotte 47a3f1a19d toggle to send or not notifications 2013-06-18 14:14:42 -04:00
Ludovic Marcotte f25344182d Rewrote escapedForCards so it's 10 times faster. 2013-06-14 14:58:16 -04:00
Jean Raby f24e3a0a31 whitespace fixes. tabkill 2013-06-12 02:36:50 -04:00
Ludovic Marcotte afb7bc309c Added message submissions rate-limiting support 2013-06-11 11:21:58 -04:00
Ludovic Marcotte cfee5aa3f4 Added new failed login rate-limiting options 2013-06-11 09:41:17 -04:00
Francis Lachapelle 2a51f6f385 Update CKEditor to version 4.1.2
Also added the blockquote plugin.
2013-06-10 21:07:52 -04:00
Jean Raby 4cffea43eb French translation of Sync Issues 2013-06-07 15:16:12 -04:00
Jean Raby cafce5753d update description of MultipleBookingsFieldName 2013-06-06 16:04:47 -04:00
Francis Lachapelle 5d6a5f5d5e Update CKEditor to version 4.1.1 2013-06-06 13:21:26 -04:00
Francis Lachapelle 8e5a26dfb1 Remove unicode separators from JSON
Fixes #2309
2013-06-05 15:55:52 -04:00
Ludovic Marcotte 4cb0facd72 Fixed bug #2206 2013-06-04 08:51:38 -04:00
Francis Lachapelle 854bce28fb Fix condition in UIxMailPartHTMLViewer 2013-06-03 12:07:18 -04:00
Francis Lachapelle 49e964c529 Fix decoding charset parameter
To avoid a libxml bug/limitation, we were already stripping the charset
parameter, but we were not considering the single quote as valid
delimiter.
2013-06-03 11:47:48 -04:00
Jean Raby 3281cea2a2 Add bindFields to the sample configuration file 2013-05-31 15:54:22 -04:00
Jean Raby 82253e91d2 don't use -M when creating the sogo user on debian
-M was not available in lenny. It is not actually needed since useradd
won't create the homedir when adding a system user (-r)
2013-05-24 15:00:05 -04:00
Jean Raby 1d1ed9a031 Update ldap filter description, example and syntax 2013-05-15 14:51:15 -04:00
Francis Lachapelle 2bd8a2935f Change default value of SOGoMailSpoolPath
Set the spool path to /var/spool/sogo and modified the installation
guide to point to the tmpwatch cronjob when changing SOGoMailSpoolPath.
2013-05-09 08:12:27 -04:00
Francis Lachapelle 8a25e38827 Add indent group to ckeditor toolbar 2013-05-02 09:07:17 -04:00
Ludovic Marcotte 4ec19d46fa Removed left-over code that would cause the logic from bug #2035 to not work. 2013-04-25 14:46:00 -04:00
Jean Raby d46a39e252 TOC links 2013-04-22 13:22:16 -04:00
Jean Raby 23e10d30be Added ldap attribute mapping table 2013-04-22 12:31:18 -04:00
Jean Raby f049e2430a Added ldap attribute mapping table 2013-04-22 12:25:22 -04:00
Jean Raby a53c66e8a4 Install openchange_user_cleanup in usr/sbin/
Instead of usr/share/doc/sogo/
2013-04-18 14:35:56 -04:00
Jean Raby 4fb3492ea8 openchange_cleanup.py -> openchange_user_cleanup 2013-04-18 14:28:55 -04:00
Jean Raby 353f40ac3e try to cleanup under INBOX too (altnamespace = no) 2013-04-18 14:15:35 -04:00
Jean Raby 96c831f726 Use separator sent by the imap server, not '/' 2013-04-18 14:11:36 -04:00
Jean Raby 59b3219f2d Merge to 2.05a 2013-04-16 15:20:19 -04:00
Jean Raby d7fdfc6cb2 Update NEWS + bump version 2013-04-16 15:16:54 -04:00
Jean Raby d02f58b3cd Update ChangeLog 2013-04-16 15:12:29 -04:00
Ludovic Marcotte 62fee93d86 Fix for bug #2287 2013-04-16 14:33:57 -04:00
Jean Raby 139c14d9e1 save: memCtx
Same fix as for MAPIStoreContactMessage
2013-04-16 12:06:17 -04:00
Francis Lachapelle 8ee15c6f77 Update Installation Guide
Improved the description of the parameters IMAPHostFieldName and
SieveHostFieldName.
2013-04-16 08:34:10 -04:00
Jean Raby 5d17414018 [MAPIStoreContactsMessage save] needs memCtx
From extrafu
2013-04-15 14:13:07 -04:00
Francis Lachapelle 3cd91846a6 Fix CSS color refresh of calendars 2013-04-11 16:32:17 -04:00
576 changed files with 25035 additions and 6528 deletions

No files matched your search

+2
View File
@@ -9,3 +9,5 @@ tags
*.swp
SoObjects/SOGo/SOGo.framework/
SoObjects/SOGo/derived_src/
Tests/*/config.py
*.pyc
+1 -1
View File
@@ -1,5 +1,5 @@
[main]
host = https://www.transifex.net
host = https://www.transifex.com
[sogo.ui-mailerui]
source_file = UI/MailerUI/English.lproj/Localizable.strings
+40
View File
@@ -0,0 +1,40 @@
/*
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 <Foundation/NSObject.h>
@interface ActiveSyncProduct : NSObject
{
}
@end
@implementation ActiveSyncProduct
@end /* ActiveSyncProduct */
+39
View File
@@ -0,0 +1,39 @@
# GNUstep makefile
include common.make
BUNDLE_NAME = ActiveSync
ActiveSync_PRINCIPAL_CLASS = ActiveSyncProduct
ActiveSync_OBJC_FILES = \
ActiveSyncProduct.m \
iCalEvent+ActiveSync.m \
iCalRecurrenceRule+ActiveSync.m \
iCalTimeZone+ActiveSync.m \
iCalToDo+ActiveSync.m \
NSCalendarDate+ActiveSync.m \
NSData+ActiveSync.m \
NSDate+ActiveSync.m \
NGDOMElement+ActiveSync.m \
NGMimeMessage+ActiveSync.m \
NGVCard+ActiveSync.m \
NSString+ActiveSync.m \
SOGoActiveSyncDispatcher.m \
SOGoActiveSyncDispatcher+Sync.m \
SOGoMailObject+ActiveSync.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/usr/include/libwbxml-1.0/
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed -lwbxml2
-include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/bundle.make
-include GNUmakefile.postamble
+1
View File
@@ -0,0 +1 @@
# compilation settings
+25
View File
@@ -0,0 +1,25 @@
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.
+44
View File
@@ -0,0 +1,44 @@
/*
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 __NGDOMELEMENTACTIVESYNC_H__
#define __NGDOMELEMENTACTIVESYNC_H__
#import <DOM/DOMElement.h>
#import <DOM/DOMProtocols.h>
@class NSDictionary;
@interface NGDOMElement (ActiveSync)
- (NSDictionary *) applicationData;
@end
#endif // NGDOMELEMENTACTIVESYNC
+158
View File
@@ -0,0 +1,158 @@
/*
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 "NGDOMElement+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
static NSArray *asElementArray = nil;
@implementation NGDOMElement (ActiveSync)
//
// We must handle "inner data" like this:
//
// <ApplicationData>
// <Flag xmlns="Email:">
// <FlagStatus>2</FlagStatus>
// <FlagType>Flag for follow up</FlagType>
// </Flag>
// </ApplicationData>
//
// and stuff like that:
//
// <Attendees xmlns="Calendar:">
// <Attendee>
// <Attendee_Email>sogo1@example.com</Attendee_Email>
// <Attendee_Name>John Doe</Attendee_Name>
// <Attendee_Status>5</Attendee_Status>
// <Attendee_Type>1</Attendee_Type>
// </Attendee>
// <Attendee>
// <Attendee_Email>sogo2@example.com</Attendee_Email>
// <Attendee_Name>Balthazar César</Attendee_Name>
// <Attendee_Status>5</Attendee_Status>
// <Attendee_Type>1</Attendee_Type>
// </Attendee>
// <Attendee>
// <Attendee_Email>sogo3@example.com</Attendee_Email>
// <Attendee_Name>Wolfgang Fritz</Attendee_Name>
// <Attendee_Status>5</Attendee_Status>
// <Attendee_Type>1</Attendee_Type>
// </Attendee>
// </Attendees>
//
- (NSDictionary *) applicationData
{
NSMutableDictionary *data;
id <DOMNodeList> children;
id <DOMElement> element;
int i, count;
if (!asElementArray)
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", nil];
data = [NSMutableDictionary dictionary];
children = [self childNodes];
for (i = 0; i < [children length]; i++)
{
element = [children objectAtIndex: i];
if ([element nodeType] == DOM_ELEMENT_NODE)
{
NSString *tag;
id value;
tag = [element tagName];
count = [(NSArray *)[element childNodes] count];
// Handle inner data - see above for samples
if (count > 2)
{
NSMutableArray *innerElements;
id <DOMElement> innerElement;
NSArray *childNodes;
NSString *innerTag;
BOOL same;
int j;
childNodes = (NSArray *)[element childNodes];
innerElements = [NSMutableArray array];
innerTag = nil;
same = YES;
for (j = 1; j < count; j++)
{
innerElement = [childNodes objectAtIndex: j];
if ([innerElement nodeType] == DOM_ELEMENT_NODE)
{
if (!innerTag)
innerTag = [innerElement tagName];
if ([innerTag isEqualToString: [innerElement tagName]])
{
[innerElements addObject: [(NGDOMElement *)innerElement applicationData]];
}
else
{
same = NO;
break;
}
}
}
if (same && [asElementArray containsObject: innerTag])
value = innerElements;
else
{
value = [(NGDOMElement *)element applicationData];
// Don't set empty values like Foo = {}
if (![value count])
value = nil;
}
}
else
value = [[element firstChild] textValue];
if (value && tag)
[data setObject: value forKey: tag];
}
}
return data;
}
@end
+43
View File
@@ -0,0 +1,43 @@
/*
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 __NGMIMEMESSAGEACTIVESYNC_H__
#define __NGMIMEMESSAGEACTIVESYNC_H__
#import <NGMail/NGMimeMessage.h>
@class NSArray;
@interface NGMimeMessage (ActiveSync)
- (NSArray *) allRecipients;
@end
#endif
+62
View File
@@ -0,0 +1,62 @@
/*
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 "NGMimeMessage+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSString.h>
#import <SOGo/NSString+Utilities.h>
@implementation NGMimeMessage (ActiveSync)
- (NSArray *) allRecipients
{
NSMutableArray *recipients;
NSEnumerator *enumerator;
NSString *s;
recipients = [NSMutableArray array];
enumerator = [[self headersForKey: @"to"] objectEnumerator];
while ((s = [enumerator nextObject]))
{
[recipients addObject: [s pureEMailAddress]];
}
enumerator = [[self headersForKey: @"cc"] objectEnumerator];
while ((s = [enumerator nextObject]))
{
[recipients addObject: [s pureEMailAddress]];
}
return recipients;
}
@end
+47
View File
@@ -0,0 +1,47 @@
/*
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 __NGVCARDACTIVESYNC_H__
#define __NGVCARDACTIVESYNC_H__
#import <NGCards/NGVCard.h>
@class NSDictionary;
@class NSString;
@class WOContext;
@interface NGVCard (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
@end
#endif
+308
View File
@@ -0,0 +1,308 @@
/*
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 "NGVCard+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <NGExtensions/NSString+misc.h>
#import <NGCards/CardElement.h>
#import <Contacts/NGVCard+SOGo.h>
#include "NSDate+ActiveSync.h"
#include "NSString+ActiveSync.h"
@implementation NGVCard (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
CardElement *n, *homeAdr, *workAdr;
NSArray *emails, *addresses;
NSMutableString *s;
id o;
int i;
s = [NSMutableString string];
n = [self n];
if ((o = [n flattenedValueAtIndex: 0 forKey: @""]))
[s appendFormat: @"<LastName xmlns=\"Contacts:\">%@</LastName>", [o activeSyncRepresentationInContext: context]];
if ((o = [n flattenedValueAtIndex: 1 forKey: @""]))
[s appendFormat: @"<FirstName xmlns=\"Contacts:\">%@</FirstName>", [o activeSyncRepresentationInContext: context]];
if ((o = [self workCompany]))
[s appendFormat: @"<CompanyName xmlns=\"Contacts:\">%@</CompanyName>", [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];
// Secondary email addresses (2 and 3)
emails = [self secondaryEmails];
for (i = 0; i < [emails count]; i++)
{
o = [[emails objectAtIndex: i] flattenedValuesForKey: @""];
[s appendFormat: @"<Email%dAddress xmlns=\"Contacts:\">%@</Email%dAddress>", i+2, o, i+2];
if (i == 1)
break;
}
// Telephone numbers
if ((o = [self workPhone]) && [o length])
[s appendFormat: @"<BusinessPhoneNumber xmlns=\"Contacts:\">%@</BusinessPhoneNumber>", [o activeSyncRepresentationInContext: context]];
if ((o = [self homePhone]) && [o length])
[s appendFormat: @"<HomePhoneNumber xmlns=\"Contacts:\">%@</HomePhoneNumber>", [o activeSyncRepresentationInContext: context]];
if ((o = [self fax]) && [o length])
[s appendFormat: @"<BusinessFaxNumber xmlns=\"Contacts:\">%@</BusinessFaxNumber>", [o activeSyncRepresentationInContext: context]];
if ((o = [self mobile]) && [o length])
[s appendFormat: @"<MobilePhoneNumber xmlns=\"Contacts:\">%@</MobilePhoneNumber>", [o activeSyncRepresentationInContext: context]];
if ((o = [self pager]) && [o length])
[s appendFormat: @"<PagerNumber xmlns=\"Contacts:\">%@</PagerNumber>", [o activeSyncRepresentationInContext: context]];
// Home Address
addresses = [self childrenWithTag: @"adr"
andAttribute: @"type"
havingValue: @"home"];
if ([addresses count])
{
homeAdr = [addresses objectAtIndex: 0];
if ((o = [homeAdr flattenedValueAtIndex: 2 forKey: @""]))
[s appendFormat: @"<HomeStreet xmlns=\"Contacts:\">%@</HomeStreet>", [o activeSyncRepresentationInContext: context]];
if ((o = [homeAdr flattenedValueAtIndex: 3 forKey: @""]))
[s appendFormat: @"<HomeCity xmlns=\"Contacts:\">%@</HomeCity>", [o activeSyncRepresentationInContext: context]];
if ((o = [homeAdr flattenedValueAtIndex: 4 forKey: @""]))
[s appendFormat: @"<HomeState xmlns=\"Contacts:\">%@</HomeState>", [o activeSyncRepresentationInContext: context]];
if ((o = [homeAdr flattenedValueAtIndex: 5 forKey: @""]))
[s appendFormat: @"<HomePostalCode xmlns=\"Contacts:\">%@</HomePostalCode>", [o activeSyncRepresentationInContext: context]];
if ((o = [homeAdr flattenedValueAtIndex: 6 forKey: @""]))
[s appendFormat: @"<HomeCountry xmlns=\"Contacts:\">%@</HomeCountry>", [o activeSyncRepresentationInContext: context]];
}
// Work Address
addresses = [self childrenWithTag: @"adr"
andAttribute: @"type"
havingValue: @"work"];
if ([addresses count])
{
workAdr = [addresses objectAtIndex: 0];
if ((o = [workAdr flattenedValueAtIndex: 2 forKey: @""]))
[s appendFormat: @"<BusinessStreet xmlns=\"Contacts:\">%@</BusinessStreet>", [o activeSyncRepresentationInContext: context]];
if ((o = [workAdr flattenedValueAtIndex: 3 forKey: @""]))
[s appendFormat: @"<BusinessCity xmlns=\"Contacts:\">%@</BusinessCity>", [o activeSyncRepresentationInContext: context]];
if ((o = [workAdr flattenedValueAtIndex: 4 forKey: @""]))
[s appendFormat: @"<BusinessState xmlns=\"Contacts:\">%@</BusinessState>", [o activeSyncRepresentationInContext: context]];
if ((o = [workAdr flattenedValueAtIndex: 5 forKey: @""]))
[s appendFormat: @"<BusinessPostalCode xmlns=\"Contacts:\">%@</BusinessPostalCode>", [o activeSyncRepresentationInContext: context]];
if ((o = [workAdr flattenedValueAtIndex: 6 forKey: @""]))
[s appendFormat: @"<BusinessCountry xmlns=\"Contacts:\">%@</BusinessCountry>", [o activeSyncRepresentationInContext: context]];
}
// Other, less important fields
if ((o = [self birthday]))
[s appendFormat: @"<Birthday xmlns=\"Contacts:\">%@</Birthday>", [o activeSyncRepresentationWithoutSeparatorsInContext: context]];
if ((o = [self note]))
{
o = [o activeSyncRepresentationInContext: context];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
return s;
}
//
//
//
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context
{
CardElement *element;
id o;
// Contact's note
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setNote: o];
// Birthday
if ((o = [theValues objectForKey: @"Birthday"]))
{
o = [o calendarDate];
[self setBday: [o descriptionWithCalendarFormat: @"%Y-%m-%d"]];
}
//
// Business address information
//
// BusinessStreet
// BusinessCity
// BusinessPostalCode
// BusinessState
// BusinessCountry
//
element = [self elementWithTag: @"adr" ofType: @"work"];
[element setSingleValue: @""
atIndex: 1 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"BusinessStreet"]
atIndex: 2 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"BusinessCity"]
atIndex: 3 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"BusinessState"]
atIndex: 4 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"BusinessPostalCode"]
atIndex: 5 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"BusinessCountry"]
atIndex: 6 forKey: @""];
//
// Home address information
//
// HomeStreet
// HomeCity
// HomePostalCode
// HomeState
// HomeCountry
//
element = [self elementWithTag: @"adr" ofType: @"home"];
[element setSingleValue: @""
atIndex: 1 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"HomeStreet"]
atIndex: 2 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"HomeCity"]
atIndex: 3 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"HomeState"]
atIndex: 4 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"HomePostalCode"]
atIndex: 5 forKey: @""];
[element setSingleValue: [theValues objectForKey: @"HomeCountry"]
atIndex: 6 forKey: @""];
// Company's name
if ((o = [theValues objectForKey: @"CompanyName"]))
{
[self setOrg: o units: nil];
}
// Email addresses
if ((o = [theValues objectForKey: @"Email1Address"]))
{
[self addEmail: o types: [NSArray arrayWithObject: @"pref"]];
}
if ((o = [theValues objectForKey: @"Email2Address"]))
{
[self addEmail: o types: nil];
}
if ((o = [theValues objectForKey: @"Email3Address"]))
{
[self addEmail: o types: nil];
}
// Formatted name
// MiddleName
// Suffix (II)
// Title (Mr.)
[self setFn: [theValues objectForKey: @"FileAs"]];
[self setNWithFamily: [theValues objectForKey: @"LastName"]
given: [theValues objectForKey: @"FirstName"]
additional: nil prefixes: nil suffixes: nil];
// IM information
[[self uniqueChildWithTag: @"x-aim"]
setSingleValue: [theValues objectForKey: @"IMAddress"]
forKey: @""];
//
// Phone numbrrs
//
element = [self elementWithTag: @"tel" ofType: @"work"];
[element setSingleValue: [theValues objectForKey: @"BusinessPhoneNumber"] forKey: @""];
element = [self elementWithTag: @"tel" ofType: @"home"];
[element setSingleValue: [theValues objectForKey: @"HomePhoneNumber"] forKey: @""];
element = [self elementWithTag: @"tel" ofType: @"cell"];
[element setSingleValue: [theValues objectForKey: @"MobilePhoneNumber"] forKey: @""];
element = [self elementWithTag: @"tel" ofType: @"fax"];
[element setSingleValue: [theValues objectForKey: @"BusinessFaxNumber"] forKey: @""];
element = [self elementWithTag: @"tel" ofType: @"pager"];
[element setSingleValue: [theValues objectForKey: @"PagerNumber"] forKey: @""];
// Job's title
if ((o = [theValues objectForKey: @"JobTitle"]))
{
[self setTitle: o];
}
// WebPage (work)
if ((o = [theValues objectForKey: @"WebPage"]))
{
[[self elementWithTag: @"url" ofType: @"work"]
setSingleValue: o forKey: @""];
}
}
@end
+43
View File
@@ -0,0 +1,43 @@
/*
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 __NSCALENDARDATEACTIVESYNC_H__
#define __NSCALENDARDATEACTIVESYNC_H__
#import <Foundation/NSCalendarDate.h>
@class NSString;
@interface NSCalendarDate (ActiveSync)
+ (NSCalendarDate *) dateFromFilterType: (NSString *) theFilterType;
@end
#endif
+87
View File
@@ -0,0 +1,87 @@
/*
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 "NSCalendarDate+ActiveSync.h"
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#define ONE_DAY 86400
@implementation NSCalendarDate (ActiveSync)
//
// See http://msdn.microsoft.com/en-us/library/gg709713(v=exchg.80).aspx for available types
//
+ (NSCalendarDate *) dateFromFilterType: (NSString *) theFilterType
{
NSCalendarDate *d;
d = [NSCalendarDate calendarDate];
if (d)
{
int value;
switch ([theFilterType intValue])
{
case 1:
value = ONE_DAY;
break;
case 2:
value = 3 * ONE_DAY;
break;
case 3:
value = 7 * ONE_DAY;
break;
case 4:
value = 14 * ONE_DAY;
break;
case 5:
value = 30 * ONE_DAY;
break;
case 6:
value = 90 * ONE_DAY;
break;
case 7:
value = 180 * ONE_DAY;
break;
case 0:
case 8:
default:
return nil;
}
return [d initWithTimeIntervalSinceNow: -value];
}
return d;
}
@end
+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 __NSDATAACTIVESYNC_H__
#define __NSDATAACTIVESYNC_H__
#import <Foundation/NSData.h>
@class NSString;
@class WOContext;
@interface NSData (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (NSData *) wbxml2xml;
- (NSData *) xml2wbxml;
@end
#endif
+152
View File
@@ -0,0 +1,152 @@
/*
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 "NSData+ActiveSync.h"
#import <Foundation/NSProcessInfo.h>
#import <Foundation/NSString.h>
#import <NGExtensions/NGBase64Coding.h>
#include <wbxml/wbxml.h>
#include <wbxml/wbxml_conv.h>
#include <wbxml/wbxml_errors.h>
#define WBXMLDEBUG 0
@implementation NSData (ActiveSync)
- (void) _dumpToFile
{
NSString *path;
path = [NSString stringWithFormat: @"/tmp/%@.data", [[NSProcessInfo processInfo] globallyUniqueString]];
[self writeToFile: path atomically: YES];
NSLog(@"Original data written to: %@", path);
}
//
// Encodes the data in base64 and strip newline characters
//
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
return [[self stringByEncodingBase64] stringByReplacingString: @"\n" withString: @""];
}
- (NSData *) wbxml2xml
{
WBXMLGenXMLParams params;
NSData *data;
unsigned int wbxml_len, xml_len, ret;
unsigned char *wbxml, *xml;
wbxml = (unsigned char*)[self bytes];
wbxml_len = [self length];
xml = NULL;
xml_len = 0;
params.lang = WBXML_LANG_ACTIVESYNC;
params.gen_type = WBXML_GEN_XML_INDENT;
params.indent = 1;
params.keep_ignorable_ws = FALSE;
ret = wbxml_conv_wbxml2xml_withlen(wbxml, wbxml_len, &xml, &xml_len, &params);
if (ret != WBXML_OK)
{
NSLog(@"wbxml2xmlFromContent: failed: %s\n", wbxml_errors_string(ret));
[self _dumpToFile];
return nil;
}
data = [[NSData alloc] initWithBytes: xml length: xml_len];
#if WBXMLDEBUG
[data writeToFile: @"/tmp/protocol.decoded" atomically: YES];
#endif
free(xml);
return AUTORELEASE(data);
}
- (NSData *) xml2wbxml
{
WBXMLConvXML2WBXML *conv;
NSData *data;
unsigned int wbxml_len, xml_len, ret;
unsigned char *wbxml, *xml;
xml = (unsigned char*)[self bytes];
xml_len = [self length];
wbxml = NULL;
wbxml_len = 0;
conv = NULL;
ret = wbxml_conv_xml2wbxml_create(&conv);
if (ret != WBXML_OK)
{
NSLog(@"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret));
[self _dumpToFile];
return nil;
}
wbxml_conv_xml2wbxml_enable_preserve_whitespaces(conv);
// From libwbxml's changelog in v0.11.0: "The public ID is set to unknown and the DTD is not included. This is required for Microsoft ActiveSync."
wbxml_conv_xml2wbxml_disable_public_id(conv);
wbxml_conv_xml2wbxml_disable_string_table(conv);
ret = wbxml_conv_xml2wbxml_run(conv, xml, xml_len, &wbxml, &wbxml_len);
if (ret != WBXML_OK)
{
NSLog(@"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret));
[self _dumpToFile];
free(wbxml);
wbxml_conv_xml2wbxml_destroy(conv);
return nil;
}
data = [[NSData alloc] initWithBytes: wbxml length: wbxml_len];
#if WBXMLDEBUG
[data writeToFile: @"/tmp/protocol.encoded" atomically: YES];
#endif
free(wbxml);
wbxml_conv_xml2wbxml_destroy(conv);
return AUTORELEASE(data);
}
@end
+45
View File
@@ -0,0 +1,45 @@
/*
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 __NSDATEACTIVESYNC_H__
#define __NSDATEACTIVESYNC_H__
#import <Foundation/NSDate.h>
@class NSString;
@class WOContext;
@interface NSDate (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (NSString *) activeSyncRepresentationWithoutSeparatorsInContext: (WOContext *) context;
@end
#endif
+52
View File
@@ -0,0 +1,52 @@
/*
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 "NSDate+ActiveSync.h"
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
@implementation NSDate (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
return [self descriptionWithCalendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ" timeZone: [NSTimeZone timeZoneWithName: @"GMT"] locale: nil];
}
//
// From [MS-ASDTYPE].pdf - section 2.3 "Dates and times in calendar items MUST NOT include punctuation separators."
//
- (NSString *) activeSyncRepresentationWithoutSeparatorsInContext: (WOContext *) context
{
return [self descriptionWithCalendarFormat: @"%Y%m%dT%H%M%SZ" timeZone: [NSTimeZone timeZoneWithName: @"GMT"] locale: nil];
}
@end
+54
View File
@@ -0,0 +1,54 @@
/*
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 __NSSTRINGACTIVESYNC_H__
#define __NSSTRINGACTIVESYNC_H__
#import <Foundation/NSString.h>
#include "SOGoActiveSyncConstants.h"
@class NSCalendarDate;
@class NSData;
@class WOContext;
@interface NSString (ActiveSync)
- (NSString *) sanitizedServerIdWithType: (SOGoMicrosoftActiveSyncFolderType) folderType;
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (int) activeSyncFolderType;
- (NSString *) realCollectionIdWithFolderType: (SOGoMicrosoftActiveSyncFolderType *) folderType;
- (NSCalendarDate *) calendarDate;
- (NSString *) deviceId;
- (NSString *) command;
- (NSData *) convertHexStringToBytes;
@end
#endif
+283
View File
@@ -0,0 +1,283 @@
/*
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 "NSString+ActiveSync.h"
#include <Foundation/NSArray.h>
#include <Foundation/NSCalendarDate.h>
#include <Foundation/NSData.h>
#include <Foundation/NSDate.h>
#include <SOGo/NSString+Utilities.h>
#include <NGExtensions/NSString+misc.h>
@implementation NSString (ActiveSync)
- (NSString *) sanitizedServerIdWithType: (SOGoMicrosoftActiveSyncFolderType) folderType
{
if (folderType == ActiveSyncEventFolder)
{
int len;
len = [self length];
if (len > 4 && [self hasSuffix: @".ics"])
return [self substringToIndex: len-4];
else
return [NSString stringWithFormat: @"%@.ics", self];
}
return self;
}
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSString *s;
s = [self stringByEscapingHTMLString];
return [[s componentsSeparatedByCharactersInSet: [self safeCharacterSet]]
componentsJoinedByString: @""];
}
- (int) activeSyncFolderType
{
if ([self isEqualToString: @"inbox"])
return 2;
else if ([self isEqualToString: @"draft"])
return 3;
else if ([self isEqualToString: @"sent"])
return 5;
else if ([self isEqualToString: @"trash"])
return 4;
return 12;
}
- (NSString *) realCollectionIdWithFolderType: (SOGoMicrosoftActiveSyncFolderType *) folderType;
{
NSString *realCollectionId, *v;
*folderType = ActiveSyncGenericFolder;
v = [self stringByUnescapingURL];
if ([v hasPrefix: @"vevent/"])
{
realCollectionId = [v substringFromIndex: 7];
*folderType = ActiveSyncEventFolder;
}
else if ([v hasPrefix: @"vtodo/"])
{
realCollectionId = [v substringFromIndex: 6];
*folderType = ActiveSyncTaskFolder;
}
else if ([v hasPrefix: @"vcard/"])
{
realCollectionId = [v substringFromIndex: 6];
*folderType = ActiveSyncContactFolder;
}
else if ([v hasPrefix: @"mail/"])
{
realCollectionId = [[v stringByUnescapingURL] substringFromIndex: 5];
*folderType = ActiveSyncMailFolder;
}
else
{
realCollectionId = nil;
}
return realCollectionId;
}
//
// 2014-01-16T05:00:00.000Z
//
// See http://www.gnustep.org/resources/documentation/Developer/Base/Reference/NSCalendarDate.html#method$NSCalendarDate-initWithString$calendarFormat$ for the format details.
//
- (NSCalendarDate *) calendarDate
{
id o;
o = [NSCalendarDate dateWithString: self calendarFormat: @"%Y%m%dT%H%M%SZ"];
if (!o)
o = [NSCalendarDate dateWithString: self calendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ"];
return o;
}
- (NSString *) _valueForParameter: (NSString *) theParameter
{
NSArray *components;
NSString *s;
int i;
components = [[[self componentsSeparatedByString: @"/"] lastObject] componentsSeparatedByString: @"&"];
for (i = 0; i < [components count]; i++)
{
s = [components objectAtIndex: i];
if ([[s uppercaseString] hasPrefix: theParameter])
return [s substringFromIndex: [theParameter length]];
}
return nil;
}
//
// This method extracts the "DeviceId" from a URI:
//
// /SOGo/Microsoft-Server-ActiveSync?Cmd=FolderSync&User=sogo10&DeviceId=SEC17CD1A3E9E3F2&DeviceType=SAMSUNGSGHI317M
//
- (NSString *) deviceId
{
NSString *s;
s = [self _valueForParameter: @"DEVICEID="];
if (!s)
s = @"Unknown";
return s;
}
//
//
//
- (NSString *) command
{
NSString *s;
s = [self _valueForParameter: @"CMD="];
if (!s)
s = @"Unknown";
return s;
}
//
// FIXME: combine with our OpenChange code.
//
- (char) _decodeHexByte: (char) byteChar
{
char newByte;
if (byteChar >= 48 && byteChar <= 57)
newByte = (uint8_t) byteChar - 48;
else if (byteChar >= 65 && byteChar <= 70)
newByte = (uint8_t) byteChar - 55;
else if (byteChar >= 97 && byteChar <= 102)
newByte = (uint8_t) byteChar - 87;
else
newByte = -1;
return newByte;
}
//
// FIXME: combine with our OpenChange code.
//
- (BOOL) _decodeHexByte: (uint8_t *) byte
atPos: (NSUInteger) pos
{
BOOL error = NO;
char newByte;
unichar byteChar;
byteChar = [self characterAtIndex: pos];
if (byteChar < 256)
{
newByte = [self _decodeHexByte: (char) byteChar];
if (newByte == -1)
error = YES;
else
*byte = newByte;
}
else
error = YES;
return error;
}
//
// FIXME: combine with our OpenChange code.
//
- (BOOL) _decodeHexPair: (uint8_t *) byte
atPos: (NSUInteger) pos
{
BOOL error;
uint8_t lowValue, highValue;
error = [self _decodeHexByte: &highValue atPos: pos];
if (!error)
{
error = [self _decodeHexByte: &lowValue atPos: pos + 1];
if (!error)
*byte = highValue << 4 | lowValue;
}
return error;
}
//
// FIXME: combine with our OpenChange code.
//
- (NSData *) convertHexStringToBytes
{
NSUInteger count, strLen, bytesLen;
uint8_t *bytes, *currentByte;
NSData *decoded = nil;
BOOL error = NO;
strLen = [self length];
if ((strLen % 2) == 0)
{
bytesLen = strLen / 2;
bytes = NSZoneCalloc (NULL, bytesLen, sizeof (uint8_t));
currentByte = bytes;
for (count = 0; !error && count < strLen; count += 2)
{
error = [self _decodeHexPair: currentByte atPos: count];
currentByte++;
}
if (error)
NSZoneFree (NULL, bytes);
else
decoded = [NSData dataWithBytesNoCopy: bytes
length: bytesLen
freeWhenDone: YES];
}
return decoded;
}
@end
+12
View File
@@ -0,0 +1,12 @@
In order to use this software in production environments, you need to
get a proper usage license from Microsoft. Please contact them directly
to negotiate the fees associated to your user base.
To contact Microsoft, please visit:
http://www.microsoft.com/en-us/legal/intellectualproperty/IPLicensing/Programs/exchangeactivesyncprotocol.aspx
and send an email to iplicreq@microsoft.com
Inverse inc. provides this software for free, but is not responsible
for anything related to its usage.
+42
View File
@@ -0,0 +1,42 @@
/*
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 __SOGOACTIVESYNCCONSTANTS_H__
#define __SOGOACTIVESYNCCONSTANTS_H__
typedef enum
{
ActiveSyncGenericFolder = 0,
ActiveSyncMailFolder = 1,
ActiveSyncContactFolder = 2,
ActiveSyncEventFolder = 3,
ActiveSyncTaskFolder = 4,
} SOGoMicrosoftActiveSyncFolderType;
#endif
@@ -0,0 +1,47 @@
/*
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 __SOGOACTIVESYNCDISPATCHERSYNC_H__
#define __SOGOACTIVESYNCDISPATCHERSYNC_H__
#import "SOGoActiveSyncDispatcher.h"
#import <DOM/DOMElement.h>
#import <DOM/DOMProtocols.h>
@class WOResponse;
@interface SOGoActiveSyncDispatcher (Sync)
- (void) processSync: (id <DOMElement>) theDocumentElement
inResponse: (WOResponse *) theResponse;
@end
#endif // SOGOACTIVESYNCDISPATCHERSYNC
File diff suppressed because it is too large. Load diff
+48
View File
@@ -0,0 +1,48 @@
/*
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 <Foundation/NSObject.h>
#include "SOGoActiveSyncConstants.h"
@class NSException;
@interface SOGoActiveSyncDispatcher : NSObject
{
id context;
}
- (id) collectionFromId: (NSString *) theCollectionId
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType;
- (NSException *) dispatchRequest: (id) theRequest
inResponse: (id) theResponse
context: (id) theContext;
@end
File diff suppressed because it is too large. Load diff
+48
View File
@@ -0,0 +1,48 @@
/*
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 __SOGOMAILOBJECTACTIVESYNC_H__
#define __SOGOMAILOBJECTACTIVESYNC_H__
#import <Mailer/SOGoMailObject.h>
@class iCalCalendar;
@class NSDictionary;
@class WOContext;
@interface SOGoMailObject (ActiveSync)
- (iCalCalendar *) calendarFromIMIPMessage;
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
@end
#endif
+639
View File
@@ -0,0 +1,639 @@
/*
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 "SOGoMailObject+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
#import <Foundation/NSString.h>
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalDateTime.h>
#import <NGCards/iCalEvent.h>
#import <NGCards/iCalPerson.h>
#import <NGCards/iCalTimeZone.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NSString+misc.h>
#import <NGExtensions/NSString+Encoding.h>
#import <NGImap4/NGImap4Envelope.h>
#import <NGImap4/NGImap4EnvelopeAddress.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#include "iCalTimeZone+ActiveSync.h"
#include "NSData+ActiveSync.h"
#include "NSDate+ActiveSync.h"
#include "NSString+ActiveSync.h"
#include <Appointments/iCalEntityObject+SOGo.h>
#include <Appointments/iCalPerson+SOGo.h>
#include <Mailer/NSString+Mail.h>
#include <Mailer/SOGoMailBodyPart.h>
#include <SOGo/SOGoUser.h>
typedef struct {
uint32_t dwLowDateTime;
uint32_t dwHighDateTime;
} FILETIME;
struct GlobalObjectId {
uint8_t ByteArrayID[16];
uint8_t YH;
uint8_t YL;
uint8_t Month;
uint8_t D;
FILETIME CreationTime;
uint8_t X[8];
uint32_t Size;
uint8_t* Data;
};
@implementation SOGoMailObject (ActiveSync)
//
//
//
- (void) _setInstanceDate: (struct GlobalObjectId *) newGlobalId
fromDate: (NSCalendarDate *) instanceDate
{
uint16_t year;
if (instanceDate)
{
//[instanceDate setTimeZone: timeZone];
year = [instanceDate yearOfCommonEra];
newGlobalId->YH = year >> 8;
newGlobalId->YL = year & 0xff;
newGlobalId->Month = [instanceDate monthOfYear];
newGlobalId->D = [instanceDate dayOfMonth];
}
}
//
// The GlobalObjId is documented here: http://msdn.microsoft.com/en-us/library/ee160198(v=EXCHG.80).aspx
//
- (NSData *) _computeGlobalObjectIdFromEvent: (iCalEvent *) event
{
NSData *binPrefix, *globalObjectId, *uidAsASCII;
NSString *prefix, *uid;
struct GlobalObjectId newGlobalId;
const char *bytes;
prefix = @"040000008200e00074c5b7101a82e008";
// dataPrefix is "vCal-Uid %x01 %x00 %x00 %x00"
uint8_t dataPrefix[] = { 0x76, 0x43, 0x61, 0x6c, 0x2d, 0x55, 0x69, 0x64, 0x01, 0x00, 0x00, 0x00 };
uid = [event uid];
binPrefix = [prefix convertHexStringToBytes];
[binPrefix getBytes: &newGlobalId.ByteArrayID];
[self _setInstanceDate: &newGlobalId
fromDate: [event recurrenceId]];
uidAsASCII = [uid dataUsingEncoding: NSASCIIStringEncoding];
bytes = [uidAsASCII bytes];
// 0x0c is the size of our dataPrefix
newGlobalId.Size = 0x0c + [uidAsASCII length];
newGlobalId.Data = malloc(newGlobalId.Size * sizeof(uint8_t));
memcpy(newGlobalId.Data, dataPrefix, 0x0c);
memcpy(newGlobalId.Data + 0x0c, bytes, newGlobalId.Size - 0x0c);
globalObjectId = [[NSData alloc] initWithBytes: &newGlobalId length: 40 + newGlobalId.Size*sizeof(uint8_t)];
free(newGlobalId.Data);
return [globalObjectId autorelease];
}
//
// For debugging purposes...
//
- (NSString *) _uidFromGlobalObjectId: (NSData *) objectId
{
NSString *uid;
struct GlobalObjectId *newGlobalId;
NSUInteger length;
uint8_t *bytes;
length = [objectId length];
uid = nil;
bytes = malloc(length*sizeof(uint8_t));
[objectId getBytes: bytes length: length];
newGlobalId = (struct GlobalObjectId *)bytes;
// We must take the offset (dataPrefix) into account
uid = [[NSString alloc] initWithBytes: newGlobalId->Data+12 length: newGlobalId->Size-12 encoding: NSASCIIStringEncoding];
free(bytes);
return AUTORELEASE(uid);
}
//
//
//
- (NSString *) _emailAddressesFrom: (NSArray *) enveloppeAddresses
{
NGImap4EnvelopeAddress *address;
NSString *email, *rc, *name;
NSMutableArray *addresses;
int i, max;
rc = nil;
max = [enveloppeAddresses count];
if (max > 0)
{
addresses = [NSMutableArray array];
for (i = 0; i < max; i++)
{
address = [enveloppeAddresses objectAtIndex: i];
name = [address personalName];
email = [NSString stringWithFormat: @"\"%@\" <%@>", (name ? name : [address baseEMail]), [address baseEMail]];
if (email)
[addresses addObject: email];
}
rc = [addresses componentsJoinedByString: @", "];
}
return rc;
}
//
//
//
- (NSData *) _preferredBodyDataInMultipartUsingType: (int) theType
{
NSString *key, *plainKey, *htmlKey, *type, *subtype;
NSDictionary *textParts, *part;
NSEnumerator *e;
NSData *d;
textParts = [self fetchPlainTextParts];
e = [textParts keyEnumerator];
plainKey = nil;
htmlKey = nil;
d = nil;
while ((key = [e nextObject]))
{
part = [self lookupInfoForBodyPart: key];
type = [part valueForKey: @"type"];
subtype = [part valueForKey: @"subtype"];
if ([type isEqualToString: @"text"] && [subtype isEqualToString: @"html"])
htmlKey = key;
else if ([type isEqualToString: @"text"] && [subtype isEqualToString: @"plain"])
plainKey = key;
}
if (theType == 2)
{
d = [[self fetchPlainTextParts] objectForKey: htmlKey];
}
else if (theType == 1)
{
d = [[self fetchPlainTextParts] objectForKey: plainKey];
}
return d;
}
//
//
//
- (NSData *) _preferredBodyDataUsingType: (int) theType
nativeType: (int *) theNativeType
{
NSString *type, *subtype, *encoding;
NSData *d;
type = [[[self bodyStructure] valueForKey: @"type"] lowercaseString];
subtype = [[[self bodyStructure] valueForKey: @"subtype"] lowercaseString];
d = nil;
// We determine the native type
if ([type isEqualToString: @"text"] && [subtype isEqualToString: @"plain"])
*theNativeType = 1;
else if ([type isEqualToString: @"text"] && [subtype isEqualToString: @"html"])
*theNativeType = 2;
else if ([type isEqualToString: @"multipart"])
*theNativeType = 4;
// We get the right part based on the preference
if (theType == 1 || theType == 2)
{
if ([type isEqualToString: @"text"])
{
d = [[self fetchPlainTextParts] objectForKey: @""];
// We check if we have base64 encoded parts. If so, we just
// un-encode them before using them
encoding = [[self lookupInfoForBodyPart: @""] objectForKey: @"encoding"];
if ([encoding caseInsensitiveCompare: @"base64"] == NSOrderedSame)
d = [d dataByDecodingBase64];
// 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];
}
}
else if ([type isEqualToString: @"multipart"])
{
d = [self _preferredBodyDataInMultipartUsingType: theType];
}
}
else if (theType == 4)
{
d = [self content];
}
return d;
}
//
//
//
- (iCalCalendar *) calendarFromIMIPMessage
{
NSDictionary *part;
NSArray *parts;
int i;
// We check if we have at least 2 parts and if one of them is a text/calendar
parts = [[self bodyStructure] objectForKey: @"parts"];
if ([parts count] > 1)
{
for (i = 0; i < [parts count]; i++)
{
part = [parts objectAtIndex: i];
if ([[part objectForKey: @"type"] isEqualToString: @"text"] &&
[[part objectForKey: @"subtype"] isEqualToString: @"calendar"])
{
id bodyPart;
bodyPart = [self lookupImap4BodyPartKey: [NSString stringWithFormat: @"%d", i+1]
inContext: self->context];
if (bodyPart)
{
iCalCalendar *calendar;
NSData *calendarData;
calendarData = [bodyPart fetchBLOB];
calendar = nil;
NS_DURING
calendar = [iCalCalendar parseSingleFromSource: calendarData];
NS_HANDLER
calendar = nil;
NS_ENDHANDLER
return calendar;
}
}
}
}
return nil;
}
//
//
//
- (NSString *) activeSyncRepresentationInContext: (WOContext *) _context
{
NSData *d, *globalObjId;
NSMutableString *s;
id value;
iCalCalendar *calendar;
int preferredBodyType, nativeBodyType;
s = [NSMutableString string];
// To - "The value of this element contains one or more e-mail addresses.
// If there are multiple e-mail addresses, they are separated by commas."
value = [self _emailAddressesFrom: [[self envelope] to]];
if (value)
[s appendFormat: @"<To xmlns=\"Email:\">%@</To>", [value activeSyncRepresentationInContext: context]];
// From
value = [self _emailAddressesFrom: [[self envelope] from]];
if (value)
[s appendFormat: @"<From xmlns=\"Email:\">%@</From>", [value activeSyncRepresentationInContext: context]];
// Subject
value = [self decodedSubject];
if (value)
{
[s appendFormat: @"<Subject xmlns=\"Email:\">%@</Subject>", [value activeSyncRepresentationInContext: context]];
[s appendFormat: @"<ThreadTopic xmlns=\"Email:\">%@</ThreadTopic>", [value activeSyncRepresentationInContext: context]];
}
// DateReceived
value = [self date];
if (value)
[s appendFormat: @"<DateReceived xmlns=\"Email:\">%@</DateReceived>", [value activeSyncRepresentationInContext: context]];
// DisplayTo
[s appendFormat: @"<DisplayTo xmlns=\"Email:\">%@</DisplayTo>", [[context activeUser] login]];
// Cc - same syntax as the To field
value = [self _emailAddressesFrom: [[self envelope] cc]];
if (value)
[s appendFormat: @"<Cc xmlns=\"Email:\">%@</Cc>", [value activeSyncRepresentationInContext: context]];
// Importance - FIXME
[s appendFormat: @"<Importance xmlns=\"Email:\">%@</Importance>", @"1"];
// Read
[s appendFormat: @"<Read xmlns=\"Email:\">%d</Read>", ([self read] ? 1 : 0)];
// We handle MeetingRequest
calendar = [self calendarFromIMIPMessage];
if (calendar)
{
NSString *method, *className;
iCalPerson *attendee;
iCalTimeZone *tz;
iCalEvent *event;
iCalPersonPartStat partstat;
int v;
event = [[calendar events] lastObject];
method = [[event parent] method];
// If we are the organizer, let's pick the attendee based on the From address
if ([event userIsOrganizer: [context activeUser]])
attendee = [event findAttendeeWithEmail: [[[[self envelope] from] lastObject] baseEMail]];
else
attendee = [event findAttendeeWithEmail: [[[context activeUser] allEmails] objectAtIndex: 0]];
partstat = [attendee participationStatus];
// We generate the correct MessageClass
if ([method isEqualToString: @"REQUEST"])
className = @"IPM.Schedule.Meeting.Request";
else if ([method isEqualToString: @"REPLY"])
{
switch (partstat)
{
case iCalPersonPartStatAccepted:
className = @"IPM.Schedule.Meeting.Resp.Pos";
break;
case iCalPersonPartStatDeclined:
className = @"IPM.Schedule.Meeting.Resp.Neg";
break;
case iCalPersonPartStatTentative:
case iCalPersonPartStatNeedsAction:
className = @"IPM.Schedule.Meeting.Resp.Tent";
break;
default:
className = @"IPM.Appointment";
NSLog(@"unhandled part stat");
}
}
else if ([method isEqualToString: @"COUNTER"])
className = @"IPM.Schedule.Meeting.Resp.Tent";
else if ([method isEqualToString: @"CANCEL"])
className = @"IPM.Schedule.Meeting.Cancelled";
else
className = @"IPM.Appointment";
[s appendFormat: @"<MessageClass xmlns=\"Email:\">%@</MessageClass>", className];
[s appendString: @"<MeetingRequest xmlns=\"Email:\">"];
[s appendFormat: @"<AllDayEvent xmlns=\"Email:\">%d</AllDayEvent>", ([event isAllDay] ? 1 : 0)];
// StartTime -- http://msdn.microsoft.com/en-us/library/ee157132(v=exchg.80).aspx
if ([event startDate])
[s appendFormat: @"<StartTime xmlns=\"Email:\">%@</StartTime>", [[event startDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
if ([event timeStampAsDate])
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event timeStampAsDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
else if ([event created])
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event created] activeSyncRepresentationWithoutSeparatorsInContext: context]];
// EndTime -- http://msdn.microsoft.com/en-us/library/ee157945(v=exchg.80).aspx
if ([event endDate])
[s appendFormat: @"<EndTime xmlns=\"Email:\">%@</EndTime>", [[event endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
// FIXME: Single appointment - others are not supported right now
[s appendFormat: @"<InstanceType xmlns=\"Email:\">%d</InstanceType>", 0];
// Location
if ([[event location] length])
[s appendFormat: @"<Location xmlns=\"Email:\">%@</Location>", [[event location] activeSyncRepresentationInContext: context]];
[s appendFormat: @"<Organizer xmlns=\"Email:\">%@</Organizer>", [[[event organizer] mailAddress] activeSyncRepresentationInContext: context]];
// This will trigger the SendMail command. We set it to no for email invitations as
// SOGo will send emails when MeetingResponse is called.
[s appendFormat: @"<ResponseRequested xmlns=\"Email:\">%d</ResponseRequested>", 0];
// Sensitivity
if ([[event accessClass] isEqualToString: @"PRIVATE"])
v = 2;
if ([[event accessClass] isEqualToString: @"CONFIDENTIAL"])
v = 3;
else
v = 0;
[s appendFormat: @"<Sensitivity xmlns=\"Email:\">%d</Sensitivity>", v];
[s appendFormat: @"<BusyStatus xmlns=\"Email:\">%d</BusyStatus>", 2];
// Timezone
tz = [(iCalDateTime *)[event firstChildWithTag: @"dtstart"] timeZone];
if (!tz)
tz = [iCalTimeZone timeZoneForName: @"Europe/London"];
[s appendFormat: @"<TimeZone xmlns=\"Email:\">%@</TimeZone>", [tz activeSyncRepresentationInContext: context]];
// We disallow new time proposals
[s appendFormat: @"<DisallowNewTimeProposal xmlns=\"Email:\">%d</DisallowNewTimeProposal>", 1];
// From http://blogs.msdn.com/b/exchangedev/archive/2011/07/22/working-with-meeting-requests-in-exchange-activesync.aspx:
//
// "Clients that need to determine whether the GlobalObjId element for a meeting request corresponds to an existing Calendar
// object in the Calendar folder have to convert the GlobalObjId element value to a UID element value to make the comparison."
//
globalObjId = [self _computeGlobalObjectIdFromEvent: event];
[s appendFormat: @"<GlobalObjId xmlns=\"Email:\">%@</GlobalObjId>", [globalObjId activeSyncRepresentationInContext: context]];
// We set the right message type - we must set AS version to 14.1 for this
[s appendFormat: @"<MeetingMessageType xmlns=\"Email2:\">%d</MeetingMessageType>", 1];
[s appendString: @"</MeetingRequest>"];
// ContentClass
[s appendFormat: @"<ContentClass xmlns=\"Email:\">%@</ContentClass>", @"urn:content-classes:calendarmessage"];
}
else
{
// MesssageClass and ContentClass
[s appendFormat: @"<MessageClass xmlns=\"Email:\">%@</MessageClass>", @"IPM.Note"];
[s appendFormat: @"<ContentClass xmlns=\"Email:\">%@</ContentClass>", @"urn:content-classes:message"];
}
// Reply-To - FIXME
//NSArray *replyTo = [[message objectForKey: @"envelope"] replyTo];
//if ([replyTo count])
// [s appendFormat: @"<Reply-To xmlns=\"Email:\">%@</Reply-To>", [addressFormatter stringForArray: replyTo]];
// InternetCPID - 65001 == UTF-8, we use this all the time for now.
[s appendFormat: @"<InternetCPID xmlns=\"Email:\">%@</InternetCPID>", @"65001"];
// Body - namespace 17
preferredBodyType = [[context objectForKey: @"BodyPreferenceType"] intValue];
nativeBodyType = 1;
d = [self _preferredBodyDataUsingType: preferredBodyType nativeType: &nativeBodyType];
if (d)
{
NSString *content;
int len, truncated;
content = [[NSString alloc] initWithData: d encoding: NSUTF8StringEncoding];
// FIXME: This is a hack. We should normally avoid doing this as we might get
// broken encodings. We should rather tell that the data was truncated and expect
// a ItemOperations call to download the whole base64 encoding multipart.
if (!content)
content = [[NSString alloc] initWithData: d encoding: NSISOLatin1StringEncoding];
AUTORELEASE(content);
content = [content activeSyncRepresentationInContext: context];
truncated = 0;
len = [content length];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", preferredBodyType];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", len];
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
if (!truncated)
[s appendFormat: @"<Data>%@</Data>", content];
[s appendString: @"</Body>"];
}
// Attachments -namespace 16
NSArray *attachmentKeys = [self fetchFileAttachmentKeys];
if ([attachmentKeys count])
{
int i;
[s appendString: @"<Attachments xmlns=\"AirSyncBase:\">"];
for (i = 0; i < [attachmentKeys count]; i++)
{
value = [attachmentKeys objectAtIndex: i];
[s appendString: @"<Attachment>"];
[s appendFormat: @"<DisplayName>%@</DisplayName>", [[value objectForKey: @"filename"] activeSyncRepresentationInContext: context]];
// FileReference must be a unique identifier across the whole store. We use the following structure:
// mail/<foldername>/<message UID/<pathofpart>
// mail/INBOX/2
[s appendFormat: @"<FileReference>mail/%@/%@/%@</FileReference>", [[[self container] relativeImap4Name] stringByEscapingURL], [self nameInContainer], [value objectForKey: @"path"]];
[s appendFormat: @"<Method>%d</Method>", 1]; // See: http://msdn.microsoft.com/en-us/library/ee160322(v=exchg.80).aspx
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [[value objectForKey: @"size"] intValue]];
//[s appendFormat: @"<IsInline>%d</IsInline>", 1];
[s appendString: @"</Attachment>"];
}
[s appendString: @"</Attachments>"];
}
// Flags
[s appendString: @"<Flag xmlns=\"Email:\">"];
[s appendFormat: @"<FlagStatus>%d</FlagStatus>", 0];
[s appendString: @"</Flag>"];
// FIXME - support these in the future
//[s appendString: @"<ConversationId xmlns=\"Email2:\">foobar</ConversationId>"];
//[s appendString: @"<ConversationIndex xmlns=\"Email2:\">zot=</ConversationIndex>"];
// NativeBodyType -- http://msdn.microsoft.com/en-us/library/ee218276(v=exchg.80).aspx
// This is a required child element.
// 1 -> plain/text, 2 -> HTML and 3 -> RTF
if (nativeBodyType == 4)
nativeBodyType = 1;
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", nativeBodyType];
return s;
}
//
//
//
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) _context
{
id o;
if ((o = [theValues objectForKey: @"Flag"]))
{
o = [o objectForKey: @"FlagStatus"];
if ([o intValue])
[self addFlags: @"\\Flagged"];
else
[self removeFlags: @"\\Flagged"];
}
}
@end
@@ -0,0 +1,101 @@
/*
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 <NGObjWeb/SoObjectWebDAVDispatcher.h>
#include <NGObjWeb/SoObject+SoDAV.h>
#include <NGObjWeb/WEClientCapabilities.h>
#include <NGObjWeb/WOContext.h>
#include <NGObjWeb/WORequest.h>
#include <NGObjWeb/WOResponse.h>
#import <Foundation/NSArray.h>
@interface SoObjectWebDAVDispatcher (ActiveSync)
- (id)_callObjectMethod:(NSString *)_method inContext:(WOContext *)_ctx;
- (id) doOPTIONS:(WOContext *)_ctx;
@end
@implementation SoObjectWebDAVDispatcher (ActiveSync)
- (id) doOPTIONS:(WOContext *)_ctx
{
WOResponse *response;
/*
See example: http://msdn.microsoft.com/en-us/library/ee204257(v=exchg.80).aspx
*/
if ([[[_ctx request] requestHandlerKey] isEqualToString: @"Microsoft-Server-ActiveSync"])
{
response = [_ctx response];
[response setStatus: 200];
[response setHeader: @"private" forKey: @"Cache-Control"];
[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: @"OPTIONS, POST" forKey: @"Public"];
}
else
{
NSArray *tmp;
id result;
/* this checks whether the object provides a specific OPTIONS method */
if ((result = [self _callObjectMethod:@"OPTIONS" inContext:_ctx]) != nil)
return result;
response = [_ctx response];
[response setStatus:200 /* OK */];
if ((tmp = [self->object davAllowedMethodsInContext:_ctx]) != nil)
[response setHeader:[tmp componentsJoinedByString:@", "] forKey:@"allow"];
if ([[[_ctx request] clientCapabilities] isWebFolder]) {
/*
As described over here:
http://teyc.editthispage.com/2005/06/02
This page also says that: "MS-Auth-Via header is not required to work
with Web Folders".
*/
[response setHeader:[tmp componentsJoinedByString:@", "] forKey:@"public"];
}
if ((tmp = [self->object davComplianceClassesInContext:_ctx]) != nil)
[response setHeader:[tmp componentsJoinedByString:@", "] forKey:@"dav"];
}
return response;
}
@end
+36
View File
@@ -0,0 +1,36 @@
# common make file for SoObject bundles
include ../config.make
include $(GNUSTEP_MAKEFILES)/common.make
include ../Version
NEEDS_GUI=no
BUNDLE_EXTENSION = .SOGo
BUNDLE_INSTALL_DIR = $(SOGO_LIBDIR)
WOBUNDLE_EXTENSION = $(BUNDLE_EXTENSION)
WOBUNDLE_INSTALL_DIR = $(BUNDLE_INSTALL_DIR)
# SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
ADDITIONAL_INCLUDE_DIRS += \
-I.. \
-I../.. \
-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/usr/local/lib
BUNDLE_LIBS += \
-lSOGo \
-lGDLContentStore \
-lGDLAccess \
-lNGObjWeb \
-lNGCards -lNGMime -lNGLdap \
-lNGStreams -lNGExtensions -lEOControl \
-lDOM -lSaxObjC -lSBJson
ADDITIONAL_BUNDLE_LIBS += $(BUNDLE_LIBS)
+47
View File
@@ -0,0 +1,47 @@
/*
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 __ICALEVENTACTIVESYNC_H__
#define __ICALEVENTACTIVESYNC_H__
#import <NGCards/iCalEvent.h>
@class NSString;
@class WOContext;
@interface iCalEvent (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
@end
#endif
+471
View File
@@ -0,0 +1,471 @@
/*
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 "iCalEvent+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSString+misc.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalDateTime.h>
#import <NGCards/iCalPerson.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <Appointments/iCalEntityObject+SOGo.h>
#include "iCalRecurrenceRule+ActiveSync.h"
#include "iCalTimeZone+ActiveSync.h"
#include "NSDate+ActiveSync.h"
#include "NSString+ActiveSync.h"
@implementation iCalEvent (ActiveSync)
- (int) _attendeeStatus: (iCalPerson *) attendee
{
int attendee_status;
attendee_status = 5;
if ([[attendee partStat] caseInsensitiveCompare: @"ACCEPTED"] == NSOrderedSame)
attendee_status = 3;
else if ([[attendee partStat] caseInsensitiveCompare: @"DECLINED"] == NSOrderedSame)
attendee_status = 4;
else if ([[attendee partStat] caseInsensitiveCompare: @"TENTATIVE"] == NSOrderedSame)
attendee_status = 2;
return attendee_status;
}
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSMutableString *s;
NSArray *attendees;
iCalPerson *organizer, *attendee;
iCalTimeZone *tz;
id o;
int v;
s = [NSMutableString string];
[s appendFormat: @"<AllDayEvent xmlns=\"Calendar:\">%d</AllDayEvent>", ([self isAllDay] ? 1 : 0)];
// DTStamp -- http://msdn.microsoft.com/en-us/library/ee219470(v=exchg.80).aspx
if ([self timeStampAsDate])
[s appendFormat: @"<DTStamp xmlns=\"Calendar:\">%@</DTStamp>", [[self timeStampAsDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
else if ([self created])
[s appendFormat: @"<DTStamp xmlns=\"Calendar:\">%@</DTStamp>", [[self created] activeSyncRepresentationWithoutSeparatorsInContext: context]];
// 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]];
// 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]];
// Timezone
tz = [(iCalDateTime *)[self firstChildWithTag: @"dtstart"] timeZone];
if (!tz)
tz = [iCalTimeZone timeZoneForName: @"Europe/London"];
[s appendFormat: @"<TimeZone xmlns=\"Calendar:\">%@</TimeZone>", [tz activeSyncRepresentationInContext: context]];
// Organizer and other invitations related properties
if ((organizer = [self organizer]))
{
o = [organizer rfc822Email];
if ([o length])
{
[s appendFormat: @"<Organizer_Email xmlns=\"Calendar:\">%@</Organizer_Email>", o];
o = [organizer cn];
if ([o length])
[s appendFormat: @"<Organizer_Name xmlns=\"Calendar:\">%@</Organizer_Name>", o];
}
}
// Attendees
attendees = [self attendees];
if ([attendees count])
{
int i, attendee_status, attendee_type;
[s appendString: @"<Attendees xmlns=\"Calendar:\">"];
for (i = 0; i < [attendees count]; i++)
{
[s appendString: @"<Attendee xmlns=\"Calendar:\">"];
attendee = [attendees objectAtIndex: i];
[s appendFormat: @"<Attendee_Email xmlns=\"Calendar:\">%@</Attendee_Email>", [attendee rfc822Email]];
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [attendee cn]];
attendee_status = [self _attendeeStatus: attendee];
[s appendFormat: @"<Attendee_Status xmlns=\"Calendar:\">%d</Attendee_Status>", attendee_status];
// FIXME: handle resource
if ([[attendee role] caseInsensitiveCompare: @"REQ-PARTICIPANT"] == NSOrderedSame)
attendee_type = 1;
else
attendee_type = 2;
[s appendFormat: @"<Attendee_Type xmlns=\"Calendar:\">%d</Attendee_Type>", attendee_type];
[s appendString: @"</Attendee>"];
}
[s appendString: @"</Attendees>"];
}
// This depends on the 'NEEDS-ACTION' parameter.
// This will trigger the SendMail command
if ([self userIsAttendee: [context activeUser]])
{
iCalPerson *attendee;
int attendee_status;
attendee = [self userAsAttendee: [context activeUser]];
attendee_status = [self _attendeeStatus: attendee];
[s appendFormat: @"<ResponseRequested xmlns=\"Calendar:\">%d</ResponseRequested>", 1];
[s appendFormat: @"<ResponseType xmlns=\"Calendar:\">%d</ResponseType>", attendee_status];
[s appendFormat: @"<MeetingStatus xmlns=\"Calendar:\">%d</MeetingStatus>", 3];
[s appendFormat: @"<DisallowNewTimeProposal xmlns=\"Calendar:\">%d</DisallowNewTimeProposal>", 1];
// BusyStatus -- http://msdn.microsoft.com/en-us/library/ee202290(v=exchg.80).aspx
[s appendFormat: @"<BusyStatus xmlns=\"Calendar:\">%d</BusyStatus>", 2];
}
// Subject -- http://msdn.microsoft.com/en-us/library/ee157192(v=exchg.80).aspx
if ([[self summary] length])
[s appendFormat: @"<Subject xmlns=\"Calendar:\">%@</Subject>", [[self summary] activeSyncRepresentationInContext: context]];
// Location
if ([[self location] length])
[s appendFormat: @"<Location xmlns=\"Calendar:\">%@</Location>", [[self location] activeSyncRepresentationInContext: context]];
// Importance - NOT SUPPORTED - DO NOT ENABLE
//o = [self priority];
//if ([o isEqualToString: @"9"])
// v = 0;
//else if ([o isEqualToString: @"1"])
// v = 2;
//else
// v = 1;
//[s appendFormat: @"<Importance xmlns=\"Calendar:\">%d</Importance>", v];
// UID -- http://msdn.microsoft.com/en-us/library/ee159919(v=exchg.80).aspx
if ([[self uid] length])
[s appendFormat: @"<UID xmlns=\"Calendar:\">%@</UID>", [self uid]];
// Sensitivity
if ([[self accessClass] isEqualToString: @"PRIVATE"])
v = 2;
if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
v = 3;
else
v = 0;
[s appendFormat: @"<Sensitivity xmlns=\"Calendar:\">%d</Sensitivity>", v];
// Reminder -- http://msdn.microsoft.com/en-us/library/ee219691(v=exchg.80).aspx
// TODO
// Recurrence rules
if ([self isRecurrent])
{
[s appendString: [[[self recurrenceRules] lastObject] activeSyncRepresentationInContext: context]];
}
// Comment
o = [self comment];
if ([o length])
{
o = [o activeSyncRepresentationInContext: context];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
return s;
}
//
// To understand meeting requests/responses, see:
//
// http://blogs.msdn.com/b/exchangedev/archive/2011/07/22/working-with-meeting-requests-in-exchange-activesync.aspx
// http://blogs.msdn.com/b/exchangedev/archive/2011/07/29/working-with-meeting-responses-in-exchange-activesync.aspx
//
//
// Here is an example of a Sync call when sogo10 accepts an invitation from sogo3:
//
// <Change>
// <ServerId>2978-52EA9D00-1-A253E70.ics</ServerId>
// <ApplicationData>
// <TimeZone xmlns="Calendar:">LAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAAAAAAAAxP///w==</TimeZone>
// <AllDayEvent xmlns="Calendar:">0</AllDayEvent>
// <StartTime xmlns="Calendar:">20140207T130000Z</StartTime>
// <EndTime xmlns="Calendar:">20140207T140000Z</EndTime>
// <DTStamp xmlns="Calendar:">20140130T185245Z</DTStamp>
// <Subject xmlns="Calendar:">test 8</Subject>
// <Sensitivity xmlns="Calendar:">0</Sensitivity>
// <Body xmlns="AirSyncBase:">
// <Type>1</Type>
// <Data/>
// </Body>
// <Organizer_Email xmlns="Calendar:">sogo3@example.com</Organizer_Email>
// <UID xmlns="Calendar:">2978-52EA9D00-1-A253E70</UID>
// <Attendees xmlns="Calendar:">
// <Attendee>
// <Attendee_Name>sogo10</Attendee_Name>
// <Attendee_Email>sogo10@example.com</Attendee_Email>
// <Attendee_Type>1</Attendee_Type>
// </Attendee>
// </Attendees>
// <BusyStatus xmlns="Calendar:">2</BusyStatus>
// <MeetingStatus xmlns="Calendar:">3</MeetingStatus>
// <Organizer_Name xmlns="Calendar:">Wolfgang Fritz</Organizer_Name>
// </ApplicationData>
// </Change>
//
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context
{
iCalDateTime *start, *end;
NSTimeZone *userTimeZone;
iCalTimeZone *tz;
id o;
NSInteger tzOffset;
BOOL isAllDay;
if ((o = [theValues objectForKey: @"UID"]))
[self setUid: o];
// FIXME: merge with iCalToDo
if ((o = [theValues objectForKey: @"Subject"]))
[self setSummary: o];
isAllDay = NO;
if ([[theValues objectForKey: @"AllDayEvent"] intValue])
{
isAllDay = YES;
}
//
// 0- free, 1- tentative, 2- busy and 3- out of office
//
if ((o = [theValues objectForKey: @"BusyStatus"]))
{
[o intValue];
}
//
//
//
if ((o = [theValues objectForKey: @"MeetingStatus"]))
{
[o intValue];
}
//
// 0- normal, 1- personal, 2- private and 3-confidential
//
if ((o = [theValues objectForKey: @"Sensitivy"]))
{
switch ([o intValue])
{
case 2:
[self setAccessClass: @"PRIVATE"];
break;
case 3:
[self setAccessClass: @"CONFIDENTIAL"];
break;
case 0:
case 1:
default:
[self setAccessClass: @"PUBLIC"];
}
}
if ((o = [theValues objectForKey: @"TimeZone"]))
{
// Ugh, we ignore it for now.
userTimeZone = [[[context activeUser] userDefaults] timeZone];
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
[(iCalCalendar *) parent addTimeZone: tz];
}
// FIXME: merge with iCalToDo
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setComment: o];
if ((o = [theValues objectForKey: @"Location"]))
[self setLocation: o];
if ((o = [theValues objectForKey: @"StartTime"]))
{
o = [o calendarDate];
start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
[start setTimeZone: tz];
if (isAllDay)
{
[start setDate: o];
[start setTimeZone: nil];
}
else
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[start setDateTime: o];
}
}
if ((o = [theValues objectForKey: @"EndTime"]))
{
o = [o calendarDate];
end = (iCalDateTime *) [self uniqueChildWithTag: @"dtend"];
[end setTimeZone: tz];
if (isAllDay)
{
[end setDate: o];
[end setTimeZone: nil];
}
else
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[end setDateTime: o];
}
}
// Recurrence
if ((o = [theValues objectForKey: @"Recurrence"]))
{
iCalRecurrenceRule *rule;
rule = [[iCalRecurrenceRule alloc] init];
[self setRecurrenceRules: [NSArray arrayWithObject: rule]];
RELEASE(rule);
[rule takeActiveSyncValues: o inContext: context];
}
// Organizer - we don't touch the value unless we're the organizer
if ((o = [theValues objectForKey: @"Organizer_Email"]) &&
([self userIsOrganizer: [context activeUser]] || [[context activeUser] hasEmail: o]))
{
iCalPerson *person;
person = [iCalPerson elementWithTag: @"organizer"];
[person setEmail: o];
[person setCn: [theValues objectForKey: @"Organizer_Name"]];
[person setPartStat: @"ACCEPTED"];
[self setOrganizer: person];
}
// Attendees - we don't touch the values if we're an attendee. This is gonna
// be done automatically by the ActiveSync client when invoking MeetingResponse.
if (![self userIsAttendee: [context activeUser]])
{
if ((o = [theValues objectForKey: @"Attendees"]))
{
NSMutableArray *attendees;
NSDictionary *attendee;
iCalPerson *person;
int status, i;
attendees = [NSMutableArray array];
for (i = 0; i < [o count]; i++)
{
// Each attendee has is a dictionary similar to this:
// { "Attendee_Email" = "sogo3@example.com"; "Attendee_Name" = "Wolfgang Fritz"; "Attendee_Status" = 5; "Attendee_Type" = 1; }
attendee = [o objectAtIndex: i];
person = [iCalPerson elementWithTag: @"attendee"];
[person setCn: [attendee objectForKey: @"Attendee_Name"]];
[person setEmail: [attendee objectForKey: @"Attendee_Email"]];
status = [[attendee objectForKey: @"Attendee_Status"] intValue];
switch (status)
{
case 2:
[person setPartStat: @"TENTATIVE"];
break;
case 3:
[person setPartStat: @"ACCEPTED"];
break;
case 4:
[person setPartStat: @"DECLINED"];
break;
case 0:
case 5:
default:
[person setPartStat: @"NEEDS-ACTION"];
break;
}
// FIXME: handle Attendee_Type
[attendees addObject: person];
}
[self setAttendees: attendees];
}
}
}
@end
@@ -0,0 +1,48 @@
/*
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 __ICALRECURRENCERULEACTIVESYNC_H__
#define __ICALRECURRENCERULEACTIVESYNC_H__
#import <NGCards/iCalRecurrenceRule.h>
@class NSDictionary;
@class NSString;
@class WOContext;
@interface iCalRecurrenceRule (ActiveSync)
- (NSString *) activeSyncRepresentationInContext:(WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
@end
#endif
+355
View File
@@ -0,0 +1,355 @@
/*
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 "iCalRecurrenceRule+ActiveSync.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <NGCards/iCalByDayMask.h>
#import "NSCalendarDate+ActiveSync.h"
#import "NSDate+ActiveSync.h"
@implementation iCalRecurrenceRule (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSMutableString *s;
int type;
s = [NSMutableString string];
[s appendString: @"<Recurrence xmlns=\"Calendar:\">"];
// 0 -> daily, 1 -> weekly, 2 -> montly, 5 -> yearly
type = 0;
if ([self frequency] == iCalRecurrenceFrequenceDaily)
{
type = 0;
// 1 -> sunday, 2 -> monday, 4 -> tuesday, 8 -> wednesday, 16 -> thursday, 32 -> friday, 64 -> saturday, 127 -> last day of month (montly or yearl recurrences only)
if ([[self byDayMask] isWeekDays])
{
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (2|4|8|16|32)];
}
else
{
[s appendFormat: @"<Recurrence_Interval xmlns=\"Calendar:\">%d</Recurrence_Interval>", [self repeatInterval]];
}
}
else if ([self frequency] == iCalRecurrenceFrequenceWeekly)
{
iCalWeekOccurrences *occurrences;
int i, v;
type = 1;
occurrences = [[self byDayMask] weekDayOccurrences];
v = 0;
for (i = 0; i < 7; i++)
{
if (occurrences[i])
v += (1 << i);
}
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", v];
[s appendFormat: @"<Recurrence_Interval xmlns=\"Calendar:\">%d</Recurrence_Interval>", [self repeatInterval]];
}
else if ([self frequency] == iCalRecurrenceFrequenceMonthly)
{
if ([[self byDay] length])
{
int firstOccurrence;
iCalByDayMask *dm;
type = 3; // recurs monthly on the nth day
dm = [self byDayMask];
firstOccurrence = [dayMask firstOccurrence];
// Handle the case for "Last day of the month"
if (firstOccurrence < 0)
firstOccurrence = 5;
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (1 << [dm firstDay])];
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"Calendar:\">%d</Recurrence_WeekOfMonth>", firstOccurrence];
}
else if ([[self byMonthDay] count])
{
NSArray *days;
type = 2; // recurs monthly
days = [self byMonthDay];
if ([days count] > 0 && [[days objectAtIndex: 0] intValue] < 0)
{
// Last day of the month
iCalByDayMask *dm;
dm = [self byDayMask];
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (1 << [dm firstDay])];
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"Calendar:\">%d</Recurrence_WeekOfMonth>", 5];
}
else
{
// Unsupported rule in ActiveSync/Outlook. Rule that says "Repeat on the 7th and 8th of each month".
// FIXME
}
}
}
else if ([self frequency] == iCalRecurrenceFrequenceYearly)
{
type = 6; // Yearly on the nth day
if ([[self flattenedValuesForKey: @"bymonth"] length])
{
if ([[self byDay] length])
{
int firstOccurrence;
iCalByDayMask *dm;
dm = [self byDayMask];
firstOccurrence = [dm firstOccurrence];
if (firstOccurrence < 0)
firstOccurrence = 5;
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (1 << [dm firstDay])];
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"Calendar:\">%d</Recurrence_WeekOfMonth>", firstOccurrence];
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"Calendar:\">%@</Recurrence_MonthOfYear>",
[self flattenedValuesForKey: @"bymonth"]];
}
else
{
type = 5; // Yearly
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"Calendar:\">%@</Recurrence_DayOfMonth>",
[self flattenedValuesForKey: @"bymonthday"]];
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"Calendar:\">%@</Recurrence_MonthOfYear>",
[self flattenedValuesForKey: @"bymonth"]];
}
}
else
type = 5;
}
[s appendFormat: @"<Recurrence_Type xmlns=\"Calendar:\">%d</Recurrence_Type>", type];
// Occurrences / Until
//[s appendFormat: @"<Recurrence_Occurrences xmlns=\"Calendar:\">%d</Recurrence_Occurrences>", 5];
if ([self repeatCount])
{
[s appendFormat: @"<Recurrence_Occurrences xmlns=\"Calendar:\">%@</Recurrence_Occurrences>",
[self flattenedValuesForKey: @"count"]];
}
else if ([self untilDate])
{
NSCalendarDate *date;
date = [self untilDate];
//ud = [[context activeUser] userDefaults];
//[date setTimeZone: [ud timeZone]];
[s appendFormat: @"<Recurrence_Until xmlns=\"Calendar:\">%@</Recurrence_Until>",
[date activeSyncRepresentationWithoutSeparatorsInContext: context]];
}
[s appendString: @"</Recurrence>"];
return s;
}
//
//
//
- (void) _setByDayFromValues: (NSDictionary *) theValues
{
NSString *day;
id o;
unsigned int day_of_week;
int i, week_of_month;
o = [theValues objectForKey: @"Recurrence_DayOfWeek"];
// The documentation says WeekOfMonth must be between 1 and 5. The value
// 5 means "last week of month"
week_of_month = [[theValues objectForKey: @"Recurrence_WeekOfMonth"] intValue];
if (week_of_month > 4)
week_of_month = -1;
// We find the correct day of the week
day_of_week = [o intValue];
for (i = 0; i < 7; i++)
{
if ((1<<i) == day_of_week)
{
day_of_week = i;
break;
}
}
day = [self iCalRepresentationForWeekDay: i];
[self setSingleValue: [NSString stringWithFormat: @"%d%@",
week_of_month, day]
forKey: @"byday"];
}
- (void) _setByMonthFromValues: (NSDictionary *) theValues
{
unsigned int month_of_year;
month_of_year = [[theValues objectForKey: @"Recurrence_MonthOfYear"] intValue];
[self setSingleValue: [NSString stringWithFormat: @"%d", month_of_year]
forKey: @"bymonth"];
}
//
//
//
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context
{
id o;
int recurrenceType;
recurrenceType = [[theValues objectForKey: @"Recurrence_Type"] intValue];
if ((o = [theValues objectForKey: @"Recurrence_Interval"]))
{
[self setRepeatInterval: [o intValue]];
}
else
[self setRepeatInterval: 1];
switch (recurrenceType)
{
//
// Daily
//
case 0:
[self setFrequency: iCalRecurrenceFrequenceDaily];
// Every weekday
if ((o = [theValues objectForKey: @"Recurrence_DayOfWeek"]))
{
[self setByDayMask: [iCalByDayMask byDayMaskWithWeekDays]];
}
break;
//
// Weekly
//
case 1:
[self setFrequency: iCalRecurrenceFrequenceWeekly];
// 42 == Every Monday, Wednesday and Friday, for example
if ((o = [theValues objectForKey: @"Recurrence_DayOfWeek"]))
{
iCalWeekOccurrences days;
unsigned int i, v;
memset(days, 0, 7 * sizeof(iCalWeekOccurrence));
v = [o intValue];
for (i = 0; i < 7; i++)
{
if (v & (1<<i))
days[i] = iCalWeekOccurrenceAll;
}
[self setByDayMask: [iCalByDayMask byDayMaskWithDays: days]];
}
break;
//
// Montly
//
case 2:
case 3:
[self setFrequency: iCalRecurrenceFrequenceMonthly];
// The 5th of every X month(s)
if ((o = [theValues objectForKey: @"Recurrence_DayOfMonth"]))
{
[self setValues: [NSArray arrayWithObject: o]
atIndex: 0 forKey: @"bymonthday"];
}
// The 3rd Thursay every X month(s)
else if ((o = [theValues objectForKey: @"Recurrence_DayOfWeek"]))
{
[self _setByDayFromValues: theValues];
}
break;
//
// Yearly
//
case 5:
case 6:
default:
[self setFrequency: iCalRecurrenceFrequenceYearly];
// On April 19th
if ((o = [theValues objectForKey: @"Recurrence_DayOfMonth"]))
{
[self setValues: [NSArray arrayWithObject: o] atIndex: 0
forKey: @"bymonthday"];
[self _setByMonthFromValues: theValues];
}
else
{
// On the Second Wednesday of April
[self _setByDayFromValues: theValues];
[self _setByMonthFromValues: theValues];
}
break;
}
if ((o = [theValues objectForKey: @"Recurrence_Occurrences"]))
{
[self setRepeatCount: [o intValue]];
}
else if ((o = [theValues objectForKey: @"Recurrence_Until"]))
{
[self setUntilDate: [o calendarDate]];
}
}
@end
+44
View File
@@ -0,0 +1,44 @@
/*
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 __ICALTIMEZONEACTIVESYNC_H__
#define __ICALTIMEZONEACTIVESYNC_H__
#import <NGCards/iCalTimeZone.h>
@class NSString;
@class WOContext;
@interface iCalTimeZone (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
@end
#endif
+165
View File
@@ -0,0 +1,165 @@
/*
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 "iCalTimeZone+ActiveSync.h"
#include <Foundation/NSArray.h>
#include <Foundation/NSCalendarDate.h>
#include <Foundation/NSData.h>
#include <Foundation/NSDate.h>
#include <Foundation/NSString.h>
#import <NGCards/iCalByDayMask.h>
#import <NGCards/iCalTimeZonePeriod.h>
#import <NGCards/iCalRecurrenceRule.h>
#import <NGExtensions/NGBase64Coding.h>
#include "NSData+ActiveSync.h"
struct SYSTEMTIME {
uint16_t wYear;
uint16_t wMonth;
uint16_t wDayOfWeek;
uint16_t wDay;
uint16_t wHour;
uint16_t wMinute;
uint16_t wSecond;
uint16_t wMilliseconds;
};
@interface iCalTimeZonePeriod (ActiveSync)
- (void) _fillTZDate: (struct SYSTEMTIME *) tzData;
@end
@implementation iCalTimeZonePeriod (ActiveSync)
//
// FIXME - combine with iCalTimeZone+MAPIStore.m
//
- (void) _fillTZDate: (struct SYSTEMTIME *) tzData
{
iCalRecurrenceRule *rrule;
NSArray *byMonth;
iCalByDayMask *mask;
NSCalendarDate *dateValue;
rrule = [self recurrenceRule];
byMonth = [rrule byMonth];
if ([byMonth count] > 0)
{
tzData->wMonth = [[byMonth objectAtIndex: 0] intValue];
mask = [rrule byDayMask];
tzData->wDayOfWeek = [mask firstDay];
tzData->wDay = [mask firstOccurrence];
dateValue = [self startDate];
tzData->wHour = [dateValue hourOfDay];
tzData->wMinute = [dateValue minuteOfHour];
tzData->wSecond = [dateValue secondOfMinute];
}
}
@end
@implementation iCalTimeZone (ActiveSync)
//
// FIXME - combine with iCalTimeZone+MAPIStore.m
//
- (iCalTimeZonePeriod *) _mostRecentPeriodWithName: (NSString *) periodName
{
NSArray *periods;
iCalTimeZonePeriod *period;
NSUInteger max;
periods = [self childrenWithTag: periodName];
max = [periods count];
if (max > 0)
{
periods = [periods sortedArrayUsingSelector: @selector (compare:)];
period = (iCalTimeZonePeriod *) [periods objectAtIndex: (max - 1)];
}
else
period = nil;
return period;
}
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
iCalTimeZonePeriod *period;
NSMutableData *bytes;
uint32_t lBias;
uint32_t lStandardBias;
uint32_t lDaylightBias;
//uint16_t wStandardYear;
struct SYSTEMTIME stStandardDate;
//uint16_t wDaylightYear;
struct SYSTEMTIME stDaylightDate;
char standardName[64], daylightName[64];
bytes = [NSMutableData data];
memset(standardName, 0, 64);
memset(daylightName, 0, 64);
lStandardBias = 0;
period = [self _mostRecentPeriodWithName: @"STANDARD"];
lBias = -[period secondsOffsetFromGMT] / 60;
[period _fillTZDate: &stStandardDate];
period = [self _mostRecentPeriodWithName: @"DAYLIGHT"];
if (!period)
stStandardDate.wMonth = 0;
lDaylightBias = (uint32_t) -([period secondsOffsetFromGMT] / 60) - lBias;
[period _fillTZDate: &stDaylightDate];
//wStandardYear = stStandardDate.wYear;
//wDaylightYear = stDaylightDate.wYear;
// We build the timezone
[bytes appendBytes: &lBias length: 4];
[bytes appendBytes: standardName length: 64];
[bytes appendBytes: &stStandardDate length: 16];
[bytes appendBytes: &lStandardBias length: 4];
[bytes appendBytes: daylightName length: 64];
[bytes appendBytes: &stDaylightDate length: 16];
[bytes appendBytes: &lDaylightBias length: 4];
return [bytes activeSyncRepresentationInContext: context];
}
@end
+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 __ICALTODOACTIVESYNC_H__
#define __ICALTODOACTIVESYNC_H__
#import <NGCards/iCalToDo.h>
@class NSString;
@class WOContext;
@interface iCalToDo (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context;
@end
#endif
+192
View File
@@ -0,0 +1,192 @@
/*
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 "iCalToDo+ActiveSync.h"
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSString+misc.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalDateTime.h>
#import <NGCards/iCalTimeZone.h>
#include "NSDate+ActiveSync.h"
#include "NSString+ActiveSync.h"
@implementation iCalToDo (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{
NSMutableString *s;
id o;
int v;
s = [NSMutableString string];
// Complete
o = [self completed];
[s appendFormat: @"<Complete xmlns=\"Tasks:\">%d</Complete>", (o ? 1 : 0)];
// DateCompleted
if (o)
[s appendFormat: @"<DateCompleted xmlns=\"Tasks:\">%@</DateCompleted>", [o activeSyncRepresentationInContext: context]];
// Start date
if ((o = [self startDate]))
{
[s appendFormat: @"<StartDate xmlns=\"Tasks:\">%@</StartDate>", [o activeSyncRepresentationInContext: context]];
[s appendFormat: @"<UTCStartDate xmlns=\"Tasks:\">%@</UTCStartDate>", [o activeSyncRepresentationInContext: context]];
}
// Due date
if ((o = [self due]))
{
[s appendFormat: @"<DueDate xmlns=\"Tasks:\">%@</DueDate>", [o activeSyncRepresentationInContext: context]];
[s appendFormat: @"<UTCDueDate xmlns=\"Tasks:\">%@</UTCDueDate>", [o activeSyncRepresentationInContext: context]];
}
// Importance
o = [self priority];
if ([o isEqualToString: @"9"])
v = 0;
else if ([o isEqualToString: @"1"])
v = 2;
else
v = 1;
[s appendFormat: @"<Importance xmlns=\"Tasks:\">%d</Importance>", v];
// Reminder - FIXME
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
// Sensitivity - FIXME
[s appendFormat: @"<Sensitivity xmlns=\"Tasks:\">%d</Sensitivity>", 0];
// Subject
o = [self summary];
if ([o length])
[s appendFormat: @"<Subject xmlns=\"Tasks:\">%@</Subject>", [[self summary] activeSyncRepresentationInContext: context]];
if ((o = [self comment]))
{
o = [o activeSyncRepresentationInContext: context];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
return s;
}
- (void) takeActiveSyncValues: (NSDictionary *) theValues
inContext: (WOContext *) context
{
NSTimeZone *userTimeZone;
iCalTimeZone *tz;
id o;
NSInteger tzOffset;
userTimeZone = [[[context activeUser] userDefaults] timeZone];
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
[(iCalCalendar *) parent addTimeZone: tz];
// FIXME: merge with iCalEvent
if ((o = [theValues objectForKey: @"Subject"]))
[self setSummary: o];
// FIXME: merge with iCalEvent
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setComment: o];
if ([[theValues objectForKey: @"Complete"] intValue] &&
((o = [theValues objectForKey: @"DateCompleted"])) )
{
iCalDateTime *completed;
o = [o calendarDate];
completed = (iCalDateTime *) [self uniqueChildWithTag: @"completed"];
//tzOffset = [[o timeZone] secondsFromGMTForDate: o];
//o = [o dateByAddingYears: 0 months: 0 days: 0
// hours: 0 minutes: 0
// seconds: -tzOffset];
[completed setDate: o];
[self setStatus: @"COMPLETED"];
}
if ((o = [theValues objectForKey: @"DueDate"]))
{
iCalDateTime *due;
o = [o calendarDate];
due = (iCalDateTime *) [self uniqueChildWithTag: @"due"];
[due setTimeZone: tz];
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[due setDateTime: o];
}
// 2 == high, 1 == normal, 0 == low
if ((o = [theValues objectForKey: @"Importance"]))
{
if ([o intValue] == 2)
[self setPriority: @"1"];
else if ([o intValue] == 1)
[self setPriority: @"5"];
else
[self setPriority: @"9"];
}
if ((o = [theValues objectForKey: @"ReminderTime"]))
{
}
}
@end
+3
View File
@@ -0,0 +1,3 @@
{
requires = ( MAIN, Appointments, Contacts, Mailer );
}
+49 -1
View File
@@ -1,4 +1,52 @@
# use *:8843 for SSL
#
#
# Keep only one of those vhost definition, comment out the other one
#
#
# for https
# don't forget to add a Listen parameter for port 8843:
# Listen 8843
<VirtualHost *:8843>
ServerName YOUR.SERVER.NAME
SSLEngine on
SSLProtocol -ALL +SSLv3 +TLSv1
SSLHonorCipherOrder On
SSLCipherSuite HIGH:MEDIUM:!ADH:!aNULL:!eNULL:!NULL
SSLCertificateFile /path/to/your/cert/cert.pem
SSLCertificateChainFile /path/to/your/cert/cert-chain-file.pem
SSLCertificateKeyFile /path/to/your/key/file.key
RewriteEngine Off
ProxyRequests Off
SetEnv proxy-nokeepalive 1
ProxyPreserveHost On
ProxyPassInterpolateEnv On
ProxyPass /principals http://127.0.0.1:20000/SOGo/dav/ interpolate
ProxyPass /SOGo http://127.0.0.1:20000/SOGo interpolate
ProxyPass / http://127.0.0.1:20000/SOGo/dav/ interpolate
<Location />
Order allow,deny
Allow from all
</Location>
<Proxy http://127.0.0.1:20000>
RequestHeader set "x-webobjects-server-port" "8843"
RequestHeader set "x-webobjects-server-name" "CHANGETHIS:8843"
RequestHeader set "x-webobjects-server-url" "http://CHANGETHIS:8843"
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
AddDefaultCharset UTF-8
</Proxy>
ErrorLog /var/log/apache2/ab-error.log
CustomLog /var/log/apache2/ab-access.log combined
</VirtualHost>
# plain http
# Same here, don't forget to add a Listen parameter for port 8800:
# Listen 8800
<VirtualHost *:8800>
RewriteEngine Off
ProxyRequests Off
+14 -6
View File
@@ -2,8 +2,6 @@ Alias /SOGo.woa/WebServerResources/ \
/usr/lib/GNUstep/SOGo/WebServerResources/
Alias /SOGo/WebServerResources/ \
/usr/lib/GNUstep/SOGo/WebServerResources/
AliasMatch /SOGo/so/ControlPanel/Products/(.*)/Resources/(.*) \
/usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2
<Directory /usr/lib/GNUstep/SOGo/>
AllowOverride None
@@ -18,10 +16,6 @@ AliasMatch /SOGo/so/ControlPanel/Products/(.*)/Resources/(.*) \
</IfModule>
</Directory>
<LocationMatch "^/SOGo/so/ControlPanel/Products/.*UI/Resources/.*\.(jpg|png|gif|css|js)">
SetHandler default-handler
</LocationMatch>
## Uncomment the following to enable proxy-side authentication, you will then
## need to set the "SOGoTrustProxyAuthentication" SOGo user default to YES and
## adjust the "x-webobjects-remote-user" proxy header in the "Proxy" section
@@ -48,6 +42,14 @@ ProxyPreserveHost On
ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
# Enable to use Microsoft ActiveSync support
# Note that you MUST have many sogod workers to use ActiveSync.
# See the SOGo Installation and Configuration guide for more details.
#
#ProxyPass /Microsoft-Server-ActiveSync \
# http://127.0.0.1:20000/SOGo/Microsoft-Server-ActiveSync \
# retry=60 connectiontimeout=5 timeout=360
<Proxy http://127.0.0.1:20000/SOGo>
## adjust the following to your configuration
RequestHeader set "x-webobjects-server-port" "443"
@@ -66,3 +68,9 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
Allow from all
</Proxy>
# For Apple autoconfiguration
<IfModule rewrite_module>
RewriteEngine On
RewriteRule ^/.well-known/caldav/?$ /SOGo/dav [R=301]
</IfModule>
+4572
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 433 KiB

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 768 KiB

After

Width:  |  Height:  |  Size: 311 KiB

+1 -3
View File
@@ -1,8 +1,6 @@
/* SOGo+DAV.m - this file is part of SOGo
*
* Copyright (C) 2010 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2010-2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,5 +1,5 @@
/*
Copyright (C) 2005-2011 Inverse inc.
Copyright (C) 2005-2014 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of SOGo
+220
View File
@@ -1,3 +1,223 @@
2.2.1 (2014-03-07)
------------------
Enhancements
- updated Czech, Dutch, Finnish, and Hungarian translations
- show current folder name in prompt dialog when renaming a mail folder
Bug fixes
- fixed an issue with ActiveSync when the number of messages in the mailbox was greater than the window-size specified by the client
- fixed sogo-tool operations on Sieve script (#2617)
- fixed unsubscription when renaming an IMAP folder (#2630)
- fixed sorting of events list by calendar name (#2629)
- 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 encoding of string as CSS identifier when the string starts with a digit
- fixed auto-completion popupmenu when UID is a digit
2.2.0 (2014-02-24)
------------------
New features
- initial implementation of Microsoft ActiveSync protocol
- it's now possible to set a default reminder for calendar components
using SOGoCalendarDefaultReminder
- select multiple files to attach to a message or drag'n'drop files onto the
mail editor; will also now display progress of uploads
- new popup menu to download all attachments of a mail
- move & copy messages between different accounts
- support for the Sieve 'body' extension (mail filter based on the body content)
Enhancements
- we now automatically convert <img src=data...> into file attachments
using CIDs to prevent Outlook issues
- updated French, Finnish, Polish, German, Russian, and Spanish (Spain) translations
- XMLHttpRequest.js is now loaded conditionaly (< IE9)
- format time in attendees invitation window according to the user's locale
- improved IE11 support
- respect signature placement when forwarding a message
- respect Sieve server capabilities
- encode messages in quoted-printable when content is bigger than 72 bytes
- we now use binary encoding in memcached (#2587)
- warn user when overbooking a resource by creating an event in its calendar (#2541)
- converted JavaScript alerts to inline CSS dialogs in appointment editor
- visually identify users with no freebusy information in autocompletion widget of attendees editor (#2565)
- respect occurences of recurrent events when deleting selected events (#1950)
- improved confirmation dialog box when deleting events and tasks
- moved the DN cache to SOGoCache - avoiding sogod restarts after RDN operations
- don't use the HTML editor with Internet Explorer 7
- add message-id header to appointment notifications (#2535)
- detect URLs in popup of events
- improved display of a contact (#2350)
Bug fixes
- don't load 'background' attribute (#2437)
- fixed validation of subscribed folders (#2583)
- fixed display of folder names in messages filter editor (#2569)
- fixed contextual menu of the current calendar view (#2557)
- fixed handling of the '=' character in cards/events/tasks (#2505)
- simplify searches in the address book (#2187)
- warn user when dnd failed because of a resource conflict (#1613)
- respect the maximum number of bookings when viewing the freebusy information of a resource (#2560)
- encode HTML entities when forwarding an HTML message inline in plain text composition mode (#2411)
- encode HTML entities in JSON data (#2598)
- fixed handling of ACLs on shared calendars with multiple groups (#1854)
- fixed HTML formatting of appointment notifications for Outlook (#2233)
- replace slashes by dashes in filenames of attachments to avoid a 404 return code (#2537)
- avoid over-using LDAP connections when decomposing groups
- fixed display of a contact's birthday when not defined (#2503)
- fixed JavaScript error when switching views in calendar module (#2613)
2.1.1b (2013-12-04)
-------------------
Enhancements
- updated CKEditor to version 4.3.0 and added tab module
Bug fixes
- HTML formatting is now retained when forwarding/replying to a mail using the HTML editor
- put the text part before the HTML part when composing mail to fix a display issue with Thunderbird (#2512)
2.1.1a (2013-11-22)
-------------------
Bug fixes
- fixed Sieve filters editor (#2504)
- moved missing translation to UI/Common (#2499)
- fixed potential crasher in OpenChange
2.1.1 (2013-11-19)
------------------
New features
- creation and modification of mail labels
Enhancements
- the color picker is no longer a popup window
Bug fixes
- fixed utf8 character handling in special folder names
Special folder names can now be set as UTF8 or modified UTF7 in sogo.conf
- fixed reply-to header not being set for auxiliary IMAP accounts
- fixed handling of broken/invalid email addresses
2.1.0 (2013-11-07)
------------------
Enhancements
- improved order of user rights in calendar module (#1431)
- increased height of alarm editor when email alarms are enabled
- added SMTP AUTH support for sogo-ealarms-notify
- added support for LDAP password change against AD/Samba4
- added Apache configuration for Apple autoconfiguration (#2248)
- the init scripts now start 3 sogod processes by default instead of 1
- SOGo now also sends a plain/text parts when sending HTML mails (#2217)
- SOGo now listens on 127.0.0.1:20000 by default (instead of *:20000)
- SOGo new uses the latest WebDAV sync response type (#1275)
- updated CKEditor to version 4.2.2 and added the tables-related modules (#2410)
- improved display of vEvents in messages
Bug fixes
- fixed handling of an incomplete attachment filename (#2385)
- fixed Finnish mail reply/forward templates (#2401)
- fixed position of red line of current time (#2373)
- fixed crontab error (#2372)
- avoid using too many LDAP connections while looping through LDAP results
- don't encode HTML entities in mail subject of notification (#2402)
- fixed crash of Samba when sending an invitation (#2398)
- fixed selection of destination calendar when saving a task or an event (#2353)
- fixed "display remote images" preference for message in a popup (#2417)
- avoid crash when handling malformed or non-ASCII HTTP credentials (#2358)
- fixed crash in DAV free-busy lookups when using SQL addressbooks (#2418)
- disabled verbose logging of SMTP sessions by default
- fixed high CPU usage when there are no available child processes and added logging when such a condition occurs
- fixed memory consumption issues when doing dav lookups with huge result set
- fixed S/MIME verification issues with certain OpenSSL versions
- worked around an issue with chunked encoding of CAS replies (#2408)
- fixed OpenChange corruption issue regarding predecessors change list (#2405)
- avoid unnecessary UTF-7 conversions (#2318)
- improved RTF parser to fix vCards (#2354)
- fixed definition of the COMPLETED attribute of vTODO (#2240)
- fixed DAV:resource-id property when sharing calendars (#2399)
- fixed reload of multiple external web calendars (#2221)
- fixed display of PDF files sent from Thunderbird (#2270)
- fixed TLS support for IMAP (#2386)
- fixed creation of web calendar when added using sogo-tool (#2007)
- avoid crash when parsing HTML tags of a message (#2434)
- fixed handling of LDAP groups with no email address (#1328)
- fixed encoding of messages with non-ASCII characters (#2459)
- fixed compilation with clang 3.2 (#2235)
- truncated long fields of quick records to avoid an SQL error (#2461)
- fixed IMAP ACLs (#2433)
- removed inline JavaScript when viewing HTML messages (#2468)
2.0.7 (2013-07-19)
------------------
New features
- print gridlines of calendar in 15-minute intervals
- allow the events/tasks lists to be collapsable
Enhancements
- bubble box of events no longer overlaps the current event
- now pass the x-originating-ip using the IMAP ID extension (#2366)
- updated BrazilianPortuguese, Czech, Dutch, German, Polish and Russian translations
Bug fixes
- properly handle RFC2231 everywhere
- fixed minor XSS issues
- fixed jquery-ui not bluring the active element when clicking on a draggable
2.0.6b (2013-06-27)
------------------
Bug fixes
- properly escape the foldername to avoid XSS issues
- fixed loading of MSExchangeFreeBusySOAPResponseMap
2.0.6a (2013-06-25)
------------------
Bug fixes
- documentation fixes
- added missing file for CAS single logout
2.0.6 (2013-06-21)
------------------
Enhancements
- updated CKEditor to version 4.1.1 (#2333)
- new failed login attemps rate-limiting options. See the new
SOGoMaximumFailedLoginCount, SOGoMaximumFailedLoginInterval and
SOGoFailedLoginBlockInterval defaults
- new message submissions rate-limiting options. See the new
SOGoMaximumMessageSubmissionCount, SOGoMaximumRecipientCount,
SOGoMaximumSubmissionInterval and SOGoMessageSubmissionBlockInterval defaults
- now possible to send or not event notifications on a per-event basis
- now possible to see who created an event/task in a delegated calendar
- multi-domain support in OpenChange (implemented using a trick)
Bug fixes
- fixed decoding of the charset parameter when using single quotes (#2306)
- fixed potential crash when sending MDN from Sent folder (#2209)
- fixed handling of unicode separators (#2309)
- fixed public access when SOGoTrustProxyAuthentication is used (#2237)
- fixed access right issues with import feature (#2294)
- fixed IMAP ACL issue when SOGoForceExternalLoginWithEmail is used (#2313)
- fixed handling of CAS logoutRequest (#2346)
- fixed many major OpenChange stability issues
2.0.5a (2013-04-17)
------------------
Bug fixes
- fixed an issue when parsing user CN with leading or trailing spaces (#2287)
- fixed a crash that occured when saving contacts or tasks via Outlook
2.0.5 (2013-04-11)
------------------
+3 -3
View File
@@ -76,7 +76,7 @@
},
{
columnName = c_participants;
sqlType = "VARCHAR(1000000)";
sqlType = "TEXT";
allowsNull = YES;
},
{
@@ -91,7 +91,7 @@
},
{
columnName = c_cycleinfo;
sqlType = "VARCHAR(1000000)";
sqlType = "TEXT";
allowsNull = YES;
},
{
@@ -126,7 +126,7 @@
},
{
columnName = c_partmails;
sqlType = "VARCHAR(100000)";
sqlType = "TEXT";
allowsNull = YES;
},
{
+5 -1
View File
@@ -85,13 +85,17 @@ static NSDictionary *BSONTypes()
@implementation NSObject (BSONObjectCoding)
- (NSData *) BSONEncode
{
if (!class_conformsToProtocol([self class], @protocol(BSONObjectCoding)))
if (![self conformsToProtocol: @protocol(BSONObjectCoding)])
[NSException raise: NSInvalidArgumentException format: @"BSON encoding is only valid on objects conforming to the BSONObjectEncoding protocol."];
id <BSONObjectCoding> myself = (id <BSONObjectCoding>) self;
NSMutableDictionary *values = [[myself BSONDictionary] mutableCopy];
#if (defined(__GNU_LIBOBJC__) && (__GNU_LIBOBJC__ >= 20100911)) || defined(APPLE_RUNTIME) || defined(__GNUSTEP_RUNTIME__)
const char* className = class_getName([self class]);
#else
const char* className = [self class]->name;
#endif
[values setObject: [NSData dataWithBytes: (void *)className length: strlen(className)] forKey: CLASS_NAME_MARKER];
NSData *retval = [values BSONEncode];
[values release];
+1 -1
View File
@@ -911,7 +911,7 @@ fromProperties: (NSDictionary *) attachmentProps
//
//
//
- (void) save
- (void) save:(TALLOC_CTX *) memCtx
{
NSArray *elements, *units;
CardElement *element;
+17
View File
@@ -23,6 +23,7 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#import <NGExtensions/NSObject+Logs.h>
@@ -34,6 +35,7 @@
#import "MAPIStoreDBMessage.h"
#import "MAPIStoreTypes.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
#undef DEBUG
#include <mapistore/mapistore.h>
@@ -99,6 +101,21 @@
return objectVersion;
}
//
// FIXME: how this can happen?
//
// We might get there if for some reasons, all classes weren't able
// to tell us the message class.
//
- (int) getPidTagMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"IPM.Note" asUnicodeInMemCtx: memCtx];
[self logWithFormat: @"METHOD '%s' - unable to determine message class. Falling back to IPM.Note", __FUNCTION__];
return MAPISTORE_SUCCESS;
}
- (int) getProperties: (struct mapistore_property_data *) data
withTags: (enum MAPITAGS *) tags
andCount: (uint16_t) columnCount
+2
View File
@@ -122,6 +122,8 @@
[MAPIApp setUserContext: userContext];
moduleName = [self MAPIModuleName];
parentFolder = [[userContext rootFolders] objectForKey: moduleName];
nameInContainer = nil;
if (![parentFolder newFolderWithName: folderName
nameInContainer: &nameInContainer])
mapistoreURI = [NSString stringWithFormat: @"sogo://%@@%@/%@/",
+4 -2
View File
@@ -259,7 +259,6 @@ static Class NSNumberK;
}
}
*/
- (void) _setChangeKey: (NSData *) changeKey
forMessageEntry: (NSMutableDictionary *) messageEntry
inChangeListOnly: (BOOL) inChangeListOnly
@@ -461,7 +460,10 @@ static Class NSNumberK;
[mapping setObject: cLastModified forKey: changeNumber];
[messageEntry setObject: changeNumber forKey: @"version"];
newChangeNum = [changeNumber unsignedLongValue];
newChangeNum = [changeNumber unsignedLongLongValue];
// A GLOBCNT structure is a 6-byte global namespace counter,
// we strip the first 2 bytes. The first two bytes is the ReplicaId
changeKey = [self getReplicaKeyFromGlobCnt: newChangeNum >> 16];
[self _setChangeKey: changeKey forMessageEntry: messageEntry
inChangeListOnly: NO];
+3 -2
View File
@@ -24,6 +24,7 @@
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSURL.h>
#import <NGImap4/NSString+Imap4.h>
#import <NGExtensions/NSString+misc.h>
#import <Mailer/SOGoMailAccount.h>
#import <Mailer/SOGoMailFolder.h>
@@ -156,7 +157,7 @@ MakeDisplayFolderName (NSString *folderName)
stringData = [NSString stringWithFormat: @"%@%@",
urlBase, [currentName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
context->url = [stringData asUnicodeInMemCtx: context];
stringData = [[currentName substringFromIndex: 6] fromCSSIdentifier];
stringData = [[[currentName substringFromIndex: 6] fromCSSIdentifier] stringByDecodingImap4FolderName];
context->name = [stringData asUnicodeInMemCtx: context];
context->main_folder = false;
context->role = MAPISTORE_MAIL_ROLE;
@@ -188,7 +189,7 @@ MakeDisplayFolderName (NSString *folderName)
if ([newFolder create])
mapistoreURI = [NSString stringWithFormat: @"sogo://%@:%@@mail/%@/",
userName, userName,
[folderName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
[[folderName stringByEncodingImap4FolderName] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
else
mapistoreURI = nil;
[MAPIApp setUserContext: nil];
+4 -5
View File
@@ -1,8 +1,6 @@
/* MAPIStoreMailFolder.m - this file is part of SOGo
*
* Copyright (C) 2011-2012 Inverse inc
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2011-2013 Inverse inc
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,6 +34,7 @@
#import <NGExtensions/NSString+misc.h>
#import <NGImap4/NGImap4Connection.h>
#import <NGImap4/NGImap4Client.h>
#import <NGImap4/NSString+Imap4.h>
#import <Mailer/SOGoDraftsFolder.h>
#import <Mailer/SOGoMailAccount.h>
#import <Mailer/SOGoMailAccounts.h>
@@ -177,7 +176,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
if (folderName)
{
nameInContainer = [NSString stringWithFormat: @"folder%@",
[folderName asCSSIdentifier]];
[[folderName stringByEncodingImap4FolderName] asCSSIdentifier]];
newFolder = [SOGoMailFolderK objectWithName: nameInContainer
inContainer: sogoObject];
if ([newFolder create])
@@ -315,7 +314,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
if (![subfolderName hasPrefix: @"folder"])
abort ();
strippedName = [subfolderName substringFromIndex: 6];
strippedName = [[subfolderName substringFromIndex: 6] stringByDecodingImap4FolderName];
[representation appendFormat: @"/%@", strippedName];
return representation;
+9 -1
View File
@@ -693,7 +693,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
ngAddress = [[NGMailAddressParser mailAddressParserWithString: fullMail]
parse];
if ([ngAddress isKindOfClass: [NGMailAddress class]])
cn = [ngAddress displayName];
{
cn = [ngAddress displayName];
// If we don't have a displayName, we use the email address instead. This
// avoid bug #2119 - where Outlook won't display anything in the "From" field,
// nor in the recipient field if we reply to the email.
if (![cn length])
cn = [ngAddress address];
}
else
cn = @"";
+16
View File
@@ -543,6 +543,7 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
NSDictionary *recipients;
NSUInteger type, bccLimit;
SOGoUser *activeUser;
NSNumber *priority;
activeUser
= [SOGoUser
@@ -596,6 +597,21 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
[headers addObject: [date rfc822DateString] forKey: @"date"];
}
[headers addObject: @"1.0" forKey: @"MIME-Version"];
priority = [mailProperties objectForKey: MAPIPropertyKey (PidTagImportance)];
if ([priority intValue] == 2)
{
[headers addObject: @"1 (Highest)" forKey: @"X-Priority"];
}
else if ([priority intValue] == 1)
{
[headers removeAllObjectsForKey: @"X-Priority"];
}
else
{
[headers addObject: @"5 (Lowest)" forKey: @"X-Priority"];
}
}
static NSArray *
+3
View File
@@ -284,6 +284,9 @@ static Class NSExceptionK, MAPIStoreFolderK;
return MAPISTORE_SUCCESS;
}
//
// The GlobCnt is 6 bytes long.
//
- (NSData *) getReplicaKeyFromGlobCnt: (uint64_t) objectCnt
{
struct mapistore_connection_info *connInfo;
+1 -1
View File
@@ -357,7 +357,7 @@
return rc;
}
- (void) save
- (void) save:(TALLOC_CTX *) memCtx
{
iCalCalendar *vCalendar;
iCalToDo *vToDo;
+4 -1
View File
@@ -148,6 +148,7 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
- (struct XID *) asXIDInMemCtx: (void *) memCtx
{
struct XID *xid;
uint8_t *bytes;
NSUInteger max;
max = [self length];
@@ -158,7 +159,9 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
[self _extractGUID: &xid->GUID];
xid->Size = max - 16;
xid->Data = talloc_memdup (xid, [self bytes] + 16, xid->Size);
bytes = (uint8_t *) [self bytes];
xid->Data = talloc_memdup (xid, (bytes+16), xid->Size);
}
else
{
+17 -1
View File
@@ -694,10 +694,18 @@ const unsigned short ansicpg874[256] = {
}
else if (*(_bytes+1) == '*')
{
while (*_bytes != '}')
int cc = 1;
do
{
if (*_bytes == '{')
cc++;
if (*_bytes == '}')
cc--;
ADVANCE;
}
while (cc != 0);
continue;
}
@@ -777,6 +785,10 @@ const unsigned short ansicpg874[256] = {
[_html appendBytes: v length: strlen(v)];
free(v);
}
else if ([s hasPrefix: @"fcs"])
{
// ignore
}
else if ([s hasPrefix: @"fs"])
{
// ignore
@@ -789,6 +801,10 @@ const unsigned short ansicpg874[256] = {
{
// ignore
}
else if ([s hasPrefix: @"fromtext"])
{
// ignore
}
else if ([s hasPrefix: @"f"] && [s length] > 1)
{
RTFFontInfo *fontInfo;
+1 -1
View File
@@ -27,7 +27,7 @@
#import "EOQualifier+GCS.h"
#if __GNU_LIBOBJC__ >= 20100911
#if (defined(__GNU_LIBOBJC__) && (__GNU_LIBOBJC__ >= 20100911)) || defined(APPLE_RUNTIME) || defined(__GNUSTEP_RUNTIME__)
# define sel_eq(__A__,__B__) sel_isEqual(__A__,__B__)
#endif
+1 -1
View File
@@ -44,7 +44,7 @@
#import "EOQualifier+GCS.h"
#import "GCSStringFormatter.h"
#if __GNU_LIBOBJC__ >= 20100911
#if (defined(__GNU_LIBOBJC__) && (__GNU_LIBOBJC__ >= 20100911)) || defined(APPLE_RUNTIME) || defined(__GNUSTEP_RUNTIME__)
# define sel_eq(__A__,__B__) sel_isEqual(__A__,__B__)
#endif
+14 -2
View File
@@ -35,6 +35,8 @@
@"http://www.ietf.org/internet-drafts/draft-dawson-vcard-xml-dtd-03.txt"
#endif
static NSArray *privilegedTagNames = nil;
@implementation NGCardsSaxHandler
- (id) init
@@ -42,6 +44,12 @@
if ((self = [super init]))
topGroupClass = nil;
if (!privilegedTagNames)
{
privilegedTagNames = [NSArray arrayWithObjects: @"ADR", @"N", @"RRULE", nil];
RETAIN(privilegedTagNames);
}
return self;
}
@@ -210,8 +218,12 @@
length: contentLength];
free (content);
content = NULL;
// NSLog (@"content: '%@'", s);
contentValues = [s vCardSubvalues];
//NSLog(@"content: '%@'", s);
if ([privilegedTagNames containsObject: [currentElement tag]])
contentValues = [s vCardSubvalues];
else
contentValues = [NSMutableDictionary dictionaryWithObject: [NSMutableArray arrayWithObject: [s asCardAttributeValues]]
forKey: @""];
}
else
contentValues = nil;
+34 -13
View File
@@ -155,20 +155,41 @@
- (NSString *) escapedForCards
{
NSString *string;
NSMutableString *string;
unsigned int len, i;
unichar c;
string = [self stringByReplacingString: @"\\"
withString: @"\\\\"];
string = [string stringByReplacingString: @","
withString: @"\\,"];
// string = [string stringByReplacingString: @":"
// withString: @"\\:"];
string = [string stringByReplacingString: @";"
withString: @"\\;"];
string = [string stringByReplacingString: @"\n"
withString: @"\\n"];
string = [string stringByReplacingString: @"\r"
withString: @"\\r"];
len = [self length];
string = [NSMutableString stringWithCapacity: len * 1.5];
for (i = 0; i < len; i++)
{
c = [self characterAtIndex: i];
switch (c)
{
case '\\':
[string appendString: @"\\\\"];
break;
case ',':
[string appendString: @"\\,"];
break;
//case ':':
// [string appendString: @"\\:"];
//break;
case ';':
[string appendString: @"\\;"];
break;
case'\n':
[string appendString: @"\\n"];
break;
case'\r':
[string appendString: @"\\r"];
break;
default:
[string appendFormat: @"%C", c];
}
}
return string;
}
+1 -1
View File
@@ -72,7 +72,7 @@
- (void) setCompleted: (NSCalendarDate *) newCompletedDate
{
[(iCalDateTime *) [self uniqueChildWithTag: @"completed"]
setDate: newCompletedDate];
setDateTime: newCompletedDate];
if (newCompletedDate)
[self setStatus: @"COMPLETED"];
else
@@ -89,6 +89,16 @@ def main():
except Exception as e:
print "Error during sqlCleanup, continuing: %s" % str(e)
def getsep(client):
seq = None
(code, data) = client.list("", "")
if code == "OK" and data is not None:
# yes this is ugly but it works on cyrus and dovecot.
# (\\Noinferiors \\HasNoChildren) "/" INBOX
m = re.search(".*\s+[\"\']?(.)[\"\']?\s+[\"\']?.*[\"\']?$", data[0])
sep = m.group(1)
return sep
def extractmb(si):
inparen = False
inquote = False
@@ -120,13 +130,13 @@ def extractmb(si):
return parts[-1]
def cleanupmb(mb, client):
(code, data) = client.list("%s/" % mb, "%")
def cleanupmb(mb, sep, client):
(code, data) = client.list("%s%s" % (mb, sep), "%")
if code == "OK":
for si in data:
if si is not None:
submb = extractmb(si)
cleanupmb(submb, client)
cleanupmb(submb, sep, client)
else:
raise Exception, "Failure while cleaning up '%s'" % mb
client.unsubscribe(mb)
@@ -145,13 +155,20 @@ def imapCleanup(imaphost, imapport, username, userpass):
print "Logged in as '%s'" % username
for foldername in ("Sync Issues", "Junk E-mail"):
sep = getsep(client)
if not sep:
client.logout()
return
for foldername in ("Sync Issues", "Junk E-mail",
"INBOX%sSync Issues" % sep, "INBOX%sJunk E-mail" % sep,
"Probl&AOg-mes de synchronisation"):
(code, data) = client.list(foldername, "%")
if code == "OK":
for si in data:
if si is not None:
mb = extractmb(si)
cleanupmb(mb, client)
cleanupmb(mb, sep, client)
client.logout()
def mapistoreCleanup(mapistorefolder, username):
+1 -1
View File
@@ -4,7 +4,7 @@ set -o pipefail
#set -x
PROGNAME="$(basename $0)"
BACKUP_DIR=/home/sogo/backups
BACKUP_DIR=~sogo/backups
SOGO_TOOL=/usr/sbin/sogo-tool
DAYS_TO_KEEP="30"
+2 -2
View File
@@ -1,5 +1,5 @@
# The amount of processes that should be spawned (Default: 1)
# PREFORK=1
# The amount of processes that should be spawned (Default: 3)
# PREFORK=3
# The name of the account under which SOGo will be running (Default: sogo)
# USER=sogo
+1 -1
View File
@@ -34,7 +34,7 @@ DAEMON=/usr/sbin/sogod
DESC="SOGo"
USER=$NAME
PREFORK=1
PREFORK=3
PIDFILE=/var/run/$NAME/$NAME.pid
LOGFILE=/var/log/$NAME/$NAME.log
+1 -1
View File
@@ -37,7 +37,7 @@ DAEMON=/usr/sbin/sogod
DESC="SOGo"
USER=$NAME
PREFORK=1
PREFORK=3
PIDFILE=/var/run/$NAME/$NAME.pid
LOGFILE=/var/log/$NAME/$NAME.log
+32 -4
View File
@@ -33,8 +33,10 @@
//SOGoMailSpoolPath = /var/spool/sogo;
//NGImap4ConnectionStringSeparator = "/";
/* Notifications */
//SOGoAppointmentSendEMailNotifications = NO;
//SOGoACLsSendEMailNotifications = NO;
//SOGoFoldersSendEMailNotifications = NO;
/* Authentication */
//SOGoPasswordChangeEnabled = YES;
@@ -44,8 +46,9 @@
// {
// type = ldap;
// CNFieldName = cn;
// IDFieldName = uid;
// UIDFieldName = uid;
// IDFieldName = uid; // first field of the DN for direct binds
// bindFields = (uid, mail); // array of fields to use for indirect binds
// baseDN = "ou=users,dc=acme,dc=com";
// bindDN = "uid=sogo,ou=users,dc=acme,dc=com";
// bindPassword = qwerty;
@@ -57,13 +60,33 @@
// }
//);
/* LDAP AD/Samba4 example */
//SOGoUserSources = (
// {
// type = ldap;
// CNFieldName = cn;
// UIDFieldName = sAMAccountName;
// baseDN = "CN=users,dc=domain,dc=tld";
// bindDN = "CN=sogo,CN=users,DC=domain,DC=tld";
// bindFields = (sAMAccountName, mail);
// bindPassword = password;
// canAuthenticate = YES;
// displayName = "Public";
// hostname = ldap://127.0.0.1:389;
// filter = "mail = '*'";
// id = directory;
// isAddressBook = YES;
// }
//);
/* SQL authentication example */
/* These database columns MUST be present in the view/table:
* c_uid - will be used for authentication - it's the username or username@domain.tld)
* c_name - which can be identical to c_uid - will be used to uniquely identify entries
* c_password - password of the user, plain-text, md5 or sha encoded for now
* c_cn - the user's common name - such as "John Doe"
* mail - the user's mail address
* mail - the user's mail address
* See the installation guide for more details
*/
//SOGoUserSources =
@@ -83,6 +106,8 @@
//SOGoVacationEnabled = YES;
//SOGoForwardEnabled = YES;
//SOGoSieveScriptsEnabled = YES;
//SOGoMailAuxiliaryUserAccountsEnabled = YES;
//SOGoTrustProxyAuthentication = NO;
/* General */
//SOGoLanguage = English;
@@ -91,13 +116,16 @@
// PublicDAndTViewer,
// ConfidentialDAndTViewer
//);
//SOGoSuperUsernames = (sogo1, sogo2); //This is an array - keep the parens!
//SOGoSuperUsernames = (sogo1, sogo2); // This is an array - keep the parens!
//SxVMemLimit = 384;
//WOPidFile = "/var/run/sogo/sogo.pid";
//SOGoMemcachedHost = "/var/run/memcached.sock";
/* Debug */
//SOGoDebugRequests = YES;
//SoDebugBaseURL = YES;
//ImapDebugEnabled = YES;
//LDAPDebugEnabled = YES;
//SOGoDebugRequests = YES;
//PGDebugEnabled = YES;
//MySQL4DebugEnabled = YES;
//SOGoUIxDebugEnabled = YES;
+3 -1
View File
@@ -10,10 +10,12 @@
#* * * * * sogo /usr/sbin/sogo-tool expire-sessions 60
# Email alarms - runs every minutes
# If you need to use SMTP AUTH for outgoing mails, specify credentials to use
# with '-p /path/to/credentialsFile' (same format as the sieve credentials)
#* * * * * sogo /usr/sbin/sogo-ealarms-notify
# Daily backups
# - writes to /home/sogo/backups/ by default
# - writes to ~sogo/backups/ by default
# - will keep 31 days worth of backups by default
# - runs once a day by default, but can run more frequently
# - make sure to set the path to sogo-backup.sh correctly
+2 -1
View File
@@ -1,6 +1,7 @@
#!/bin/sh
# SOGOSPOOL must match the value of the configuration parameter SOGoMailSpoolPath
SOGOSPOOL=/var/spool/sogo
/usr/sbin/tmpwatch 24 "$SOGOSPOOL"
find "$SOGOSPOOL" -depth -mindepth 1 -type d -empty -exec /bin/rmdir {} \; 2> /dev/null
find "$SOGOSPOOL" -mindepth 1 -type d -user sogo -empty -delete > /dev/null
+8 -8
View File
@@ -28,22 +28,22 @@ $plugins
= array(
"sogo-connector@inverse.ca"
=> array( "application" => "thunderbird",
"version" => "17.0.3",
"filename" => "sogo-connector-17.0.3.xpi" ),
"version" => "24.0.4",
"filename" => "sogo-connector-24.0.4.xpi" ),
"sogo-integrator@inverse.ca"
=> array( "application" => "thunderbird",
"version" => "17.0.3",
"filename" => "sogo-integrator-17.0.3.xpi" ),
"version" => "24.0.4",
"filename" => "sogo-integrator-24.0.4.xpi" ),
"{e2fda1a4-762b-4020-b5ad-a41df1933103}"
=> array( "application" => "thunderbird",
"version" => "1.9",
"filename" => "lightning-1.9.xpi" )
"version" => "2.6.4",
"filename" => "lightning-2.6.4.xpi" )
);
$applications
= array( "thunderbird" => "<em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
<em:minVersion>17.0</em:minVersion>
<em:maxVersion>17.*</em:maxVersion>" );
<em:minVersion>24.0</em:minVersion>
<em:maxVersion>24.*</em:maxVersion>" );
$pluginname = $_GET["plugin"];
$plugin =& $plugins[$pluginname];
+1 -1
View File
@@ -50,7 +50,7 @@ Appointments_OBJC_FILES = \
Appointments_RESOURCE_FILES += \
product.plist \
\
MSExchangeFreeBusySOAPResponseMap.plist \
MSExchangeFreeBusySOAPRequest.wo
Appointments_LANGUAGES = Arabic BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
@@ -27,13 +27,13 @@ vtodo_class2 = "(Vertrauliche Aufgabe)";
/* Invitation */
"Event Invitation: \"%{Summary}\"" = "Termineinladung: \"%{Summary}\"";
"(sent by %{SentBy}) " = "(gesendet von %{SentBy}) ";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText} Hat Sie eingeladen zu %{Summary}.\n\nBeginn: %{StartDate}\nEnde: %{EndDate}\nBeschreibung: %{Description}";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText} Hat Sie eingeladen zu \"%{Summary}\".\n\nBeginn: %{StartDate}\nEnde: %{EndDate}\nBeschreibung: %{Description}";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText} hat Sie eingeladen zu \"%{Summary}\".\n\nBeginn: %{StartDate} um %{StartTime}\nEnde: %{EndDate} um %{EndTime}\nBeschreibung: %{Description}";
/* Deletion */
"Event Cancelled: \"%{Summary}\"" = "Termin abgesagt: \"%{Summary}\"";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
= "%{Organizer} %{SentByText} hat den folgenden Termin abgesagt: %{Summary}.\n\nBeginn: %{StartDate}\nEnde: %{EndDate}\nBeschreibung: %{Description}";
= "%{Organizer} %{SentByText} hat den folgenden Termin abgesagt: \"%{Summary}\".\n\nBeginn: %{StartDate}\nEnde: %{EndDate}\nBeschreibung: %{Description}";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
= "%{Organizer} %{SentByText} hat diesen Termin abgesagt: \"%{Summary}\".\n\nBeginn: %{StartDate} um %{StartTime}\nEnde: %{EndDate} um %{EndTime}\nBeschreibung: %{Description}";
@@ -45,7 +45,7 @@ vtodo_class2 = "(Vertrauliche Aufgabe)";
"The following parameters have changed in the \"%{Summary}\" meeting:"
= "Folgendes wurde am Termin \"%{Summary}\" geändert:";
"Please accept or decline those changes."
= "Bitte akzeptieren Sie diese Änderung oder lehnen Sie ab.";
= "Bitte akzeptieren Sie diese Änderung oder lehnen Sie diese ab.";
/* Reply */
"Accepted invitation: \"%{Summary}\"" = "Einladung zugestimmt: \"%{Summary}\"";
+11 -4
View File
@@ -1,8 +1,6 @@
/* MSExchangeFreeBusy.m - this file is part of SOGo
*
* Copyright (C) 2012 Inverse inc.
*
* Author: Francis Lachapelle <flachapelle@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
@@ -20,6 +18,7 @@
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSBundle.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
@@ -97,8 +96,10 @@ size_t curl_body_function_freebusy(void *ptr, size_t size, size_t nmemb, void *i
MSExchangeFreeBusySOAPRequest *soapRequest;
MSExchangeFreeBusyResponse *freeBusyResponse;
NSString *rawRequest, *url, *body, *hostname, *httpauth, *authname, *password;
NSString *mapFile;
NSArray *infos = nil;
NSDictionary *root;
NSBundle *bundle;
CURL *curl;
struct curl_slist *headerlist=NULL;
@@ -161,7 +162,13 @@ size_t curl_body_function_freebusy(void *ptr, size_t size, size_t nmemb, void *i
}
if (sax == nil && parser != nil)
{
sax = [[SaxObjectDecoder alloc] initWithMappingAtPath:@"./MSExchangeFreeBusySOAPResponseMap.plist"];
bundle = [NSBundle bundleForClass: [self class]];
mapFile = [bundle pathForResource: @"MSExchangeFreeBusySOAPResponseMap" ofType: @"plist"];
if (![mapFile length])
{
[self errorWithFormat: @"mapFile not found (MSExchangeFreeBusySOAPResponseMap.plist)"];
}
sax = [[SaxObjectDecoder alloc] initWithMappingAtPath: mapFile];
[parser setContentHandler:sax];
//[parser setErrorHandler:sax];
}
@@ -8,23 +8,15 @@ vtodo_class1 = "(Privat oppgave)";
vtodo_class2 = "(Konfidensiell oppgave)";
/* Receipts */
"Title:" = "Tittel:";
"Start:" = "Start:";
"End:" = "Slutt:";
"Receipt: users invited to a meeting" = "Kvittering: brukere invitert til et møte";
"You have invited the following attendees(s):" = "Du har invitert følende deltagere:";
"... to attend the following event:" = "... til å delta i følgende hendelse:";
"Receipt: invitation updated" = "Kvittering: invitasjon oppdatert";
"The following attendees(s):" = "Følgende deltager(e):";
"... have been notified of the changes to the following event:" = "... har blitt informert om endringene i følgende hendelse:";
"Receipt: attendees removed from an event" = "Kvittering: deltagere fjernet fra en hendelse";
"You have removed the following attendees(s):" = "Du har tatt bort følgende deltagere:";
"... from the following event:" = "... fra følgende hendelse:";
"The event \"%{Summary}\" was created" = "Hendelsen \"%{Summary}\" ble opprettet";
"The event \"%{Summary}\" was deleted" = "Hendelsen \"%{Summary}\" ble slettet";
"The event \"%{Summary}\" was updated" = "Hendelsen \"%{Summary}\" ble oppdatert";
"The following attendees(s) were notified:" = "Følgende deltaker(e) ble varslet:";
"The following attendees(s) were added:" = "Følgende deltaker(e) ble lagt til:";
"The following attendees(s) were removed:" = "Følgende deltaker(e) ble fjernet:";
/* IMIP messages */
"calendar_label" = "Kalender:";
"startDate_label" = "Start:";
"endDate_label" = "Slutt:";
"due_label" = "Forfallsdato:";
@@ -35,27 +27,31 @@ vtodo_class2 = "(Konfidensiell oppgave)";
/* Invitation */
"Event Invitation: \"%{Summary}\"" = "Hendelseinvitasjon: \"%{Summary}\"";
"(sent by %{SentBy}) " = "(sendt av %{SentBy})";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText} har invitert deg til %{Summary}.\n\nStart: %{StartDate} %{StartTime}\nSlutt: %{EndDate} %{EndTime}\nBeskrivelse: %{Description}";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText} har invitert deg til %{Summary}.⏎ ⏎ Start: %{StartDate}⏎ Slutt: %{EndDate}⏎ Beskrivelse: %{Description}";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText} har invitert deg til %{Summary}.\n\nStart: %{StartDate} klokken %{StartTime}\nSlutt: %{EndDate} klokken %{EndTime}\nBeskrivelse: %{Description}";
/* Deletion */
"Event Cancelled: \"%{Summary}\"" = "Hendelse avlyst: \"%{Summary}\"";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
= "";
= "%{Organizer} %{SentByText} har avlyst hendelsen: %{Summary}.⏎ ⏎ Start: %{StartDate}⏎ Slutt: %{EndDate}⏎ Beskrivelse: %{Description}";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
= "%{Organizer} %{SentByText} har avlyst : %{Summary}.\n\nStart: %{StartDate} %{StartTime}\nEnd: %{EndDate} %{EndTime}\nBeskrivelse: %{Description}";
= "%{Organizer} %{SentByText} har avlyst : %{Summary}.\n\nStart: %{StartDate} klokken %{StartTime}\nEnd: %{EndDate} klokken %{EndTime}\nBeskrivelse: %{Description}";
/* Update */
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
= "";
= "Avtalen \"%{Summary}\", %{OldStartDate} er endret";
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
= "Avtalen \"%{Summary}\" for %{OldStartDate} klokken %{OldStartTime} er endret.";
"The following parameters have changed in the \"%{Summary}\" meeting:"
= "Følgende parametre er endret for \"%{Summary}\" møtet:";
= "Følgende parametre er endret for \"%{Summary}\"-møtet:";
"Please accept or decline those changes."
= "Vennligst godta eller avvis endringene.";
/* Reply */
"Accepted invitation: \"%{Summary}\"" = "Aksepterte invitasjonen: \"%{Summary}\"";
"Declined invitation: \"%{Summary}\"" = "Avviste invitasjonen: \"%{Summary}\"";
"Delegated invitation: \"%{Summary}\"" = "Delegerte invitasjonen: \"%{Summary}\"";
"Not yet decided on invitation: \"%{Summary}\"" = "Fortsatt ikke svart på invitasjonen: \"%{Summary}";
"%{Attendee} %{SentByText}has accepted your event invitation."
= "%{Attendee} %{SentByText} har godtatt invitasjonen.";
"%{Attendee} %{SentByText}has declined your event invitation."
@@ -63,7 +59,8 @@ vtodo_class2 = "(Konfidensiell oppgave)";
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
= "%{Attendee} %{SentByText} har delegert invitasjonen til %{Delegate}.";
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
= "%{Attendee} %{SentByText} had ends ikke var på invitasjonen.";
= "%{Attendee} %{SentByText} har ikke svart på invitasjonen.";
/* Resources */
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\"." = "Maksimalt antall samtidige bookinger (%{NumberOfSimultaneousBookings}) er nåd for ressurs \"%{Cn} %{SystemEmail}\".";
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "Kan ikke få tilgang til ressurs: \"%{Cn} %{SystemEmail}\"";
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "Maksimum antall samtidige reservasjoner (%{NumberOfSimultaneousBookings}) er nådd for ressursen \"%{Cn} %{SystemEmail}\". Kolliderende hendelse er \"%{EventTitle}\", som starter %{StartDate}.";
+91 -18
View File
@@ -573,17 +573,27 @@ static iCalEvent *iCalEventK = nil;
}
grantedCount = [grantedClasses count];
if (grantedCount == 3)
filter = @"";
{
// User have access to all three classifications
filter = @"";
}
else if (grantedCount == 2)
filter
= [NSString stringWithFormat: @"c_classification != %@",
[deniedClasses objectAtIndex: 0]];
{
// User has access to all but one of the classifications
filter = [NSString stringWithFormat: @"c_classification != %@",
[deniedClasses objectAtIndex: 0]];
}
else if (grantedCount == 1)
filter
= [NSString stringWithFormat: @"c_classification = %@",
[grantedClasses objectAtIndex: 0]];
{
// User has access to only one classification
filter = [NSString stringWithFormat: @"c_classification = %@",
[grantedClasses objectAtIndex: 0]];
}
else
filter = nil;
{
// User has access to no classification
filter = nil;
}
return filter;
}
@@ -676,7 +686,6 @@ static iCalEvent *iCalEventK = nil;
qualifier = nil;
/* fetch non-recurrent apts first */
records = [folder fetchFields: fields matchingQualifier: qualifier];
}
else
@@ -871,7 +880,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
{
NSCalendarDate *recurrenceId;
NSMutableDictionary *newRecord;
NSDictionary *oldRecord;
NGCalendarDateRange *newRecordRange;
NSComparisonResult compare;
int recordIndex, secondsOffsetFromGMT;
@@ -2236,10 +2244,39 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
return @"";
}
/*
RFC5842 states:
3.1. DAV:resource-id Property
The DAV:resource-id property is a REQUIRED property that enables
clients to determine whether two bindings are to the same resource.
The value of DAV:resource-id is a URI, and may use any registered URI
scheme that guarantees the uniqueness of the value across all
resources for all time (e.g., the urn:uuid: URN namespace defined in
[RFC4122] or the opaquelocktoken: URI scheme defined in [RFC4918]).
<!ELEMENT resource-id (href)>
...
so we must STRIP any username prefix, to make the ID global.
*/
- (NSString *) davResourceId
{
NSString *name, *prefix;
prefix = [NSString stringWithFormat: @"%@_", [self ownerInContext: context]];
name = [self nameInContainer];
if ([name hasPrefix: prefix])
{
name = [name substringFromIndex: [prefix length]];
}
return [NSString stringWithFormat: @"urn:uuid:%@:calendars:%@",
[self ownerInContext: context], [self nameInContainer]];
[self ownerInContext: context], name];
}
- (NSArray *) davScheduleCalendarTransparency
@@ -2504,7 +2541,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
unsigned int permStrIndex;
[super initializeQuickTablesAclsInContext: localContext];
/* We assume "userIsOwner" will be set after calling the super method. */
/* We assume "userCanAccessAllObjects" will be set after calling the super method. */
if (!userCanAccessAllObjects)
{
login = [[localContext activeUser] login];
@@ -2901,9 +2938,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
NSMutableString *content;
NSString *uid;
uid = [self globallyUniqueObjectId];
[event setUid: uid];
// We first look if there's an event with the same UID in our calendar. If not,
// let's reuse what is in the event, otherwise generate a new GUID and use it.
uid = [event uid];
@@ -3097,6 +3131,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
{
NSMutableArray *aclsForUser;
NSArray *superAcls;
static NSArray *rolesClassifications = nil;
superAcls = [super aclsForUser: uid forObjectAtPath: objectPathArray];
if ([uid isEqualToString: [self defaultUserID]])
@@ -3111,14 +3146,52 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
[aclsForUser addObject: SoRole_Authenticated];
}
else
aclsForUser = (NSMutableArray *) superAcls;
{
aclsForUser = [NSMutableArray array];
if (!rolesClassifications)
{
rolesClassifications =
[NSArray arrayWithObjects:
[NSArray arrayWithObjects:
SOGoCalendarRole_PublicModifier,
SOGoCalendarRole_PublicResponder,
SOGoCalendarRole_PublicViewer,
SOGoCalendarRole_PublicDAndTViewer,
nil],
[NSArray arrayWithObjects:
SOGoCalendarRole_ConfidentialModifier,
SOGoCalendarRole_ConfidentialResponder,
SOGoCalendarRole_ConfidentialViewer,
SOGoCalendarRole_ConfidentialDAndTViewer,
nil],
[NSArray arrayWithObjects:
SOGoCalendarRole_PrivateModifier,
SOGoCalendarRole_PrivateResponder,
SOGoCalendarRole_PrivateViewer,
SOGoCalendarRole_PrivateDAndTViewer,
nil],
[NSArray arrayWithObject: SOGoRole_ObjectCreator],
[NSArray arrayWithObject: SOGoRole_ObjectEraser],
nil];
[rolesClassifications retain];
}
// When a user is a member of many groups for which there are access rights, multiple access rights
// can be returned for each classification. In this case, we only keep the highest access right.
int i, count = [rolesClassifications count];
NSString *role;
for (i = 0; i < count; i++)
{
role = [[rolesClassifications objectAtIndex: i] firstObjectCommonWithArray: superAcls];
if (role)
[aclsForUser addObject: role];
}
}
return aclsForUser;
}
/* caldav-proxy */
- (SOGoAppointmentProxyPermission)
proxyPermissionForUserWithLogin: (NSString *) login
- (SOGoAppointmentProxyPermission) proxyPermissionForUserWithLogin: (NSString *) login
{
SOGoAppointmentProxyPermission permission;
NSArray *roles;
@@ -1,8 +1,6 @@
/* SOGoAppointmentFolders.h - this file is part of SOGo
*
* Copyright (C) 2007 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2007-2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,8 +33,8 @@
NSMutableArray *folderObjectKeys;
}
- (SOGoWebAppointmentFolder *) newWebCalendarWithName: (NSString *) folderDisplayName
atURL: (NSString *) url;
- (SOGoWebAppointmentFolder *) newWebCalendarWithURL: (NSString *) urlString
nameInContainer: (NSString *) name;
- (void) reloadWebCalendars: (BOOL) forceReload;
+41 -12
View File
@@ -1,9 +1,7 @@
/* SOGoAppointmentFolders.m - this file is part of SOGo
*
* Copyright (C) 2007-2010 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2007-2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -133,18 +131,29 @@ static SoSecurityManager *sm = nil;
return [self labelForKey: @"Personal Calendar" inContext: context];
}
- (SOGoWebAppointmentFolder *)
newWebCalendarWithName: (NSString *) folderDisplayName
atURL: (NSString *) urlString
- (SOGoWebAppointmentFolder *) newWebCalendarWithURL: (NSString *) urlString
nameInContainer: (NSString *) name
{
NSException *error;
SOGoAppointmentFolder *aptFolder;
NSString *folderDisplayName, *tmp;
SOGoWebAppointmentFolder *webCalendar;
NSString *name;
SOGoAppointmentFolder *aptFolder;
NSException *error;
NSURL *url;
folderDisplayName = [self labelForKey: @"Web Calendar"];
webCalendar = nil;
tmp = [urlString lastPathComponent];
if (tmp)
{
if ([[tmp pathExtension] caseInsensitiveCompare: @"ics"] == NSOrderedSame)
folderDisplayName = [tmp substringToIndex: [tmp length] - 4];
else
folderDisplayName = tmp;
}
if ([folderDisplayName length] > 0 && [urlString length] > 0)
{
url = [NSURL URLWithString: urlString];
@@ -154,6 +163,10 @@ static SoSecurityManager *sm = nil;
nameInContainer: &name];
if (!error)
{
// We make sure we initialized our subfolfers list. This can happen
// when auto-creating Web calendars during the logon process.
[self subFolders];
aptFolder = [subFolders objectForKey: name];
[aptFolder setFolderPropertyValue: urlString
inCategory: @"WebCalendars"];
@@ -561,9 +574,25 @@ static SoSecurityManager *sm = nil;
folder = [SOGoWebAppointmentFolder
folderWithSubscriptionReference: ref
inContainer: self];
if (folder
&& (forceReload || [folder reloadOnLogin]))
[folder loadWebCalendar];
if (forceReload || [folder reloadOnLogin] || !folder)
{
if (!folder)
{
NSString *s, *urlString;
urlString = [[calSettings objectForKey: @"WebCalendars"] objectForKey: ref];
s = [ref lastPathComponent];
// See bug #2007. Some admins want to subscribe users to Web calendars
// using sogo-tool. If they do that, the db tables won't be created
// so we must detect that here and create them upon login.
folder = [self newWebCalendarWithURL: urlString
nameInContainer: s];
}
[folder loadWebCalendar];
}
}
}
+91 -57
View File
@@ -431,18 +431,38 @@
forEvent: (iCalEvent *) theEvent
{
iCalPerson *currentAttendee;
NSMutableArray *attendees;
NSEnumerator *enumerator;
NSString *currentUID;
SOGoUser *user;
SOGoUser *user, *currentUser, *ownerUser;
// Build a list of the attendees uids
attendees = [NSMutableArray arrayWithCapacity: [theAttendees count]];
enumerator = [theAttendees objectEnumerator];
while ((currentAttendee = [enumerator nextObject]))
{
currentUID = [currentAttendee uid];
if (currentUID)
{
{
[attendees addObject: currentUID];
}
}
// If the active user is not the owner of the calendar, check possible conflict when
// the owner is a resource
currentUser = [context activeUser];
if (!activeUserIsOwner && ![currentUser isSuperUser])
{
ownerUser = [SOGoUser userWithLogin: owner];
if ([ownerUser isResource])
{
[attendees addObject: owner];
}
}
enumerator = [attendees objectEnumerator];
while ((currentUID = [enumerator nextObject]))
{
user = [SOGoUser userWithLogin: currentUID];
if ([user isResource])
@@ -461,8 +481,7 @@
start = [[theEvent startDate] dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: 1];
end = [[theEvent endDate] dateByAddingYears: ([theEvent isRecurrent] ? 1 : 0) months: 0 days: 0 hours: 0 minutes: 0 seconds: -1];
folder = [[SOGoUser userWithLogin: currentUID]
personalCalendarFolderInContext: context];
folder = [user personalCalendarFolderInContext: context];
// Deny access to the resource if the ACLs don't allow the user
if (![folder aclSQLListingFilter])
@@ -526,52 +545,64 @@
[fbInfo removeObjectAtIndex: i];
}
}
if ([fbInfo count])
{
// If we always force the auto-accept if numberOfSimultaneousBookings == 0 (ie., no limit
// is imposed) or if numberOfSimultaneousBookings is greater than the number of
// overlapping events
if ([user numberOfSimultaneousBookings] == 0 ||
[user numberOfSimultaneousBookings] > [fbInfo count])
// Find the attendee associated to the current UID
for (i = 0; i < [theAttendees count]; i++)
{
currentAttendee = [theAttendees objectAtIndex: i];
if ([[currentAttendee uid] isEqualToString: currentUID])
break;
else
currentAttendee = nil;
}
if (currentAttendee)
{
if ([fbInfo count])
{
// If we always force the auto-accept if numberOfSimultaneousBookings == 0 (ie., no limit
// is imposed) or if numberOfSimultaneousBookings is greater than the number of
// overlapping events
if ([user numberOfSimultaneousBookings] == 0 ||
[user numberOfSimultaneousBookings] > [fbInfo count])
{
[[currentAttendee attributes] removeObjectForKey: @"RSVP"];
[currentAttendee setParticipationStatus: iCalPersonPartStatAccepted];
}
else
{
iCalCalendar *calendar;
NSDictionary *values;
NSString *reason;
iCalEvent *event;
calendar = [iCalCalendar parseSingleFromSource: [[fbInfo objectAtIndex: 0] objectForKey: @"c_content"]];
event = [[calendar events] lastObject];
values = [NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat: @"%d", [user numberOfSimultaneousBookings]], @"NumberOfSimultaneousBookings",
[user cn], @"Cn",
[user systemEmail], @"SystemEmail",
([event summary] ? [event summary] : @""), @"EventTitle",
[[fbInfo objectAtIndex: 0] objectForKey: @"startDate"], @"StartDate",
nil];
reason = [values keysWithFormat: [self labelForKey: @"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}."]];
return [NSException exceptionWithHTTPStatus:403
reason: reason];
}
}
else
{
// No conflict, we auto-accept. We do this for resources automatically if no
// double-booking is observed. If it's not the desired behavior, just don't
// set the resource as one!
[[currentAttendee attributes] removeObjectForKey: @"RSVP"];
[currentAttendee setParticipationStatus: iCalPersonPartStatAccepted];
}
else
{
iCalCalendar *calendar;
NSDictionary *values;
NSString *reason;
iCalEvent *event;
calendar = [iCalCalendar parseSingleFromSource: [[fbInfo objectAtIndex: 0] objectForKey: @"c_content"]];
event = [[calendar events] lastObject];
values = [NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat: @"%d", [user numberOfSimultaneousBookings]], @"NumberOfSimultaneousBookings",
[user cn], @"Cn",
[user systemEmail], @"SystemEmail",
([event summary] ? [event summary] : @""), @"EventTitle",
[[fbInfo objectAtIndex: 0] objectForKey: @"startDate"], @"StartDate",
nil];
reason = [values keysWithFormat: [self labelForKey: @"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}."]];
return [NSException exceptionWithHTTPStatus:403
reason: reason];
}
}
else
{
// No conflict, we auto-accept. We do this for resources automatically if no
// double-booking is observed. If it's not the desired behavior, just don't
// set the resource as one!
[[currentAttendee attributes] removeObjectForKey: @"RSVP"];
[currentAttendee setParticipationStatus: iCalPersonPartStatAccepted];
}
}
}
}
}
}
return nil;
@@ -787,7 +818,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
[self expandGroupsInEvent: newEvent];
// We first update the event. It is important to this initially
// We first update the event. It is important to do this initially
// as the event's UID might get modified.
[super updateComponent: newEvent];
@@ -795,13 +826,14 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
{
// New event -- send invitation to all attendees
attendees = [newEvent attendeesWithoutUser: ownerUser];
// We catch conflicts and abort the save process immediately
// in case of one with resources
if ((ex = [self _handleAddedUsers: attendees fromEvent: newEvent]))
return ex;
if ([attendees count])
{
// We catch conflicts and abort the save process immediately
// in case of one with resources
if ((ex = [self _handleAddedUsers: attendees fromEvent: newEvent]))
return ex;
[self sendEMailUsingTemplateNamed: @"Invitation"
forObject: [newEvent itipEntryWithMethod: @"request"]
previousObject: nil
@@ -1375,9 +1407,11 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
{
// We generate the updated iCalendar file and we save it in
// the database. We do this ONLY when using SOGo from the
// Web interface. Over DAV, it'll be handled directly in
// PUTAction:
if (![context request] || [[context request] handledByDefaultHandler])
// Web interface or over ActiveSync.
// Over DAV, it'll be handled directly in PUTAction:
if (![context request]
|| [[context request] handledByDefaultHandler]
|| [[[context request] requestHandlerKey] isEqualToString: @"Microsoft-Server-ActiveSync"])
ex = [self saveContentString: [[event parent] versitString]];
}
}
@@ -1,5 +1,5 @@
/*
Copyright (C) 2006-2012 Inverse inc.
Copyright (C) 2006-2013 Inverse inc.
Copyright (C) 2000-2005 SKYRIX Software AG
This file is part of SOGo.
@@ -140,6 +140,11 @@
return newEndDate;
}
- (NSString *) location
{
return [apt location];
}
- (NSString *) summary
{
return [apt summary];
@@ -1,9 +1,6 @@
/* SOGoCalendarComponent.h - this file is part of SOGo
*
* Copyright (C) 2006-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
* Copyright (C) 2006-2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+53 -35
View File
@@ -1,10 +1,6 @@
/* SOGoCalendarComponent.m - this file is part of SOGo
*
* Copyright (C) 2006-2012 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
* Ludovic Marcotte <lmarcotte@inverse.ca>
* Copyright (C) 2006-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
@@ -22,8 +18,10 @@
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSProcessInfo.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
@@ -62,6 +60,7 @@
#import <SOGo/SOGoWebDAVAclManager.h>
#import <SOGo/WORequest+SOGo.h>
#import <Appointments/SOGoAppointmentFolder.h>
#import <Mailer/NSString+Mail.h>
#import "SOGoAptMailICalReply.h"
#import "SOGoAptMailNotification.h"
@@ -219,29 +218,13 @@
- (NSString *) secureContentAsString
{
iCalCalendar *tmpCalendar;
iCalRepeatableEntityObject *tmpComponent;
// NSArray *roles;
iCalCalendar *tmpCalendar;
NSArray *allComponents;
SoSecurityManager *sm;
NSString *iCalString;
// uid = [[context activeUser] login];
// roles = [self aclsForUser: uid];
// if ([roles containsObject: SOGoCalendarRole_Organizer]
// || [roles containsObject: SOGoCalendarRole_Participant]
// || [roles containsObject: SOGoCalendarRole_ComponentViewer])
// calContent = content;
// else if ([roles containsObject: SOGoCalendarRole_ComponentDAndTViewer])
// {
// tmpCalendar = [[self calendar: NO] copy];
// tmpComponent = (iCalRepeatableEntityObject *)
// [tmpCalendar firstChildWithTag: [self componentTag]];
// [self _filterComponent: tmpComponent];
// calContent = [tmpCalendar versitString];
// [tmpCalendar release];
// }
// else
// calContent = nil;
int i;
sm = [SoSecurityManager sharedSecurityManager];
if (activeUserIsOwner
@@ -253,14 +236,21 @@
onObject: self inContext: context])
{
tmpCalendar = [[self calendar: NO secure: NO] mutableCopy];
tmpComponent = (iCalRepeatableEntityObject *)
[tmpCalendar firstChildWithTag: [self componentTag]];
[self _filterComponent: tmpComponent];
// We filter all components, in case we have RECURRENCE-ID
allComponents = [tmpCalendar childrenWithTag: [self componentTag]];
for (i = 0; i < [allComponents count]; i++)
{
tmpComponent = (iCalRepeatableEntityObject *)[allComponents objectAtIndex:i];
[self _filterComponent: tmpComponent];
// We add an additional header here to inform clients (if necessary) that
// we churned the content of the calendar.
[tmpComponent addChild: [CardElement simpleElementWithTag: @"X-SOGo-Secure"
value: @"YES"]];
// We add an additional header here to inform clients (if necessary) that
// we churned the content of the calendar.
[tmpComponent addChild: [CardElement simpleElementWithTag: @"X-SOGo-Secure"
value: @"YES"]];
}
iCalString = [tmpCalendar versitString];
[tmpCalendar release];
}
@@ -499,18 +489,31 @@
NSMutableArray *allAttendees;
iCalPerson *currentAttendee;
NSEnumerator *enumerator;
NSAutoreleasePool *pool;
SOGoGroup *group;
BOOL eventWasModified;
unsigned int i;
unsigned int i, j;
domain = [[context activeUser] domain];
organizerEmail = [[theEvent organizer] rfc822Email];
eventWasModified = NO;
allAttendees = [NSMutableArray arrayWithArray: [theEvent attendees]];
enumerator = [[theEvent attendees] objectEnumerator];
j = 0;
pool = [[NSAutoreleasePool alloc] init];
while ((currentAttendee = [enumerator nextObject]))
{
if (j%5 == 0)
{
RELEASE(pool);
pool = [[NSAutoreleasePool alloc] init];
}
group = [SOGoGroup groupWithEmail: [currentAttendee rfc822Email]
inDomain: domain];
if (group)
@@ -554,11 +557,15 @@
eventWasModified = YES;
}
}
j++;
} // while (currentAttendee ...
if (eventWasModified)
[theEvent setAttendees: allAttendees];
RELEASE(pool);
return eventWasModified;
}
@@ -760,6 +767,10 @@
SOGoUser *ownerUser;
SOGoDomainDefaults *dd;
// If defined, we return immediately. When not defined, we send the notifications correctly
if ([object firstChildWithTag: @"X-SOGo-Send-Appointment-Notifications"])
return;
ownerUser = [SOGoUser userWithLogin: owner];
dd = [ownerUser domainDefaults];
if ([dd appointmentSendEMailNotifications] && [object isStillRelevant])
@@ -837,6 +848,7 @@
mailDate = [[NSCalendarDate date] rfc822DateString];
[headerMap setObject: mailDate forKey: @"date"];
[headerMap setObject: subject forKey: @"subject"];
[headerMap setObject: [NSString generateMessageID] forKey: @"message-id"];
if ([msgType length] > 0)
[headerMap setObject: msgType forKey: @"x-sogo-message-type"];
msg = [NGMimeMessage messageWithHeader: headerMap];
@@ -866,8 +878,7 @@
sendMimePart: msg
toRecipients: [NSArray arrayWithObject: email]
sender: shortSenderEmail
withAuthenticator: [self
authenticatorInContext: context]
withAuthenticator: [self authenticatorInContext: context]
inContext: context];
}
}
@@ -892,7 +903,7 @@
SOGoDomainDefaults *dd;
dd = [from domainDefaults];
if ([dd appointmentSendEMailNotifications])
if ([dd appointmentSendEMailNotifications] && [event isStillRelevant])
{
/* get WOApplication instance */
app = [WOApplication application];
@@ -921,6 +932,7 @@
[headerMap setObject: mailDate forKey: @"date"];
[headerMap setObject: [[p getSubject] asQPSubjectString: @"UTF-8"]
forKey: @"subject"];
[headerMap setObject: [NSString generateMessageID] forKey: @"message-id"];
[headerMap setObject: @"1.0" forKey: @"MIME-Version"];
[headerMap setObject: @"multipart/mixed" forKey: @"content-type"];
[headerMap setObject: @"calendar:invitation-reply" forKey: @"x-sogo-message-type"];
@@ -1030,6 +1042,11 @@
// Recipient is fixed, which is the calendar owner
ownerUser = [SOGoUser userWithLogin: self->owner];
recipientIdentity = [ownerUser primaryIdentity];
// Safety net for broken configurations
if (!recipientIdentity)
return;
recipientEmail = [recipientIdentity objectForKey: @"email"];
fullRecipientEmail = [recipientIdentity keysWithFormat: @"%{fullName} <%{email}>"];
@@ -1038,6 +1055,7 @@
mailDate = [[NSCalendarDate date] rfc822DateString];
[headerMap setObject: mailDate forKey: @"date"];
[headerMap setObject: [page getSubject] forKey: @"subject"];
[headerMap setObject: [NSString generateMessageID] forKey: @"message-id"];
[headerMap setObject: @"1.0" forKey: @"MIME-Version"];
[headerMap setObject: @"text/html; charset=utf-8"
forKey: @"content-type"];
+3 -1
View File
@@ -294,7 +294,9 @@
contact = [contacts lastObject];
email = [contact valueForKey: @"c_email"];
source = [contact objectForKey: @"source"];
if ([email length] && [source MSExchangeHostname])
if ([email length]
&& [source conformsToProtocol: @protocol (SOGoDNSource)]
&& [source MSExchangeHostname])
{
exchangeFreeBusy = [[MSExchangeFreeBusy alloc] init];
[exchangeFreeBusy autorelease];
+5 -3
View File
@@ -1,14 +1,16 @@
/*
Copyright (C) 2006-2013 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.
@@ -1,8 +1,6 @@
/* iCalEntityObject+SOGo.h - 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
@@ -48,6 +46,8 @@ extern NSNumber *iCalDistantFutureNumber;
- (NSMutableDictionary *) quickRecord;
- (int) priorityNumber;
- (NSString *) createdBy;
- (NSNumber *) quickRecordDateAsNumber: (NSCalendarDate *) _date
withOffset: (int) offset
forAllDay: (BOOL) allDay;
+16 -3
View File
@@ -1,8 +1,6 @@
/* iCalEntityObject+SOGo.m - this file is part of SOGo
*
* Copyright (C) 2007-2010 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
@@ -242,4 +240,19 @@ NSNumber *iCalDistantFutureNumber = nil;
return priorityNumber;
}
- (NSString *) createdBy
{
NSString *created_by;
created_by = [[self firstChildWithTag: @"X-SOGo-Component-Created-By"] flattenedValuesForKey: @""];
// We consider "SENT-BY" in case our custom header isn't found
if (![created_by length])
{
created_by = [[self organizer] sentBy];
}
return created_by;
}
@end
+11
View File
@@ -64,6 +64,9 @@
return isStillRelevent;
}
//
//
//
- (NSMutableDictionary *) quickRecord
{
NSMutableDictionary *row;
@@ -88,7 +91,15 @@
title = [self summary];
if (![title isNotNull])
title = @"";
if ([title length] > 1000)
title = [title substringToIndex: 1000];
location = [self location];
if ([location length] > 255)
location = [location substringToIndex: 255];
sequence = [self sequence];
accessClass = [self symbolicAccessClass];
isAllDay = [self isAllDay];
+15 -3
View File
@@ -1,8 +1,6 @@
/* NGVCard+SOGo.h - this file is part of SOGo
*
* Copyright (C) 2009 Inverse inc.
*
* Author: Cyril Robert <crobert@inverse.ca>
* Copyright (C) 2009-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
@@ -30,9 +28,23 @@
@interface NGVCard (SOGoExtensions)
- (CardElement *) elementWithTag: (NSString *) elementTag
ofType: (NSString *) type;
- (void) updateFromLDIFRecord: (NSDictionary *) ldifRecord;
- (NSMutableDictionary *) asLDIFRecord;
- (NSString *) workCompany;
- (NSString *) fullName;
- (NSArray *) secondaryEmails;
- (NSString *) workPhone;
- (NSString *) homePhone;
- (NSString *) fax;
- (NSString *) mobile;
- (NSString *) pager;
- (NSCalendarDate *) birthday;
@end
#endif /* NGVCARD_SOGO_H */
+165 -16
View File
@@ -1,8 +1,6 @@
/* NGVCard+SOGo.m - this file is part of SOGo
*
* Copyright (C) 2009 Inverse inc.
*
* Author: Cyril Robert <crobert@inverse.ca>
* Copyright (C) 2009-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
@@ -29,6 +27,8 @@
#import <NGCards/NSArray+NGCards.h>
#import <NGCards/NSString+NGCards.h>
#import <SOGo/NSCalendarDate+SOGo.h>
#import "NSDictionary+LDIF.h"
#import "NGVCard+SOGo.h"
@@ -164,8 +164,8 @@ convention:
@implementation NGVCard (SOGoExtensions)
/* LDIF -> VCARD */
- (CardElement *) _elementWithTag: (NSString *) elementTag
ofType: (NSString *) type
- (CardElement *) elementWithTag: (NSString *) elementTag
ofType: (NSString *) type
{
NSArray *elements;
CardElement *element;
@@ -188,16 +188,16 @@ convention:
{
CardElement *phone;
phone = [self _elementWithTag: @"tel" ofType: @"work"];
phone = [self elementWithTag: @"tel" ofType: @"work"];
[phone setSingleValue: [ldifRecord objectForKey: @"telephonenumber"] forKey: @""];
phone = [self _elementWithTag: @"tel" ofType: @"home"];
phone = [self elementWithTag: @"tel" ofType: @"home"];
[phone setSingleValue: [ldifRecord objectForKey: @"homephone"] forKey: @""];
phone = [self _elementWithTag: @"tel" ofType: @"cell"];
phone = [self elementWithTag: @"tel" ofType: @"cell"];
[phone setSingleValue: [ldifRecord objectForKey: @"mobile"] forKey: @""];
phone = [self _elementWithTag: @"tel" ofType: @"fax"];
phone = [self elementWithTag: @"tel" ofType: @"fax"];
[phone setSingleValue: [ldifRecord objectForKey: @"facsimiletelephonenumber"]
forKey: @""];
phone = [self _elementWithTag: @"tel" ofType: @"pager"];
phone = [self elementWithTag: @"tel" ofType: @"pager"];
[phone setSingleValue: [ldifRecord objectForKey: @"pager"] forKey: @""];
}
@@ -205,9 +205,9 @@ convention:
{
CardElement *mail, *homeMail;
mail = [self _elementWithTag: @"email" ofType: @"work"];
mail = [self elementWithTag: @"email" ofType: @"work"];
[mail setSingleValue: [ldifRecord objectForKey: @"mail"] forKey: @""];
homeMail = [self _elementWithTag: @"email" ofType: @"home"];
homeMail = [self elementWithTag: @"email" ofType: @"home"];
[homeMail setSingleValue: [ldifRecord objectForKey: @"mozillasecondemail"] forKey: @""];
[[self uniqueChildWithTag: @"x-mozilla-html"]
setSingleValue: [ldifRecord objectForKey: @"mozillausehtmlmail"]
@@ -230,7 +230,7 @@ convention:
[self setFn: [ldifRecord objectForKey: @"displayname"]];
[self setTitle: [ldifRecord objectForKey: @"title"]];
element = [self _elementWithTag: @"adr" ofType: @"home"];
element = [self elementWithTag: @"adr" ofType: @"home"];
[element setSingleValue: [ldifRecord objectForKey: @"mozillahomestreet2"]
atIndex: 1 forKey: @""];
[element setSingleValue: [ldifRecord objectForKey: @"mozillahomestreet"]
@@ -244,7 +244,7 @@ convention:
[element setSingleValue: [ldifRecord objectForKey: @"mozillahomecountryname"]
atIndex: 6 forKey: @""];
element = [self _elementWithTag: @"adr" ofType: @"work"];
element = [self elementWithTag: @"adr" ofType: @"work"];
[element setSingleValue: [ldifRecord objectForKey: @"mozillaworkstreet2"]
atIndex: 1 forKey: @""];
[element setSingleValue: [ldifRecord objectForKey: @"street"]
@@ -268,9 +268,9 @@ convention:
[self _setPhoneValues: ldifRecord];
[self _setEmails: ldifRecord];
[[self _elementWithTag: @"url" ofType: @"home"]
[[self elementWithTag: @"url" ofType: @"home"]
setSingleValue: [ldifRecord objectForKey: @"mozillahomeurl"] forKey: @""];
[[self _elementWithTag: @"url" ofType: @"work"]
[[self elementWithTag: @"url" ofType: @"work"]
setSingleValue: [ldifRecord objectForKey: @"mozillaworkurl"] forKey: @""];
[[self uniqueChildWithTag: @"x-aim"]
@@ -639,4 +639,153 @@ convention:
return ldifRecord;
}
- (NSString *) workCompany
{
CardElement *org;
NSString *company;
org = [self org];
company = [org flattenedValueAtIndex: 0 forKey: @""];
if ([company length] == 0)
company = nil;
return company;
}
- (NSString *) fullName
{
CardElement *n;
NSString *fn, *firstName, *lastName, *org;
fn = [self fn];
if ([fn length] == 0)
{
n = [self n];
lastName = [n flattenedValueAtIndex: 0 forKey: @""];
firstName = [n flattenedValueAtIndex: 1 forKey: @""];
if ([firstName length] > 0)
{
if ([lastName length] > 0)
fn = [NSString stringWithFormat: @"%@ %@", firstName, lastName];
else
fn = firstName;
}
else if ([lastName length] > 0)
fn = lastName;
else
{
n = [self org];
org = [n flattenedValueAtIndex: 0 forKey: @""];
fn = org;
}
}
return fn;
}
- (NSArray *) secondaryEmails
{
NSMutableArray *emails;
NSString *email;
int i;
emails = [NSMutableArray array];
[emails addObjectsFromArray: [self childrenWithTag: @"email"]];
[emails removeObjectsInArray: [self childrenWithTag: @"email"
andAttribute: @"type"
havingValue: @"pref"]];
for (i = [emails count]-1; i >= 0; i--)
{
email = [[emails objectAtIndex: i] flattenedValuesForKey: @""];
if ([email caseInsensitiveCompare: [self preferredEMail]] == NSOrderedSame)
[emails removeObjectAtIndex: i];
}
return emails;
}
- (NSString *) _phoneOfType: (NSString *) aType
excluding: (NSString *) aTypeToExclude
{
NSArray *elements, *phones;
NSString *phone;
phones = [self childrenWithTag: @"tel"];
elements = [phones cardElementsWithAttribute: @"type"
havingValue: aType];
phone = nil;
if ([elements count] > 0)
{
CardElement *ce;
int i;
for (i = 0; i < [elements count]; i++)
{
ce = [elements objectAtIndex: i];
phone = [ce flattenedValuesForKey: @""];
if (!aTypeToExclude)
break;
if (![ce hasAttribute: @"type" havingValue: aTypeToExclude])
break;
phone = nil;
}
}
return phone;
}
- (NSString *) workPhone
{
// We do this (exclude FAX) in order to avoid setting the WORK number as the FAX
// one if we do see the FAX field BEFORE the WORK number.
return [self _phoneOfType: @"work" excluding: @"fax"];
}
- (NSString *) homePhone
{
return [self _phoneOfType: @"home" excluding: @"fax"];
}
- (NSString *) fax
{
return [self _phoneOfType: @"fax" excluding: nil];
}
- (NSString *) mobile
{
return [self _phoneOfType: @"cell" excluding: nil];
}
- (NSString *) pager
{
return [self _phoneOfType: @"pager" excluding: nil];
}
- (NSCalendarDate *) birthday
{
NSString *bday, *value;
NSCalendarDate *date;
bday = [self bday];
date = nil;
if ([bday length] > 0)
{
// Expected format of BDAY is YYYY[-]MM[-]DD
value = [bday stringByReplacingString: @"-" withString: @""];
date = [NSCalendarDate dateFromShortDateString: value
andShortTimeString: nil
inTimeZone: nil];
}
return date;
}
@end /* NGVCard */
+3 -3
View File
@@ -1,8 +1,6 @@
/* SOGoContactFolders.h - this file is part of SOGo
*
* Copyright (C) 2006, 2007 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2006-2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,6 +29,8 @@
withDisplayName: (NSString *) newDisplayName;
- (NSException *) removeLDAPAddressBook: (NSString *) sourceID;
- (NSDictionary *) systemSources;
@end
#endif /* SOGOCONTACTFOLDERS_H */
+14 -12
View File
@@ -1,8 +1,6 @@
/* SOGoContactFolders.m - this file is part of SOGo
*
* Copyright (C) 2006-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2006-2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,13 +18,6 @@
* Boston, MA 02111-1307, USA.
*/
/* MailItems IPF.Note
ContactItems IPF.Contact
AppointmentItems IPF.Appointment
NoteItems IPF.StickyNote
TaskItems IPF.Task
JournalItems IPF.Journal */
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
@@ -50,6 +41,7 @@
#import "SOGoContactFolders.h"
#define XMLNS_INVERSEDAV @"urn:inverse:params:xml:ns:inverse-dav"
@implementation SOGoContactFolders
+ (NSString *) gcsFolderType
@@ -118,8 +110,9 @@
return result;
}
- (NSException *) appendSystemSources
- (NSDictionary *) systemSources
{
NSMutableDictionary *systemSources;
SOGoUserManager *um;
SOGoSystemDefaults *sd;
NSEnumerator *sourceIDs, *domains;
@@ -127,6 +120,8 @@
SOGoContactSourceFolder *currentFolder;
SOGoUser *currentUser;
systemSources = [NSMutableDictionary dictionary];
if (! ([[context request] isIPhoneAddressBookApp] &&
![[context request] isAndroid]))
{
@@ -151,13 +146,20 @@
andDisplayName: srcDisplayName
inContainer: self];
[currentFolder setSource: [um sourceWithID: currentSourceID]];
[subFolders setObject: currentFolder forKey: currentSourceID];
[systemSources setObject: currentFolder forKey: currentSourceID];
}
domain = [domains nextObject];
}
}
}
return systemSources;
}
- (NSException *) appendSystemSources
{
[subFolders addEntriesFromDictionary: [self systemSources]];
return nil;
}
+1 -3
View File
@@ -1,8 +1,6 @@
/* SOGoContactGCSEntry.h - this file is part of SOGo
*
* Copyright (C) 2006-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2006-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
Loaded 100 of 576 files, more files were not shown because too many files have changed in this diff. Show more