Compare commits

...
410 Commits
Author SHA1 Message Date
Ludovic Marcotte 289100beff Updated files for the 2.3 release 2015-06-01 08:36:02 -04:00
Ludovic Marcotte 7da6b0b822 (fix) only dump broken eas data to file if SOGoEASDebugEnabled is enabled 2015-05-29 14:23:01 -04:00
Ludovic Marcotte 6cf2fd1e52 Adjusted the doc for the procedure on Wheezy/Precise 2015-05-28 13:41:19 -04:00
Ludovic Marcotte c95568373f Added control file for i386/i686 distro to not build OC 2015-05-28 11:29:44 -04:00
Francis Lachapelle bd12a817a6 Update languages in Installation Guide 2015-05-28 08:30:30 -04:00
Ludovic Marcotte 2fd0beeaca Added precision on supported architectures 2015-05-27 15:53:23 -04:00
Ludovic Marcotte db4cd9da6e (fix) doc update regarding samba 4.1.18 2015-05-27 15:53:23 -04:00
extrafu d1551bc7bb Merge pull request #86 from gillesgagniard/rhel7-improvements
various fixes for systemd service on RHEL7
2015-05-26 16:59:36 -04:00
Gilles Gagniard bea9b26907 systemd needs to reload the newly installed sogod.service, otherwise enable/start will fail on first sogo installation 2015-05-26 22:55:14 +02:00
Gilles Gagniard 84dfba7978 honor PREFORK setting in /etc/sysconfig/sogo when starting sogod with systemd 2015-05-26 22:50:28 +02:00
Ludovic Marcotte ce3d55d2cc (fix) do not rewrite the username when using the session from the db 2015-05-26 11:08:30 -04:00
Francis Lachapelle b43c3f6d98 Fix asciidoc of Installation guide 2015-05-25 13:52:25 -04:00
Ludovic Marcotte abcd48a0cd Added missing image used in the documentation 2015-05-25 13:37:04 -04:00
Ludovic Marcotte d07df554f3 (fix) more fixes and clarifications on the mutli-domain settings 2015-05-25 13:00:08 -04:00
Ludovic Marcotte 772c3b3115 (fix) formatting fixes 2015-05-25 10:43:42 -04:00
Ludovic Marcotte ed42d1e26b (fix) more multi-domain fixes and cleanups 2015-05-25 09:19:04 -04:00
Ludovic Marcotte e0c1d5e47b Improved the doc for the 2.3 release 2015-05-25 08:27:46 -04:00
Ludovic Marcotte 55d91973bd Improved the doc for the release 2015-05-22 15:23:48 -04:00
Ludovic Marcotte 4f303f8aa2 Fixed mess regarding uid/realUID 2015-05-22 14:03:49 -04:00
Ludovic Marcotte c8995087d8 Small improvements to the docs 2015-05-22 13:50:06 -04:00
Ludovic Marcotte 2ae5f342da Fix a crasher 2015-05-22 13:47:48 -04:00
extrafu d6ab7582e5 Merge pull request #85 from Zentyal/inverse_fix-multidomain-web
Avoid reading emails from other domains
2015-05-22 09:19:54 -04:00
Francis Lachapelle 1e0473f1e5 Localization 2015-05-22 07:58:26 -04:00
Jesús García Sáez 7990e23aaa Fix warning distinct Objective-C type
failedCount is a NSDictionary *, not NSMutableDictionary *
2015-05-22 10:19:09 +02:00
Jesús García Sáez 04ce8d1066 Avoid cache entries with uid@domain@domain prefix
Depend of the current workflow this paths are reached with
username as uid and sometimes as uid@domain. So in multidomain
environments only append @domain when needed.

Conflicts:
	SoObjects/SOGo/SOGoUserManager.m
2015-05-22 10:18:55 +02:00
Jesús García Sáez 37461e650d Fix conflicts with externalLoginWithEmail + DomainBasedUid
On multidomain environment (SOGoEnableDomainBasedUID) with email for imap
authentication (SOGoForceExternalLoginWithEmail) we need to use uid@domain
instead of just uid in method getEmailForUID
2015-05-22 10:14:49 +02:00
Jesús García Sáez 9922ec56d9 Avoid uid+attributes entries on shared cache
In multidomain environments this will produce that info@domain1.com
can read info@domain2.com emails when info@domain2.com log in after
info@domain1.com is already logged in.

If multidomain is not enabled, this action is not needed because
uid+attributes has been already saved on shared cache
2015-05-22 10:14:43 +02:00
Francis Lachapelle 7893349244 TimePicker: allow entries from numpad
Fixes #1516
2015-05-21 21:35:13 -04:00
Ludovic Marcotte e40be92204 Updated NEWS file regarding PR#84 2015-05-21 08:48:45 -04:00
extrafu 30103532ae Merge pull request #84 from Zentyal/master
sogo-openchange fixes
2015-05-21 08:46:21 -04:00
extrafu b433bac432 Merge pull request #83 from Zentyal/jag/change-passsword-exceptions
Return appropiate error code when changing AD password with incorrect…
2015-05-21 08:42:17 -04:00
Ludovic Marcotte 79bfc7aedf (fix) more rhel7 fix 2015-05-20 14:27:57 -04:00
Ludovic Marcotte 54ab0bf822 (fix) rhel7 packaging fix 2015-05-20 14:24:02 -04:00
Ludovic Marcotte 7e8c79c646 (fix) use the contact-info, not the user/group bit identifier 2015-05-20 13:51:16 -04:00
Ludovic Marcotte 416711ea43 (fix) avoid appending the domain unconditionally when SOGoEnableDomainBasedUID is set to YES 2015-05-19 13:48:59 -04:00
Javier Amor García 5a8f310bc8 Show 'complexity password' error instead of a generic error.
There is not discrimination between complexity and length errors because backend does not
return different error codes for each case.
2015-05-19 15:00:18 +02:00
Ludovic Marcotte ae72c2f1d5 Renamed scripts 2015-05-19 06:35:19 -04:00
Jesús García Sáez ca500df0af Merge pull request #136 from Zentyal/ejhernandez/fix-regression-all-day-recurrent
oc-calendar: Fix regression on PidLidAppointmentTimeZoneDefinitionStartDisplay
2015-05-19 10:38:35 +02:00
Enrique J. Hernández Blasco e2ef0103c4 oc-calendar: Fix regression on AppointmentTimeZoneDefinitionStartDisplay
Introduced by ebe2a466e7 in PR #132 when the event is not
all day neither recurrent one.

The fix is just to initialise to nil when it is a normal event
and it returns NOT_FOUND for this property.
2015-05-19 00:26:42 +02:00
Julio J. García Martín e6d1a00928 Merge pull request #135 from Zentyal/jvalles/reply-requested-return-values
oc-calendar: Fix property values of invitation responses
2015-05-18 12:48:37 +02:00
Ludovic Marcotte 143ee59f5b Improved debian packaging regarding apache 2.2 -> 2.4 2015-05-15 09:38:58 -04:00
Ludovic Marcotte 037a3a136a (fix) message bodies not shown on some EAS devices (#3173) 2015-05-14 15:58:53 -04:00
Ludovic Marcotte c98a000515 (feat) many improvements to EAS SmartReply/SmartForward commands 2015-05-14 15:49:53 -04:00
Ludovic Marcotte cc1e9f2fff (fix) additional fix for #3152 2015-05-14 15:40:03 -04:00
Ludovic Marcotte 9dc0a08bba (fix) removed unused import 2015-05-14 15:28:23 -04:00
Ludovic Marcotte 5412599832 (feat) now possible to log EAS commands using the SOGoEASDebugEnabled system defaults 2015-05-14 15:26:18 -04:00
Ludovic Marcotte fbf5c4f6c2 (fix) always include SrcMsgId in the MoveItems's response 2015-05-13 19:09:58 -04:00
Ludovic Marcotte d97813451e (fix) moved stuff to multiarch 2015-05-13 16:09:41 -04:00
Ludovic Marcotte 4de814c3b2 (fix) first pass (and hopefully only) at Apache 2.2->2.4 mess 2015-05-13 15:48:47 -04:00
Ludovic Marcotte fb121974ec refactored previous commit 2015-05-13 14:52:10 -04:00
Ludovic Marcotte 39aa9a97db (fix) make sure we return event blocks sorted by start date (#2939) 2015-05-13 14:36:35 -04:00
Ludovic Marcotte dc48e05dd3 (feat) print event/task description in list view (#2881) 2015-05-13 13:12:15 -04:00
Ludovic Marcotte 0ea0a77666 fixed typo in previous commit 2015-05-13 10:55:17 -04:00
Ludovic Marcotte f8b7ebdaf8 Adjust OCS files regarding previous commit 2015-05-13 10:51:12 -04:00
Ludovic Marcotte 5cf500d560 (feat) added c_description to calendar quick tables 2015-05-13 10:45:19 -04:00
Ludovic Marcotte c1ce32ac94 (fix) now handle very large amount of participants correctly (#3175) 2015-05-12 15:48:42 -04:00
Ludovic Marcotte e71a1c9974 (fix) addition fix for #3152 2015-05-12 10:44:51 -04:00
Ludovic Marcotte 96b2e0e1f5 (fix) use dateTime instead of compact format for meeting requests 2015-05-12 10:37:26 -04:00
Ludovic Marcotte a145fdbb53 (fix) ensure calendar objects have a (fake) filename 2015-05-12 10:33:05 -04:00
Ludovic Marcotte 619e9fe7dd (fix) now correctly handle multiple email addresses in the GAL over EAS 2015-05-12 10:28:47 -04:00
Ludovic Marcotte 64da65d827 (fix) fallback to Latin1 when trying to parse versit data 2015-05-12 10:19:20 -04:00
Ludovic Marcotte 364a07bd05 set the preferred body type for meeting response 2015-05-12 10:15:07 -04:00
Ludovic Marcotte 2c78d60e4a (fix) now correct handle external invitations using EAS 2015-05-12 10:12:57 -04:00
Ludovic Marcotte ee8caa5a99 (fix) now set MeetingMessageType only for EAS 14.1 2015-05-12 10:05:45 -04:00
Ludovic Marcotte f666b436dd (fix) make sure sure email invitations can always be read by EAS clients 2015-05-12 09:59:01 -04:00
Ludovic Marcotte 4826f01555 (fix) fixed EAS replies decoding from Outlook (#3123) 2015-05-12 09:52:13 -04:00
Juan Vallés 0a285eedec oc-calendar: Fix property values of invitation responses
The value of `PidTagResponseRequested` property in the invitation mail
wasn't being set properly, while the `PidTagReplyRequested` property
wasn't being set at all. This caused invitation response mails not to be
sent. Both properties are expected to be `true`.
2015-05-11 12:58:06 +02:00
Julio J. García Martín 582c24afc5 Merge pull request #133 from Zentyal/ejhernandez/flush-cache
oc-mail: Flush IMAP hierarchy cache to update Outlook folders
2015-05-07 09:53:49 +02:00
Enrique J. Hernández 92ab267db5 Merge pull request #131 from Zentyal/ejhernandez/set-restriction-on-name-for-mail-folders
oc-mail: Support restricitions on name for MAPIStoreMailFolderTable
2015-05-07 02:03:39 +02:00
Ludovic Marcotte fbb779a71d (fix) During login, we now extract the domain from the user to accelerate authentication requests on sources 2015-05-06 16:03:33 -04:00
Julio J. García Martín 54b405a83d Merge pull request #132 from Zentyal/jvalles/floating-time-in-all-day-events
oc-calendar: Interpret dates of all-day events in floating time
2015-05-06 12:22:51 +02:00
Enrique J. Hernández Blasco 15f95c4956 oc-mail: Support restricitions on name for MAPIStoreMailFolderTable
This allows us to search for a subfolder in a mail
folder successfully. This is happening, for instance, on folder creation.
2015-05-05 23:34:09 +02:00
Enrique J. Hernández Blasco 2d65b75b56 oc-mail: Flush IMAP hierarchy cache to update Outlook folders
This fixes two scenarios:

* An IMAP subfolder has updated its hierarchy when it is asked
  to be synchronised
* An IMAP root folder is created on Outlook when you logon. OpenChange
  changes are required to be refreshed on synchronisation.
2015-05-05 23:30:12 +02:00
Juan Vallés ebe2a466e7 oc-calendar: Compute PidLidAppointmentDefinitionStartWhole for all-day events 2015-05-05 10:29:24 +02:00
Juan Vallés 7e89c43919 oc-calendar: Compute time offset in floating time in all-day recurring events 2015-05-05 10:29:24 +02:00
Ludovic Marcotte a37f438663 (fix) the EAS maximum response size being per-folder, and not global 2015-05-04 09:11:52 -04:00
Julio J. García Martín dc5237e92e Merge pull request #123 from Zentyal/ejhernandez/no-mapping-creation-root-folder
oc: Do not create indexing entry for a root folder
2015-05-04 11:10:47 +02:00
Francis Lachapelle 50896eb526 (i18n) Improve Basque Locale file 2015-04-28 14:44:29 -04:00
Ludovic Marcotte 7ff12c7a64 Updated NEWS file regarding Zentyal's PRs 2015-04-27 15:07:44 -04:00
Ludovic Marcotte f2b5f5917b Fixed dot notation 2015-04-27 15:02:00 -04:00
Ludovic Marcotte ee74b78bf2 Merge branch 'master' of https://github.com/inverse-inc/sogo 2015-04-27 14:58:20 -04:00
Ludovic Marcotte dfb960eac4 Disabled -Werr for now 2015-04-27 14:57:44 -04:00
Francis Lachapelle a1406d01e1 Initial Basque translation 2015-04-27 13:59:05 -04:00
Francis Lachapelle 07ac3f43fb Simplify some calls in SOGoAppointmentFolder.m 2015-04-27 10:39:09 -04:00
extrafu 1db2b9793a Merge pull request #79 from Zentyal/contribute-back
Latest changes for sogo-openchange
2015-04-27 10:14:29 -04:00
extrafu 393d8e5a73 Merge pull request #80 from dekkers/md4-compile-fix
Do not include nonexistent config.h in md4.c
2015-04-26 20:00:29 -04:00
extrafu 6f741168a9 Merge pull request #81 from dekkers/spelling-fix
Spelling fix: dictionnary -> dictionary
2015-04-26 20:00:08 -04:00
Jeroen Dekkers 84c199b95a Spelling fix: dictionnary -> dictionary 2015-04-26 13:33:03 +02:00
Jeroen Dekkers 769045bbf6 Do not include nonexistent config.h 2015-04-25 14:40:42 +02:00
Julio García 08501dacaa Merge branch 'master' into contribute-back
Conflicts:
	NEWS
2015-04-24 16:53:05 +02:00
Jesús García Sáez b7907d654d Merge pull request #127 from Zentyal/jkerihuel/asynchronous-notifications
[oxcnotif] Delete deprecated notification code
2015-04-22 12:45:20 +02:00
extrafu a94591a365 Merge pull request #78 from Zentyal/contribute-back
Fixes for OpenChange integration from Zentyal
2015-04-20 11:43:04 -04:00
Julio García 78f5f60b16 Revert "oc: monkeypatched NGImap4Connection class from sope"
This reverts commit 24e35103ff.
2015-04-20 13:15:22 +02:00
Julio García 255b3d2d00 Revert "oc: NGImap4Connection:fetchUids don't delete RawResponse"
This reverts commit c410a9fc3f.
2015-04-20 13:15:13 +02:00
Julio García 1d9e085658 Revert "oc: NGImap4Connection:fetchUids changed error messages"
This reverts commit 41320a4813.
2015-04-20 13:15:04 +02:00
Julio García 9901788db6 Revert "Update news for next release"
This reverts commit cd47c926c9.

Conflicts:
	NEWS
2015-04-20 09:51:02 +02:00
Julio García 8e39f03f83 Revert "Prepare for 2.2.17a-zentyal1"
This reverts commit 8706443685.

Conflicts:
	NEWS
2015-04-20 09:48:52 +02:00
Julio García f6370d10cb Revert "Prepare for new 2.2.15-zentyal3 version"
This reverts commit 914e7b7418.

Conflicts:
	NEWS
2015-04-20 09:47:40 +02:00
Ludovic Marcotte d0c1737b1b Removed TODO refs 2015-04-17 14:09:51 -04:00
Ludovic Marcotte 836095e984 Removed old TODO file 2015-04-17 14:09:13 -04:00
Luc Charland a86b164228 uses a dict instead of a string of a dict for preventInvitationsTest 2015-04-17 10:38:40 -04:00
Francis Lachapelle 5847e086ec (fix) Edition and access of attach URL in editor 2015-04-17 10:00:29 -04:00
Ludovic Marcotte 3872af35d1 (fix) Improve prevent invitations error handling 2015-04-17 09:41:39 -04:00
Ludovic Marcotte beb666bc5f (fix) fixed md4 support (for NTLM password changes) with GNU TLS 2015-04-17 09:29:49 -04:00
Enrique J. Hernández Blasco 8fce211172 Merge pull request #125 from Zentyal/jgarcia/multidomain-outlook-entryId
All this basically is to make it work on multidomain environment
the Reply all functionality of emails but I'm sure there are more use cases
as an Outlook client that don't work nowadays without this patch.

More info on commit message but basically it was that we were using user
instead of user@domain.com in several places.
2015-04-17 11:33:21 +02:00
Enrique J. Hernández Blasco 030d343432 oc: Do not create indexing entry for a root folder
This is done by OpenChange after this patchset is merged:

https://github.com/openchange/openchange/pull/273
2015-04-16 23:23:32 +02:00
Francis Lachapelle a7306a77cb (fix) JavaScript error when saving preferences
The error was occuring when the user enabled forwarding but no domains
constraints were defined in the SOGo's configuration.
2015-04-16 15:27:55 -04:00
Jesús García Sáez 58449076a3 Merge branch 'jacalvo/fix-optional-rec-type' 2015-04-16 19:55:19 +02:00
José Antonio Calvo 539060d252 oc-calendar: Fix recipient type for invitations
Take into account optional attendees setting the recipient
type to MAPI_CC when they have the iCal role set to OPT-PARTICIPANT
instead of harding always MAPI_TO (required) as was done before.

This is a complementary fix for: https://github.com/Zentyal/sogo/pull/108
2015-04-16 19:47:47 +02:00
Jesús García Sáez 336c4fb9d3 Merge pull request #121 from Zentyal/ejhernandez/search-mapidb-message-props
oc: Search for properties in a SOGoMAPIDB object now works
2015-04-16 18:51:18 +02:00
Jesús García Sáez d3bf3dcd8f Merge pull request #122 from Zentyal/ejhernandez/enforce-mapping-subfolder
oc: Enforce the folder creation mapping when the FID exists
2015-04-16 18:05:29 +02:00
Julien Kerihuel d4930a7960 oc: Remove deprecated notification code. 2015-04-16 16:04:47 +02:00
Jesús García Sáez 49ee0850e1 Merge pull request #118 from Zentyal/ejhernandez/return-sorted-events
oc: return last modified messages when sorted by PidMessageTagDeliveryTime

This change is required as oxcfxics is asking for sorting
using this property.

We fake this property on GCS folders (Tasks, Calendar, Contacts)
using c_lastmodified column.
2015-04-16 12:50:20 +02:00
Jesús García Sáez 0f432b654f oc: Fix internal EntryIds properties on multidomain
PidTag*EntryId properties were not being generated (which contain
the email address and so on). Functionality on Outlook clients like
"Reply All" were not working because of this (probably a lot more
stuff related with email addresses).

With multidomain support enabled outlook clients will use full email
address (e.g. user@domain.com) as login.

This change is needed because we were performing ldap queries on samdb
using (sAMAccountName=UIDFieldName), being UIDFieldName the parameter
configured in sogo.conf for that source. In multidomain environment
this field could be `sAMAccountName` but it could not. Actually the
more logical scenario will be to use `uid` field here (which will be
just `user`, without the `@domain.com` part).

SOGoUserManager will return `sAMAccountName` if the contact has it
(in Outlook environment that means always) so it can (and must) be
used to query samdb in MAPIStoreSamDBUtils properly.

TL;DR: use sAMAccoutName instead of uid to query samdb
2015-04-16 11:32:24 +02:00
Julio García cdb6085510 Revert "Adding missing build dependency gnulib"
This reverts commit 210053ea20.
2015-04-16 09:55:32 +02:00
Julio García 6b3454376e Revert "configure: Fix gnulib/crypto/md4 dependency"
This reverts commit f0a3fdae5b.
2015-04-16 09:55:22 +02:00
Julio García a8e8ec535a Prepare for 2.2.17a-zentyal1 2015-04-15 19:57:56 +02:00
Julio García 3f3ae3acd7 Merge remote-tracking branch 'upstream/master' into contribute-back
Conflicts:
	NEWS
2015-04-15 17:08:30 +02:00
Julio García 8706443685 Prepare for 2.2.17a-zentyal1 2015-04-15 16:10:03 +02:00
Julio García ca7c4c026e Merge pull request #119 from Zentyal/jjgarcia/merge-from-upstream
Merge from upstream version 2.2.17a
2015-04-15 16:05:37 +02:00
Jesús García Sáez f0a3fdae5b configure: Fix gnulib/crypto/md4 dependency
Gnulib project needs Autoconf to be able to import their modules with gnulib-tool
http://www.gnu.org/software/gnulib/manual/html_node/Initial-import.html#Initial-import

We only need md4.c file so this is a workaround to compile it without using
gnulib-tool --import
2015-04-15 15:28:32 +02:00
Julio García 210053ea20 Adding missing build dependency gnulib 2015-04-15 15:28:23 +02:00
Julio J. García Martín 35f81318d6 Merge pull request #124 from Zentyal/jgarcia/multidomain_cache_tables
Multidomain cache tables
2015-04-15 10:41:17 +02:00
Jesús García Sáez 1d6f1a83af use full login for sogo_cache_folder tables
So when multidomain is enabled we will have tables like
sogo_cache_folder_user_A_domain_D_com instead of just
sogo_cache_folder_user

If multidomain is disabled the folders will still be like
sogo_cache_folder_user
2015-04-14 13:18:23 +02:00
Julio García 914e7b7418 Prepare for new 2.2.15-zentyal3 version 2015-04-14 11:44:32 +02:00
Enrique J. Hernández Blasco bddd67fb93 oc: Enforce the folder creation mapping when the FID exists
We believe the folder ID OpenChange is sending us is new
and we keep the indexing database properly updated.

Although the solution is not elegant, this could avoid
inconsistencies between what the client stores and the
relation in the MAPIStore backend.
2015-04-13 11:48:42 +02:00
Enrique J. Hernández Blasco fa23b574eb oc: Search for properties in a SOGoMAPIDB object now works
sogo-openchange library stores the properties as NSString keys
and the search function casts the values to NSNumber, which it may
be valid for other parts but not for this library.

The real fix would be to store the property keys as NSNumbers as
they are uint32_t at the end. However, this may lead to a great
refactor in the library.

With this fix, we can match the search for a property in a
MAPIStoreFallback folder, such as Notes or Deleted Items, or
MAPIStoreFolder properties (ie: search for a subfolder) or
for MAPIStoreFAIMessages in a folder.
2015-04-13 11:37:48 +02:00
Julio García 321e16c382 Merge tag 'SOGo-2.2.17a' into jjgarcia/merge-from-upstream
SOGo 2.2.17a

Conflicts:
	NEWS
2015-04-10 13:12:46 +02:00
Julio García 479bbce7d0 Merge pull request #116 from Zentyal/ejhernandez/soft-deleted-sync
Soft deleted mail messages sync
2015-04-10 10:27:48 +02:00
Julio J. García Martín 69b06d3c7a Merge pull request #113 from Zentyal/jag/show-internet-headers
Support for PidTagTransportMessageHeaders property
2015-04-10 10:02:00 +02:00
Julio J. García Martín 65d1fc2134 Merge pull request #117 from Zentyal/ejhernandez/oc-debug
oc: Use new OC_DEBUG macro
2015-04-10 10:01:18 +02:00
Francis Lachapelle cdc74e4984 Update translations 2015-04-09 09:06:19 -04:00
Ludovic Marcotte 1e4596ca3a (fix) fixed serialization of PreventInvitationsWhitelist 2015-04-08 14:20:33 -04:00
Francis Lachapelle 755efa789b [fix] initial loading of inbox uids and headers 2015-04-08 12:07:28 -04:00
Francis Lachapelle eae327ca19 [fix] Paragraph margins in HTML message
Fixes #3163
2015-04-07 08:27:30 -04:00
Francis Lachapelle 01857a9a47 [fix] Timezone of MS Exchange freebusy information 2015-04-02 11:53:03 -04:00
Francis Lachapelle e2c3259b16 [fix] Issues with freebusy in attendees editor 2015-04-01 20:10:52 -04:00
Ludovic Marcotte 77917780c8 (fix) packaging issue on RHEL 2015-04-01 08:46:46 -04:00
Ludovic Marcotte 9b320ec2a1 Improvements over 491d7aaffc 2015-03-31 16:17:21 -04:00
Ludovic Marcotte b2d7eb40c2 (fix) fixed a potential EAS error with multiple email priority flags 2015-03-31 16:13:52 -04:00
Francis Lachapelle ab121e6c15 [fix] Issues with freebusy in attendees editor 2015-03-31 15:19:53 -04:00
Ludovic Marcotte 94d546dc7a (feat) added systemd startup script (PR#76) 2015-03-31 13:42:59 -04:00
extrafu 2082acc1aa Merge pull request #76 from peruchi/master
Change script start sogod for systemd
2015-03-31 13:40:42 -04:00
peruchi 06ef3fe856 Delete sogo-systemd-redhat.spec 2015-03-31 14:37:35 -03:00
peruchi c9ec636a53 Update sogo.spec 2015-03-31 14:36:04 -03:00
peruchi 36a70b161c Create sogo-systemd-redhat 2015-03-31 14:19:16 -03:00
peruchi 784f0100e9 Create sogo-systemd-redhat.spec 2015-03-31 14:18:23 -03:00
Ludovic Marcotte db9536adcc (fix) fix yet an other potential crash during freebusy lookups during timezone changes 2015-03-31 09:25:57 -04:00
Ludovic Marcotte c428ac2553 EAS reply fix when message/rfc822 parts are included in the original mail (#3153) 2015-03-30 09:57:27 -04:00
Ludovic Marcotte f5607b3e85 now keep the BodyPreference for future EAS use and default to MIME if none set (#3146) 2015-03-30 09:49:44 -04:00
Ludovic Marcotte 491d7aaffc improved multipart handling using EAS 2015-03-30 09:42:32 -04:00
Enrique J. Hernández Blasco 95a8a9316a oc: Use new OC_DEBUG macro
Avoiding the usage of __FUNCTION__ and __LINE__
and more related with the logging system is being in place
for OpenChange.

As well as set the proper level to some debug messages.
2015-03-27 11:12:40 +01:00
Enrique J. Hernández Blasco 1ee47b1ee2 oc: return last modified messages when sorted by PidMessageTagDeliveryTime
This change is required as oxcfxics is asking for sorting
using this property.

We fake this property on GCS folders (Tasks, Calendar, Contacts)
using c_lastmodified column.
2015-03-27 10:27:16 +01:00
Enrique J. Hernández Blasco dfde498b7c oc-mail: Include Deleted flagged messages on syncing cache
This gives an accurate value for SyncLastDeletedMessage
2015-03-26 22:45:13 +01:00
Enrique J. Hernández Blasco 06476abdf7 oc-mail: return soft-deleted mails while syncing
As well as hard deleted

As explained in [MS-OXCFXICS] Section 2.2.1.3.1, the
property MetaTagIdsetDeleted must include both types
of messages and this idset is filled with the return
value of this message.
2015-03-26 22:05:43 +01:00
Jesús García Sáez bb0221c763 Merge pull request #115 from Zentyal/ejhernandez/sharing-flavour-val-idl
oc-mail: Update place for Sharing Flavour prop values
2015-03-26 19:45:24 +01:00
Jesús García Sáez dc869ce106 oc-mail: Support for PidTagTransportMessageHeaders property
This property is needed to show the 'Internet Headers' in Outlook.
Outlook 2010 shows them in the properties dialog of a message.
Outlook 2007 show them in message options section from context menu
of a mail message.

The property is defined in [MS-OXOMSG] section 2.2.1.61.

The property is formed concatenating the mail message headers
properly mime encoded.

The headers are appended in no defined order.
2015-03-26 19:26:48 +01:00
Ludovic Marcotte ddcae9f132 Updates for the release 2015-03-26 13:57:58 -04:00
Ludovic Marcotte f11bcd3373 Avoid using stringByReplacing... since old runtimes don't support it 2015-03-26 13:54:17 -04:00
Enrique J. Hernández Blasco a47f1de607 oc-mail: Update place for Sharing Flavour prop values
It has been moved in OpenChange
2015-03-26 14:18:34 +01:00
Jesús García Sáez 09aed26f10 Merge pull request #114 from Zentyal/ejhernandez/fix-interleaving-creating-folder
As it happened with dba17fb if we interleave requests
from different users while creating a folder we can
create the folder in other user's mailbox as latest
activeUser is the one from latest sogo_context_get_root_folder
call.

This is for me a lack of right design and a workaround
only fixing this issue but not the root cause.
2015-03-25 17:15:05 +01:00
Jesús García Sáez 0e5de2df42 Merge pull request #110 from Zentyal/ejhernandez/sharing-calendar-request
This requires https://github.com/openchange/openchange/pull/244 to work
but basically we have modified this backend to store request-related
properties in a `MAPIStoreMailMessage` using the versions message
from the `MAPIStoreMailFolder` container and fix the setter/getter
for the following properties:

  * PidNameXSharingFlavor
  * PidLidSharingFlavor
  * PidNameXSharingCapabilities
  * PidLidSharingResponseType
  * PidLidSharingResponseTime
2015-03-25 17:09:14 +01:00
Enrique J. Hernández Blasco 82fb03b67b oc-mail: Ensure we are creating folder to the right user
As it happened with dba17fb if we interleave requests
from different users while creating a folder we can
create the folder in other user's mailbox as latest
activeUser is the one from latest sogo_context_get_root_folder
call.

This is for me a lack of right design and a workaround
only fixing this issue but not the root cause.
2015-03-25 16:53:42 +01:00
Enrique J. Hernández Blasco f9c8661fe6 oc-mail: Use constant names in props value
This gives to the developer more information about
the property values for PidLidSharingFlavor and
PidLidSharingCapabilities.
2015-03-25 10:12:15 +01:00
Enrique J. Hernández Blasco 661b6694af oc-mail: Fix several sharing properties managing
* PidNameXSharingFlavor is used by Outlook 2010 so we have
  to store it
* 0x5100 is used although it is not in spec as Sharing Flavour
  value when the request is denied from a message where
  Request + Invitation was sent.
* Return properly PidNameXSharingCapabilities and PidNameXSharingFlavor
  as it is an string representation of a hex number
* Try to guess proper sharing flavour value when it is missing
2015-03-25 10:12:15 +01:00
Enrique J. Hernández Blasco 514b1c03be oc-mail: Store request properties
Save them in extra properties from folder container.

This is required because the client once a request is accepted
or denied sets these two properties and save the message again.
As we cannot modify an IMAP message, we use this utility.

See [MS-OXSHARE] Section 3.1.4.3 for details.
2015-03-25 10:12:15 +01:00
Enrique J. Hernández Blasco a663fdd260 oc-mail: Give support to store extra properties in versions message
This is handy when you want to store properties once a mail
has hit the server and thus cannot be changed.
2015-03-25 10:12:15 +01:00
Jesús García Sáez 0db16aedb1 Merge pull request #112 from Zentyal/ejhernandez/fix-crash-invalid-ics
A failure in parsing an ICS makes return a nil calendar
object. Instead of creating an appointment with nil
information which can lead to crashes like the one
generated creating PidLidCleanGlobalObjectId property.

We return an empty message with no information which is
taken into account in Outlook but not displayed like
in SOGo webmail does.
2015-03-24 19:15:05 +01:00
Jesús García Sáez 6f70066986 Merge pull request #109 from Zentyal/ejhernandez/empty-acl-perms
The `[SOGoFolder:aclUsers]` returns a reference to a `NSArray`
which is being modified in the `for` loop making fail when
more than one user is in the ACL with `NSRangeException`.
2015-03-24 17:40:37 +01:00
Ludovic Marcotte b933f53fc2 Changes for the 2.2.17 release 2015-03-24 10:56:26 -04:00
Ludovic Marcotte 097d5c2333 now possible to configure objectClass names for LDAP groups using GroupObjectClasses (#1499) 2015-03-24 08:40:13 -04:00
Ludovic Marcotte d75fb0722a Code cleanups 2015-03-24 08:34:29 -04:00
Enrique J. Hernández Blasco 6204aebf2c oc-calendar: do not crash with invalid events
A failure in parsing an ICS makes return a nil calendar
object. Instead of creating an appointment with nil
information which can lead to crashes like the one
generated creating PidLidCleanGlobalObjectId property.

We return an empty message with no information which is
taken into account in Outlook but not displayed like
in SOGo webmail does.
2015-03-23 23:57:33 +01:00
Francis Lachapelle 26d876e67a Improve event attendees editor
- Avoid repetitive AJAX queries;
- Improve handling of daylight changes.
2015-03-23 17:54:05 -04:00
Ludovic Marcotte cc3652b59b improvements to EAS SyncKey handling to avoid missing mails (#3048, #3058) 2015-03-23 17:23:29 -04:00
Ludovic Marcotte 9d7bbbc312 enable by default HTML mails support using EAS on Windows and BB phones 2015-03-23 14:55:14 -04:00
Ludovic Marcotte d2915add6d now favor login@domain as the default email address if multiple mail: fields are specified 2015-03-23 14:08:31 -04:00
Ludovic Marcotte 67139ce3e3 improved GetItemEstimate to count all vasnished/deleted mails too 2015-03-23 11:35:45 -04:00
Ludovic Marcotte 9eb138b867 prevent potential freebusy lookup crashes during timezone changes with repetitive events 2015-03-23 10:54:36 -04:00
Ludovic Marcotte baf3d1f986 immediately delete mails from EAS clients when they are marked as deleted on the IMAP server 2015-03-20 09:10:49 -04:00
Ludovic Marcotte ecd336fa5c Fix compilation warning and error 2015-03-20 08:51:35 -04:00
Ludovic Marcotte afd73289d1 properly fallback over EAS to UTF-8 and then Latin1 for messages w/o charset (#3103) 2015-03-20 08:45:42 -04:00
Ludovic Marcotte bff21ab1ff support for mail prority using EAS 2015-03-19 16:08:33 -04:00
Ludovic Marcotte 6d99226b13 Always add DisplayName no matter EAS client version 2015-03-19 14:53:01 -04:00
Francis Lachapelle 69974807b5 Fix Language-Region tags in Web interface
Fixes #3121
2015-03-19 08:35:10 -04:00
Enrique J. Hernández Blasco 8ee2303e78 oc: Empty ACL from a folder works with several users
The `[SOGoFolder:aclUsers]` returns a reference to a `NSArray`
which is being modified in the `for` loop making fail when
more than one user is in the ACL with `NSRangeException`.
2015-03-19 00:06:14 +01:00
Enrique J. Hernández 7bc8cd58dd Merge pull request #108 from Zentyal/jacalvo/fix-optional-attendees
oc-calendar: Fix event invitations for optional attendees
2015-03-18 21:34:51 +01:00
José Antonio Calvo 2668bc313c oc-calendar: Fix event invitations for optional attendees
Outlook sets recipient type of Required attendees as MAPI_TO and
optional ones as MAPI_CC, so the fix is just to not only iterate
over the "to" list of recipients but also the "cc" one. We're
also setting the proper iCal value for this case (OPT-PARTICIPANT
instead of REQ-PARTICIPANT)

In [MS-OXOCAL] Section 2.2.4.10.7 says the recipient type is 0x01
as Required and 0x02 as Optional and other documents such as
[MS-OXCMSG] 2.2.3.1.2 indicates that MAPI_TO is 0x01 and MAPI_CC
is 0x02, that's why is stored in 'to' and 'cc' respectively.
2015-03-18 18:18:46 +01:00
Jesús García Sáez 418ac15de6 Merge pull request #107 from Zentyal/jgarcia/rtf-no-color-table
oc-rtf: no color table definition
2015-03-18 18:08:05 +01:00
Jesús García Sáez 637ac1e98a oc-rtf: no color table definition
Be able to parse rtf files without color table defined
\colortbl
2015-03-18 18:06:49 +01:00
Jesús García Sáez b0ba6f4a22 Merge pull request #101 from Zentyal/ejhernandez/recurrence-exceptions-fixes
Two fixes on recurring events
2015-03-18 18:05:06 +01:00
Ludovic Marcotte cdb766e2ef Documented NGMimeBuildMimeTempDirectory 2015-03-18 10:15:33 -04:00
Enrique J. Hernández Blasco fb4c3a4730 oc-calendar: Fix weekly recurring events exported to Outlook from SOGo
SOGo does not create BYDAY mask in weekly recurrence, so
we have to guess it from the start date's day of week.

In other case, the event is not exported to Outlook and it
says that is corrupted.
2015-03-18 15:08:24 +01:00
Enrique J. Hernández Blasco 6f44ec42c1 oc-calendar: Fix import in SOGo exceptions from recurring series
According to [MS-OXICAL] Section 2.1.3.1.1.20.13, the EXDATE property
must be written only if there are ocurrences from the series that have
been deleted and before this commit ModifiedInstanceDates were also
included.

We check against every ExceptionInfo from exception ocurrences of the series
to know if the ocurrence was deleted or only modified.
2015-03-18 15:08:24 +01:00
Ludovic Marcotte e25a7e3d8d Fix for bug #3138 2015-03-18 09:36:35 -04:00
Julio García 3b0b43f28f Merge branch 'ejhernandez/peek-preload-bodies-for-real' 2015-03-18 09:28:57 +01:00
Julio García afa9061f2f Merge branch 'ejhernandez/client-drafts-no-updated' 2015-03-18 09:22:41 +01:00
Enrique J. Hernández Blasco 9f3f2aebe4 oc-mail: Register source message as soft deleted on movement
This makes sent mails are not longer automatically copied
to Drafts folder.

Reasoning:

When Outlook sends a mail, OpenChange submits the message and
copy the message to Drafts folder. Afterwards, the client asks
to move this message using SyncImportMessageMove ROP from
Drafts to Sent. During this movement, the message is unregistered
from the indexing database. If the client has updated Drafts
folder before that movement, then the client will keep this
message as the MID is not returned in oxcfxics download sync
as deleted. Setting the message as soft deleted, make it work.
2015-03-18 00:42:01 +01:00
Francis Lachapelle 1d5ae27c99 Fix issues with freebusy (Web, busyOffHours) 2015-03-17 15:34:00 -04:00
Julio García 0be36df211 Preparing release for 2.2.15-zentyal2 2015-03-17 12:30:09 +01:00
Francis Lachapelle beb57707e8 Merge pull request #72 from JensErat/export-not-archive
Rename "Archive" to "Export" in Webmail, ctd.
2015-03-13 10:15:30 -04:00
Jens Erat 1bdd5dfc90 Remove obsolete archive string from translations 2015-03-13 14:06:58 +01:00
Enrique J. Hernández 43debc1d70 Merge pull request #102 from Zentyal/jgarcia/rtf-safe-parsing
oc-rtf: safe parse ignoring content
2015-03-13 12:46:38 +01:00
Jens Erat 37fbd75d55 Rename "Archive" to "Export" in Webmail, ctd.
Fixes #2758 also for non-Inbox folders
2015-03-13 11:41:07 +01:00
Enrique J. Hernández Blasco 1c1a75d2c1 oc-mail: Use body.peek to preload message bodies
In this way, we do not modify the flags (\Seen) on preloading.
The IMAP server returns the content without .peek section so
it is removed.

This also performs the modification intended by the following
Pull Request:

https://github.com/Zentyal/sogo/pull/50

That tried to avoid set \Seen flag when preloading message bodies
on synchronisation. But in this case we are not incrementing the
modseq as we are not modifying any messages flags.
2015-03-13 10:54:57 +01:00
Enrique J. Hernández Blasco f048860729 Revert "oc-mailfolder: Avoid setting seen flag on preloading message bodies"
This reverts commit 7e0cddc06b.
2015-03-13 00:00:40 +01:00
Enrique J. Hernández Blasco 6d6053865f Revert "oc-mailfolder: Get seen flag directly from message in preloading"
This reverts commit d076e04ad4.
2015-03-13 00:00:29 +01:00
Jesús García Sáez 6e00274988 oc-rtf: safe parse ignoring content
Be able to parse safely \*\xxxxx control words with \binXXXX
elements inside it (before final })
2015-03-12 17:13:17 +01:00
Jesús García Sáez 307fe90854 Merge pull request #99 from Zentyal/ejhernandez/corner-cases-import-PST
oc-mail: Set sender on email messages without an orig recipient
2015-03-11 13:08:33 +01:00
Jesús García Sáez 8031f066dc Merge pull request #98 from Zentyal/ejhernandez/calendar-sharing-invitation
Give support to calendar sharing invitation
2015-03-11 13:07:36 +01:00
Francis Lachapelle f1fda8bd06 Return a single phone number in JSON contacts list 2015-03-10 13:27:17 -04:00
Francis Lachapelle 517f4b0f49 Fix possible JS exception in Contacts module 2015-03-09 14:04:21 -04:00
Enrique J. Hernández Blasco 2b54897d29 oc-sharing: Guess PidLidSharingFlavor from other props
When it is not set by the client on the first place.

See [MS-OXSHARE] Section 2.2.2.5 for details on returned values.
2015-03-05 00:05:02 +01:00
Enrique J. Hernández Blasco ae7ac1be29 oc-mail: Return sharing properties on sharing object mail message
When it is asked for available properties for an specific message.
2015-03-05 00:02:19 +01:00
Enrique J. Hernández Blasco 6af8b486df oc-mail: Return special properties on sharing_metadata.xml attachment
As required by [MS-OXWSMSHR] Section 3.1.1 to display the share
object message correctly and be able to open the shared calendar
directly from the message.
2015-03-04 18:49:31 +01:00
Enrique J. Hernández Blasco 316ade13f8 oc: Implement Sharing Message Object
It acts as a proxy of MAPIStoreMailMessage and it manages the properties
defined in [MS-OXSHARE] Section 2.2 by storing them in the mail message
as eXtensible MIME headers which starts with X-MS-Sharing.
2015-03-04 18:49:17 +01:00
Francis Lachapelle cbba0719bb Fix exception in SOGoUserManager 2015-03-04 10:05:12 -05:00
Jesús García Sáez c4566c4773 Merge pull request #95 from Zentyal/free-header-encoding
Free headerEncoding variable when destroying parent
2015-03-04 10:51:14 +01:00
Carlos Pérez-Aradros Herce 3b2cbb945c oc: Free headerEncoding variable 2015-03-04 10:10:32 +01:00
Francis Lachapelle 8e0849029e Fix contacts lookup by UID
When looking for a specific contact UID, we no longer match a pattern
that could return multiple results. We search for the exact UID only.
2015-03-03 21:26:09 -05:00
Francis Lachapelle 6192322513 Fix some gcc warnings 2015-03-03 21:23:19 -05:00
Enrique J. Hernández Blasco 44dfd35521 oc-mail: Set sender on email messages without an orig recipient
But it has recipients. This is for sure happening with event
invitations messages.
2015-03-03 22:52:42 +01:00
Enrique J. Hernández Blasco 575600cabc oc-calendar: Return PidTagContainerClass for Calendar folders
And it must "IPF.Appointment" as described in [MS-OXOCAL] Section 2.2.11.1
2015-03-03 17:47:37 +01:00
Enrique J. Hernández acc2bd0369 Merge pull request #97 from Zentyal/jjgarcia/update-news
Update news for next release
2015-03-03 16:08:31 +01:00
Julio García cd47c926c9 Update news for next release 2015-03-03 11:16:01 +01:00
Julio J. García Martín 9b038db0b6 Merge pull request #93 from Zentyal/jvalles/missing-contact-props
Save missing contact properties in database
2015-03-02 09:17:15 +01:00
Julio J. García Martín bcc1aa8049 Merge pull request #89 from Zentyal/jag/set-null-recurrence-pattern
In setupRecurrenceWithMasterEntit a null recurrence pattern is now inter...
2015-03-02 09:16:38 +01:00
Javier Amor García ef6aab63c9 oc-calendar: Don't change event recurrence if parse failed.
get_AppointmentRecurrencePattern() can fail to parse the input data, added a check to avoid setup the recurrence pattern in that case. This should only happen when input data is incorrect.
2015-02-27 17:32:22 +01:00
Ludovic Marcotte df59b73a22 use correct mail attachment elements for EAS 2.5 clients - patch from tfu 2015-02-26 17:56:42 -05:00
Ludovic Marcotte a5672fda52 do not use syncKey from cache when davCollectionTag = -1 - patch from tfu 2015-02-26 17:55:36 -05:00
Ludovic Marcotte b593ddc643 SmartReply improvements for missing body attributes - patch from tfu 2015-02-26 17:53:58 -05:00
Ludovic Marcotte 38d61f720f use the correct body element for events for EAS 2.5 clients - patch from tfu 2015-02-26 17:52:37 -05:00
Ludovic Marcotte 733e334726 fixed tasks disappearing issue with RoadSync - patch from tfu 2015-02-26 17:51:02 -05:00
Ludovic Marcotte 22888ba5ac use the correct mail body element for EAS 2.5 clients - patch from tfu 2015-02-26 17:49:26 -05:00
Ludovic Marcotte 33c485d2f6 fixed empty sync responses for EAS 2.5 and 12.0 clients - patch from tfu 2015-02-26 17:48:06 -05:00
Ludovic Marcotte 9160e34134 multiple collections support for GetItemEstimate - patch from tfu 2015-02-26 17:46:34 -05:00
Ludovic Marcotte 5ceddc213e Fix for bug #3116 2015-02-26 16:00:03 -05:00
Jesús García Sáez 85d9440ccd Merge pull request #94 from Zentyal/jgarcia/reset-password
Fix change password with multidomains
2015-02-26 10:48:58 +01:00
Ludovic Marcotte b97002565e Updated NEWS file regarding previous commit 2015-02-25 08:42:18 -05:00
extrafu 03b6a8a028 Merge pull request #70 from Zentyal/jgarcia/reset-password-sogo
Fix change password with DomainBasedUID
2015-02-25 08:41:05 -05:00
Jesús García Sáez 22196e0054 Fix change password with DomainBasedUID
When users use full domain to login (SOGoEnableDomainBasedUID) the
user attributes in the cache were not being properly updated because
in this case the key is `uid@domain` instead of just `uid`.
2015-02-25 12:42:03 +01:00
Jesús García Sáez 8d21bc3e36 Fix change password with DomainBasedUID
When users use full domain to login (SOGoEnableDomainBasedUID) the
user attributes in the cache were not being properly updated because
in this case the key is `uid@domain` instead of just `uid`.
2015-02-25 12:39:01 +01:00
Juan Vallés 4c3c741d9f oc-contacts: Save missing contact properties in database 2015-02-25 11:59:24 +01:00
Jesús García Sáez 731934f061 oc: Add fai properties for custom views
Without this outlook clients with custom views set on folders will
crash because this are needed properties and were not being saved
2015-02-24 17:44:56 +01:00
Jesús García Sáez b645b4187d Merge pull request #88 from Zentyal/ejhernandez/add-categories-calendar-events
oc-calendar: Implement categories to share the colour
2015-02-24 14:23:36 +01:00
Enrique J. Hernández Blasco 9b847a276c oc-calendar: Implement categories to share the colour
See [MS-OXCICAL] Section 2.1.3.1.1.20.3 for details.

It requires https://github.com/openchange/openchange/pull/216 to retrieve
the value from MAPI client
2015-02-17 10:20:16 +01:00
Jesús García Sáez 68216a7456 Merge pull request #87 from Zentyal/ejhernandez/fixes-on-calendar-props
Calendar: PidTagSensitivity and PidTagImportance now works in Outlook
2015-02-16 11:00:45 +01:00
Enrique J. Hernández Blasco 624967c60b oc-calendar: Implement PidTagSensitivity
As described in [MS-OXCICAL] Section 2.1.3.11.20.4 by using
access CLASS iCal field.

Although Outlook does not support confidential level, it is properly
exported and imported.
2015-02-15 18:44:47 +01:00
Enrique J. Hernández Blasco e6ba15bbae oc-calendar: PidTagImportance and PidTagNormalizedSubject working
It wasn't being called because the proxy (AppointmentWrapper) is not
being called as there is a base implementation for these properties
in MAPIStoreMessage making them impossible to be shared between
Outlook profiles.
2015-02-15 18:41:03 +01:00
Enrique J. Hernández Blasco 2a1b363fee oc-calendar: Proper getter for AppointmentWrapper proxy object
Do not assume it is in 0 position any longer
2015-02-15 18:39:43 +01:00
Enrique J. Hernández Blasco eaec3c0610 oc-calendar: Remove useless method
Better off implemented by AppointmentWrapper proxy
2015-02-15 18:38:59 +01:00
Enrique J. Hernández Blasco d3a4b497c6 oc-calendar: Remove commented code
Available at MAPIStoreAppointmentWrapper class
2015-02-15 18:34:28 +01:00
Ludovic Marcotte b26ea30b1b Update ChangeLog 2015-02-12 11:06:57 -05:00
Ludovic Marcotte 72b210cd2e Fixed typo 2015-02-12 10:29:46 -05:00
Ludovic Marcotte a80d75d09c Preparation for the release 2015-02-12 10:27:10 -05:00
Ludovic Marcotte aae76dc4e6 Limit curl request for webcalendars to 60 seconds 2015-02-12 09:57:10 -05:00
Francis Lachapelle c20ca0e33d Fix exception in set operation of sogo-tool 2015-02-12 09:29:40 -05:00
Francis Lachapelle 601a9ca559 Update translations 2015-02-12 09:09:18 -05:00
Ludovic Marcotte d7c283f751 improved fetching of text parts over EAS 2015-02-12 08:49:17 -05:00
Ludovic Marcotte f3325b8b0d Updated NEWS file wrt fixes 2015-02-11 18:13:36 -05:00
Ludovic Marcotte b4ea4d7e9f Improvement over previous commit 2015-02-11 14:39:57 -05:00
Ludovic Marcotte 9447437d6f Added missing strings from previous commit 2015-02-11 14:33:32 -05:00
Ludovic Marcotte 322f72626a now possible to limit automatic forwards to internal/external domains 2015-02-11 14:30:40 -05:00
Ludovic Marcotte 55ae4cb8c0 First pass at EAS' best practices for SOGo 2015-02-11 12:59:04 -05:00
Ludovic Marcotte e5d01428ad now possible for SOGo to change the sambaNTPassword/sambaLMPassword 2015-02-11 11:31:35 -05:00
Jesús García Sáez 7406fc3772 Merge pull request #83 from Zentyal/ejhernandez/move-subfolder-to-root
Move subfolder (Mail, Journal, Notes) to root
2015-02-11 15:29:26 +01:00
Ludovic Marcotte 82178fd6ce Initial patch from tfu for bug #3055 2015-02-11 08:31:32 -05:00
Jesús García Sáez efe2070227 Merge pull request #85 from Zentyal/ejhernandez/dlinklist-samba
oc: Use dlinklist from samba for now
2015-02-11 10:05:51 +01:00
Enrique J. Hernández Blasco 68ebc9e0ff oc: Use dlinklist from samba for now
Due to https://github.com/openchange/openchange/pull/204.

Until it is published by OC or dismissed.
2015-02-10 23:37:40 +01:00
Ludovic Marcotte 6cf1ec998e Updated NEWS file for the #3095 bug fix in SOPE 2015-02-10 07:09:31 -05:00
Ludovic Marcotte 6c9b1a494f Fix for bug #2332 2015-02-09 16:12:59 -05:00
Ludovic Marcotte 98e4c8ca55 Fixed doc regarder domain vs. system settings 2015-02-09 09:10:55 -05:00
Julio J. García Martín 1178bf2d60 Merge pull request #84 from Zentyal/ejhernandez/fix-send-mail-sope-2.2.15
Fix send mail with sope 2.2.15
2015-02-09 13:41:29 +01:00
Enrique J. Hernández Blasco 96986812f4 oc-mail: Set content type for a message after upgrading sope 2.2.15
Now that message headers can be set dynamically, we can
set the body-related headers using `setHeader` selector.

This fixes emails sent using this sope version are all in plain text.
2015-02-07 00:22:45 +01:00
Enrique J. Hernández Blasco 142deeb5f0 oc: Implement move a DB subfolder to root
DB folders are Notes and Fallback (Journal, InfoPath Form and Deleted Items).

By moving the DB path and update the indexing DB.
2015-02-05 23:49:59 +01:00
Enrique J. Hernández Blasco dc8012e3d3 oc-mail: Implement move a mail subfolder to root
By moving at IMAP level the mailbox and update the indexing DB
and local db path.
2015-02-05 23:48:46 +01:00
Ludovic Marcotte 3731819e15 Added patch from tfu for #2995 2015-02-05 16:21:27 -05:00
Ludovic Marcotte eca22caefc Fix for bug #3078 2015-02-05 11:14:53 -05:00
Ludovic Marcotte 923bcf8ae2 Applied patch for #3092 2015-02-05 09:29:29 -05:00
Francis Lachapelle 0b44fa81f4 Update NEWS file 2015-02-03 13:20:57 -05:00
Francis Lachapelle 776b17ff20 Fix mail editor when not called from mail module
Fixes #3088
2015-02-03 12:06:28 -05:00
Julio García 12b159a6c0 Merge branch 'master-upstream' into jjgarcia/merge-from-upstream 2015-02-02 12:53:49 +01:00
Ludovic Marcotte 2aa528dacc Preparation for the release 2015-01-30 11:08:43 -05:00
Francis Lachapelle d1d3980919 Update translations 2015-01-30 11:03:38 -05:00
Ludovic Marcotte cf35eec1f5 Improved the NEWS file for the release 2015-01-30 10:28:45 -05:00
Ludovic Marcotte 58a0b0c173 Updated for the release 2015-01-30 10:23:04 -05:00
Ludovic Marcotte 723a9d4e08 Reverted bug fix from #3054 and added comment 2015-01-29 16:21:06 -05:00
Francis Lachapelle 4cc158043e Improve CSS server-side cleaner
Fixes #3040
2015-01-28 16:38:27 -05:00
Ludovic Marcotte 7fd1564a86 fix for #3076 2015-01-28 15:16:21 -05:00
Ludovic Marcotte 981c718d22 improved handling of EAS Push when no heartbeat is provided 2015-01-28 15:03:49 -05:00
Jesús García Sáez 6cfa6b9952 Merge pull request #82 from Zentyal/jgarcia/appointments-alarms
oc-appointments: ignore alarms already triggered
2015-01-28 18:57:36 +01:00
Jesús García Sáez 0a198ccb05 Merge pull request #81 from Zentyal/ejhernandez/fix-move-db-folder
oc: Set right container in dbFolder when moving a folder
2015-01-28 16:34:27 +01:00
Jesús García Sáez 5258ee2e76 oc-appointments: ignore alarms already triggered 2015-01-28 12:56:27 +01:00
Jesús García Sáez d5ec25ee62 Merge pull request #79 from Zentyal/ejhernandez/fix-sync-move-between-different-folder-types
oc: Move back and forth folders now are in sync
2015-01-28 12:05:53 +01:00
Enrique J. Hernández Blasco 57d591c427 oc: Set right container in dbFolder when moving a folder
The path attribute from SOGoCacheGCSFolder is properly updated
in the database but not when returning from path message as
the container is the old one.
2015-01-28 11:26:56 +01:00
Enrique J. Hernández Blasco b01de763da oc: Move back and forth folders now are in sync
Two different indexing entries were created on move operation making
impossible to restore old folder position in the original parent folder.
This was due to cleanupCaches message calls to objectId which requires
to have the indexing entry available.

Use case:

  * Restore a folder from "Deleted items" folders
2015-01-27 18:27:11 +01:00
Enrique J. Hernández 2dcb8fa732 Merge pull request #75 from Zentyal/ejhernandez/move-mail-folder-with-reserved-chars
oc-mail: Move mail folders with reserved chars
2015-01-26 23:39:15 +01:00
Jesús García Sáez 6ce4cc1919 Merge pull request #78 from Zentyal/jgarcia/sync-deleted-messages
Sync deleted messages
2015-01-26 18:03:54 +01:00
Enrique J. Hernández Blasco 0e8bf0d239 oc-mail: Move mail folders with reserved chars
The URL was incorrectly set when any of ;/?:@&=+$,# was used
in the folder name.

We have to mimetise what it is done in createFolder message selector.
That is, perform the IMAP4 encoding + URL encoding without CSS
encoding. The IMAP4 + CSS encoding (without URL encoding) is used to store the folder
in SOGo and OpenChange Indexing database as we do right now.
2015-01-26 15:55:22 +01:00
Ludovic Marcotte 086361b79a Avoid GNUstep warnings 2015-01-23 16:16:36 -05:00
Ludovic Marcotte ab12c84887 More NSLog usage cleanups 2015-01-23 15:32:22 -05:00
Jesús García Sáez 312084243b oc: improve modseqFromMessageChangeNumber to return an approximation.
Only for scenarios where we hadn't store the cn <-> modseq relationship
2015-01-23 18:19:24 +01:00
Jesús García Sáez 47be392d4f oc: avoid request change number until necessary
Minor changenumber leak, but avoid it anyway
2015-01-23 18:18:25 +01:00
Jesús García Sáez 34efcfee4e oc: synchroniseCache store modseq for last delete change number.
This will be the more frequent change number used to obtain updates
on the folder related with deleted messages
2015-01-23 18:17:45 +01:00
Jesús García Sáez 8e7f6d1aec oc: avoid change number leaking when refreshing folder.
Everytime a folder where its last operation was delete some email was
requesting change numbers that were not used.
2015-01-23 18:15:44 +01:00
Ludovic Marcotte e2bee23021 Avoid unnecessary calls to NSLog 2015-01-22 16:25:16 -05:00
Ludovic Marcotte 1a10599369 Removed unnecessary NSLog calls 2015-01-22 15:39:57 -05:00
Ludovic Marcotte d907d5d268 Avoid using NSLog() where we can 2015-01-22 13:31:31 -05:00
Jesús García Sáez 7014d94937 Merge pull request #74 from Zentyal/ejhernandez/delete-folder-on-moving
oc: Remove a source folder on move folder operation
2015-01-22 17:06:13 +01:00
Enrique J. Hernández Blasco 99a36be034 oc: Remove a source folder on move folder operation
Calling deleteFolder message to actually remove it from DB/IMAP
depending on the class.
2015-01-21 12:44:31 +01:00
Jesús García Sáez 8e41e5d665 Merge pull request #71 from Zentyal/ejhernandez/filetime-utc
Use PT_SYSTIME as absolute timestamp
2015-01-20 16:54:56 +01:00
Jesús García Sáez b1dfe47f01 Merge pull request #70 from Zentyal/jgarcia/working-encoding-parse
Outlook can view mails with non-ascii characters in their body (II)
2015-01-20 14:36:50 +01:00
Jesús García Sáez 014632fddb Merge pull request #72 from Zentyal/ejhernandez/wedding-anniversary
oc-contacts: Implement Wedding Anniversary
2015-01-20 14:36:14 +01:00
Enrique J. Hernández Blasco 8b44c08a32 oc-calendar: Remove unnecessary shifts on start,end and replace time props
As the data is sent in UTC, no shifts are longer required.
2015-01-20 14:35:32 +01:00
Enrique J. Hernández Blasco c893963da5 oc-tasks: Set right start, due and complete dates
As explained in [MS-OXOTASK], we have to shift the given date
to store the right point in time with the correct timezone.
2015-01-20 14:35:32 +01:00
Enrique J. Hernández Blasco c6b976a830 oc-mail: Remove unnecessary time shift in date for new mails
The MIME type can store the date in UTC and the clients are
responsible on showing correctly to the client as it does.
2015-01-20 14:35:32 +01:00
Enrique J. Hernández Blasco d5d97db8e8 oc: PT_SYSTIME is an absolute timestamp
As the epoch is in UTC timezone, we set this timezone for NSCalendarDate.
2015-01-20 14:35:32 +01:00
Ludovic Marcotte d98ff69fbe Version bumps for the release 2015-01-20 08:35:10 -05:00
Jesús García Sáez 87a91fbdf2 Merge pull request #73 from Zentyal/cperez/sogo-multitenancy
Restore multitenancy changes for OpenChange
2015-01-20 11:09:48 +01:00
Ludovic Marcotte daa7ab87d7 Fix cosmetic change when fetching fb info 2015-01-19 13:54:04 -05:00
Carlos Pérez-Aradros Herce 00cef845b7 Restore multitenancy changes for OpenChange 2015-01-19 19:04:06 +01:00
Jesús García Sáez f9550b9181 oc: several uninitialized variables 2015-01-19 15:35:44 +01:00
Ludovic Marcotte 3e59b1ad6e Improved documentation regarding password policies over LDAP 2015-01-16 12:55:38 -05:00
Ludovic Marcotte e45451a9f9 Improved comments over previous commit 2015-01-16 09:18:37 -05:00
Enrique J. Hernández Blasco b35fee8efc oc-contacts: Implement Wedding Anniversary
As specified by Microsoft using x-ms-anniversary custom vcard element
[MS-OXVCARD] Section 2.1.3.9.6
2015-01-16 01:34:16 +01:00
Ludovic Marcotte e9e3dd5646 fixed timezone calculation on recurring event 2015-01-15 15:29:02 -05:00
Ludovic Marcotte 16c863d89d Fixed potential issue when handling multiple Add/Change/Delete/Fetch EAS commands (#3057) 2015-01-15 11:55:04 -05:00
Jesús García Sáez 7e7d302165 oc: warning if codepage not found from headerCharset 2015-01-15 13:50:26 +01:00
Jesús García Sáez d052356724 oc: encoding names must be case insensitive 2015-01-15 13:27:37 +01:00
Ludovic Marcotte d87056ebfa handle multipart for EAS/ItemOperations 2015-01-12 14:38:55 -05:00
Ludovic Marcotte 135b463e8f Updated the EAS doc 2015-01-12 13:39:06 -05:00
Ludovic Marcotte f4c4f5af62 fixed From's full name over EAS 2015-01-12 09:09:06 -05:00
Ludovic Marcotte 70e45f7843 fixed birthday offset in EAS 2015-01-12 08:40:06 -05:00
Ludovic Marcotte 28e449b050 Updated NEWS file for bugs fixed 2015-01-10 07:55:55 -05:00
Ludovic Marcotte 6b52e9c945 Fix for bug #2960 2015-01-09 09:04:15 -05:00
Ludovic Marcotte 1cfbea69c1 Make sure we always release local pool 2015-01-08 15:56:16 -05:00
Ludovic Marcotte cb9118d869 Moved the pool destruction at the correct location 2015-01-07 09:29:31 -05:00
Francis Lachapelle dd6dd7251c Fix selection of calendar in event/task editors
Fixes #3049
Fixes #3050
2015-01-06 13:59:20 -05:00
Ludovic Marcotte 24c6c8c91d Fix for bug #3054 2015-01-06 10:59:56 -05:00
Ludovic Marcotte b1ac7a0cca MultipleBookingsFieldName can be set to -1 2015-01-05 13:49:28 -05:00
Francis Lachapelle 59e6d6df4a Fix selection of calendar in event/task editors
Fixes #3049
Fixes #3050
2015-01-05 10:21:37 -05:00
Ludovic Marcotte 71ad5de910 Bumped everything for the release 2014-12-30 08:00:41 -05:00
Enrique J. Hernández b5369530f0 Merge pull request #69 from Zentyal/jgarcia/ignore-unhandled-properties
Ignore unhandled properties instead of abort
2014-12-30 12:31:16 +01:00
Ludovic Marcotte ead665de85 fix tz issue when the user one was different from the system one with EAS 2014-12-29 16:19:10 -05:00
Jesús García Sáez 838ae8995f oc: ignore unhandled properties instead of abort
When setting a row with properties not handled right now, ignore them
like they were never there instead of abort()
2014-12-29 19:20:27 +01:00
Ludovic Marcotte a0c1ce8f3b Improved handling of non-existant vs. subscribed folders over EAS 2014-12-29 12:43:20 -05:00
Jesús García Sáez 3ef28b390d Merge pull request #66 from Zentyal/ejhernandez/guessing-recipients-from-import-PST
oc: Guess recipients from some properties while importing PST
2014-12-24 13:16:46 +01:00
Jesús García Sáez 0cd6fe6135 Merge pull request #67 from Zentyal/jgarcia/rtf-with-pict-data
Parse \pict control word with binary data
2014-12-24 13:16:03 +01:00
Ludovic Marcotte 204a62aa6a Improved comments in the code 2014-12-23 10:25:53 -05:00
Ludovic Marcotte 31cffdffd3 Fix freebusy info not always returned 2014-12-23 10:24:16 -05:00
Jesús García Sáez 501ee79766 oc-rtf: fix parse \pict tag with \bin data 2014-12-23 11:14:54 +01:00
Ludovic Marcotte 255bcbe92f Fixed memory leaks in SOGoSyncCacheObject and correctly kill the cache upon each EAS iteration 2014-12-22 19:59:33 -05:00
Ludovic Marcotte 72732879fa Added memory statistics - set SOGoDebugLeaks = YES and call [[self class] memoryStatistics] 2014-12-22 19:32:17 -05:00
Enrique J. Hernández Blasco a56fc93a9a oc: Guess recipients from some properties while importing PST
This is happening when importing a PST file.

From -> PidTagSenderEntryId
To   -> PidTagOriginalDisplayTo
CC   -> PidTagOriginalDisplayCc

The tested EntryID are the local users and OneOffEntries
when the users are not from the directory.

It requires https://github.com/openchange/openchange/pull/175 to work.
2014-12-23 00:59:29 +01:00
Ludovic Marcotte 24a934275f Fix small memory leak incase of errors 2014-12-22 16:12:26 -05:00
Ludovic Marcotte 58f634bffe Cosmetic improvements to the code 2014-12-22 15:26:22 -05:00
Ludovic Marcotte ca4a754f2c Use the right cutoff date 2014-12-22 12:39:58 -05:00
Ludovic Marcotte 8015688df3 Added SOGoMaximumSyncResponseSize to support memory-limited EAS syncs 2014-12-22 11:50:51 -05:00
Ludovic Marcotte b07913d66d See NEWS file 2014-12-22 08:36:55 -05:00
extrafu 6b49a8a341 Merge pull request #68 from Crosenhain/master
Change ACL modification text to non-gender specific terms
2014-12-20 08:29:01 -05:00
Ludovic Marcotte df8a0d8715 Update ChangeLog 2014-12-19 09:03:37 -05:00
Ludovic Marcotte e6cc56dca1 Bumped version to 2.2.12a 2014-12-19 09:03:19 -05:00
Ludovic Marcotte de3d38262b Fix for bug #3034 2014-12-19 09:01:39 -05:00
Chris Rosenhain 0e56527e05 Change ACL modification text to non-gender specific terms 2014-12-19 11:04:05 +10:30
Jesús García Sáez 12cdc60af7 Merge pull request #65 from Zentyal/ejhernandez/fix-folder-other-users
Create child folder objects using parent context for real
2014-12-17 11:53:36 +01:00
Enrique J. Hernández Blasco dba17fbcbc Create child folder objects using parent context for real
We activate the user for the context using the root folder
context as there are times where the active user is not
matching with the one stored in the application context
and SOGo object is storing cached data with the wrong user
leading to create folders in wrong mailboxes, etc.

As this application is single-threaded, no problems are expected.
Indeed, the same code is available at getting the root folder (ie INBOX).
2014-12-16 23:43:57 +01:00
Jesús García Sáez ba79234ceb Merge pull request #64 from Zentyal/ejhernandez/store-change-number-subfolders-cache
Store changeNumber maps with modseq in cache for subfolders
2014-12-03 16:05:51 +01:00
Enrique J. Hernández Blasco 067809ef1c Store changeNumber maps with modseq in cache for subfolders
By getting the root folder/container whose properties
are stored in OpenChange DB.

This makes the synchronisation of sub-folders faster as
when we evaluate restrictions for this folder, we are able
to get the modseq from where to get the latest messages
unseen by the client.
2014-12-01 23:19:38 +01:00
Jesús García Sáez bdf12e5c01 Merge pull request #62 from Zentyal/ejhernandez/fix-space-temporal-crash-setChangeKey
Attempt to sync an UID in setChangeKey to avoid crashing
2014-12-01 19:45:51 +01:00
Jesús García Sáez 97201c56a4 abort if attemp to sync an UID in setChangekey fails 2014-12-01 10:47:16 +01:00
Kamen Mazdrashki 4a6daf45e0 Merge pull request #61 from Zentyal/ejhernandez/memory-leaks
Fix memory leak on getPidTagSubject
2014-11-30 00:58:01 +01:00
Enrique J. Hernández Blasco 7691d616a9 Attempt to sync an UID in setChangeKey to avoid crashing
This may happen if between sync cache and setChangeKey a modSeq
is making synchroniseCache not retrieve the newly stored message.

This should fix the following crash:

https://tracker.zentyal.org/issues/2673
2014-11-29 08:07:41 +01:00
Enrique J. Hernández Blasco 2c6d833c11 Remove an attempt to double free content
As content is freed by resetExceptResult message received by reset
which has been called by dealloc as well
2014-11-28 10:04:18 +01:00
Enrique J. Hernández Blasco f4e15e2db8 Fix memory leak on getPidTagSubject
Valgrind crafted report:

=40967== 128,927 (53,750 direct, 75,177 indirect) bytes in 383 blocks are definitely lost in loss record 10,104 of 10,179
==40967==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==40967==    by 0x86EDE3D: talloc_strndup (talloc.c:613)
==40967==    by 0x34D2BB9E: _i_NSString_MAPIStoreDataTypes_asUnicodeInMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend)
==40967==    by 0x34D2025B: _i_MAPIStoreMailMessage__getPidTagNormalizedSubject_inMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend)
==40967==    by 0x34CFCD40: _i_MAPIStoreObject__getProperty_withTag_inMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend)
==40967==    by 0x34CFBE21: _i_MAPIStoreMessage__getPidTagSubject_inMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend)
==40967==    by 0x34CFBEB6: _i_MAPIStoreMessage__getPidTagOriginalSubject_inMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend)
==40967==    by 0x34CFCD40: _i_MAPIStoreObject__getProperty_withTag_inMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend)
==40967==    by 0x34CFD07E: _i_MAPIStoreObject__getProperties_withTags_andCount_inMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend)
2014-11-28 10:04:10 +01:00
Enrique J. Hernández Blasco a8b716fbaa oc: sync old messages as last resort if there are not in cache
This is happening when the lastModSeq is greater than the modseq
from an old message and that message is not in cache.

This is used as last resort before crashing and it is only used
in objectVersion as it is the first place to call on sync. Other
related properties would work.
2014-11-19 17:16:45 +01:00
Enrique J. Hernández Blasco ef7b919175 Return MAPISTORE_ERR_NOT_FOUND when a mail is indexed but not in IMAP server
And remove that entry from the indexing table.

This avoids to crash getting properties from a no longer available message
in the IMAP server, for instance, the `PidTagPredecessorChangeList` attribute.
2014-11-19 17:12:32 +01:00
Jesús García Sáez 973ab78761 oc: synchronize folders ChangeNumber <-> modseq 2014-11-19 17:12:32 +01:00
Jesús García Sáez c4b0ac209b NSString:objectFromJSONString now can parse single values
Like null => [NSNull null]
2014-11-19 17:12:32 +01:00
Jesús García Sáez 41320a4813 oc: NGImap4Connection:fetchUids changed error messages 2014-11-19 17:12:32 +01:00
Jesús García Sáez c410a9fc3f oc: NGImap4Connection:fetchUids don't delete RawResponse 2014-11-19 17:12:31 +01:00
Jesús García Sáez 24e35103ff oc: monkeypatched NGImap4Connection class from sope
To improve fetchUids method so we can retrieve uids in batches.
Otherwise we will face an error 'too long request' kind
2014-11-19 17:12:31 +01:00
Enrique J. Hernández Blasco 616f2abbb2 Fix compilation when samba file is not others readable
This happens when any smb.conf or included file is not others readable,
thus we are fallbacking to the default installation path.
2014-11-19 17:12:31 +01:00
Enrique J. Hernández Blasco 3910769ae8 oc-folder: Uniform call to deleteMessageWithMID
To make sure flags argument is used accordingly with the specs
and not working by chance.
2014-11-19 17:12:31 +01:00
Enrique J. Hernández Blasco b67e1deda5 oc-folder: Make deleted items synched when shared
By keeping mid on moving messages by soft deleting and
only if srcMid is different from targetMid.

This makes restore/shared deleted items work.

It also requires to do the following to work smoothly:

* Do not add soft-deleted messages in ensureIDsForChildKeys
* Return soft-deleted messages on getDeletedFMIDs
* Do not register a new mid if the URL is matched with soft deleted messages
2014-11-19 17:12:31 +01:00
Enrique J. Hernández Blasco 35ca313c37 oc-calendar: Fix PidLidClipStart on recurrent events
The midnight value must be in user's timezone and returned back in UTC.
2014-11-19 17:12:31 +01:00
Enrique J. Hernández Blasco c631689975 oc-calendar: getPidLidClipEnd now follows [MS-OXOCAL]
On recurrent events when there is no end, the time to set is
31 August 4500, 11:59 P.M ([MS-OXOCAL] Section 2.2.1.15)
2014-11-19 17:12:30 +01:00
Enrique J. Hernández Blasco cd64ca199a oc-calendar: wDay field cannot be negative
Furthermore, [MS-OXOCAL] Section 2.2.1.41.1 indicates:

   The wDay field is set to indicate
   the occurrence of the day of the week within the month
   (1 to 5, where 5 indicates the final occurrence during
   the month if that day of the week does not occur 5 times).

[rule firstOccurrence] may return negative values according to iCal spec for
recurrent rules iCal 4.8.5.4 Recurrence Rule. For instance, for defining
a timezone whose recurrent rule is done using this rule:

   RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU

This fixes the problem when editing a recurrent appointment in
Outlook were incorrectly shifted when SOGo provides back the event.
2014-11-19 17:12:30 +01:00
Enrique J. Hernández Blasco be60fdebcc oc-folder: Flags are now used in indexing db when deleting a msg
Unregistering the URL in indexing db accordingly to the flags (SOFT or HARD)
2014-11-19 17:12:30 +01:00
Enrique J. Hernández Blasco d076e04ad4 oc-mailfolder: Get seen flag directly from message in preloading
To avoid a loop and a server-call.

We are not using body.peek[text] directly because bodyContentPart message
is explicitly avoiding it.
2014-11-19 17:12:30 +01:00
Enrique J. Hernández Blasco 7e0cddc06b oc-mailfolder: Avoid setting seen flag on preloading message bodies
Fetching a body[text] property using IMAP makes IMAP server set seen flag.

This commit fetches the flag beforehand to restore the previous state
once the body has been fetched.
2014-11-19 17:12:30 +01:00
Enrique J. Hernández Blasco 258444bb93 oc-rtf: Be more resilient to spaces while parsing font tables
This avoids to crash on this example:

  \f0\fibi \fcharset0
   -------^

Or:

  \f0 \fibi\fcharset0
   --^

Take into account that I found lots of RTF documents with this format:

  \f0\fbidi \froman\fcharset0
  \f0\froman\fprq2 \fcharset0

Which are not unsupported by this handler.
2014-11-19 17:12:30 +01:00
Enrique J. Hernández Blasco 75ce59d010 oc-rtf: Fix current position to match where _bytes pointer is
This avoids to have extra unknown bytes at the end of the RTF document
as _len would have been reached but _current_pos had incorrect less value.
2014-11-19 17:12:29 +01:00
Enrique J. Hernández Blasco cbfcd54858 oc-rtf: Use what RTF Spec 1.9.1 for control words
This reverts 7581c0a.
2014-11-19 17:12:29 +01:00
Enrique J. Hernández Blasco 415fb6034e oc-calendar: Retrieve properly event description created on SOGo
As it is stored as plain text without triming string.

The correct comparison here is NSNotFound as stated in Apple documentation.
2014-11-19 17:12:29 +01:00
Jesús García Sáez 445a1fb2d6 oc: MailMessages return correct codepage 2014-11-19 17:12:29 +01:00
Enrique J. Hernández Blasco c866bce8e8 Store FreeBusySimple and FreeBusyDetailed rights as roles
Map: FreeBusySimple -> PublicDAndTViewer
     FreeBusyDetailed -> ConfidentialDAndTViewer

Although SOGo is not really used AFAIK, we can now keep it and
keep Calendar permission issues consistent.
2014-11-19 17:12:29 +01:00
Jesús García Sáez ed4ca3bd1b oc: add talloc reference to indexing context
We have a cache with user contexts (objc) which have mapping contexts (objc)
where we store the indexing context (c) which will be freed by openchange
code once the connection is closed.

Right now all indexing context created for an user are the same,
independently when in time was created or by which connection, etc...
So this is a valid workaround, but this has to be refactored to used the
indexing context of the current connection that is performing the
call to SOGo backend.
2014-11-19 17:12:29 +01:00
Jesús García Sáez bb9764bc6b Revert "oc: cached usercontext updates indexing_context"
This reverts commit 0750f64b787db088e944756b66fbd0883cf44cbf.
2014-11-19 17:12:28 +01:00
Jesús García Sáez 05578bfcb6 oc-rtf: control words can also have a space before next tag
This was causing to parse a single space as an empty control
word with length 0, which was the source of several crashes.

Example:

  \f0\fbidi \fcharset0
   --------^

font index is 0, font family is bidi but when parsing charset we were
assuming control word was '' instead of 'charset0'.

This only fixes the crashes, the parseFontTable function works quite
awful right now.
2014-11-19 17:12:28 +01:00
Jesús García Sáez a7c2054cce oc: cached usercontext updates indexing_context
Instead of use always the one given on initialization
2014-11-19 17:12:28 +01:00
Julien Kerihuel 52ad0e0e5b Prevent SOGo backend from crashing when mapistore_set_connection_info is
not called beforehand and connInfo is not initialized.
2014-11-19 17:12:28 +01:00
Kamen Mazdrashki dc8b73b12b oc/MailFolder: Add more logging so we can trace invalid message kyes 2014-11-19 17:12:28 +01:00
Kamen Mazdrashki 18acdf20a6 oc: Make sure we always use NSString keys in 'messages' dictionary
Different types for keys in Dictionaries leads to not finding
expected entry - we should make sure that everythime we set/get
entry from a dictionary, key object type is same
2014-11-19 17:12:27 +01:00
Kamen Mazdrashki 0a23f18fc9 oc: Set log level to 0 in samba-get-config script - it is very chatty during builds
This script is very "chatty" when "log level" is set to a high number
(usual scenario on developer machine)
2014-11-19 17:12:27 +01:00
Kamen Mazdrashki b8366d796d oc/util: Tune dbmsgreader for new caching classes names 2014-11-19 17:12:27 +01:00
Jesús García Sáez 5ee8cb3a3f oc-rtf: check valid font name when generating <font> tag 2014-11-19 17:12:27 +01:00
Jesús García Sáez 4e3a242f2f oc-rtf: Don't crash when we don't know the specified font 2014-11-19 17:12:27 +01:00
Jesús García Sáez 68c38e2b5c openchange: return proper url for folders with non-ascii chars
toManyRelationshipKeysWithNamespaces applies asCSSIdentifier function
to the names which are already "Imap4Encoded". So we need to remove the
CSSIdentifier function first and then "Imap4Decode" to get the real name.

Once we have the real name, to create the url we have to use the same
logic as the function that creates the folder and creates this url for
the first time (this function is createRootSecondaryFolderWithFID)
which is to apply, in this order:

- asCSSIdentifier
- stringByEncodingImap4FolderName
- stringByAddingPercentEscapesUsingEncoding
2014-11-19 17:12:27 +01:00
Jesús García Sáez f1d14fdeca multitenancy: adapt openchangedb_* calls 2014-11-19 17:12:26 +01:00
Jesús García Sáez a5550cff18 avoid decode @ from url with username on it 2014-11-19 17:12:26 +01:00
294 changed files with 13092 additions and 1995 deletions

No files matched your search

+11
View File
@@ -12,6 +12,7 @@ trans.da_DK = UI/MailerUI/Danish.lproj/Localizable.strings
trans.de = UI/MailerUI/German.lproj/Localizable.strings
trans.es_AR = UI/MailerUI/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/MailerUI/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/MailerUI/Basque.lproj/Localizable.strings
trans.fi = UI/MailerUI/Finnish.lproj/Localizable.strings
trans.fr = UI/MailerUI/French.lproj/Localizable.strings
trans.hu = UI/MailerUI/Hungarian.lproj/Localizable.strings
@@ -38,6 +39,7 @@ trans.da_DK = UI/PreferencesUI/Danish.lproj/Localizable.strings
trans.de = UI/PreferencesUI/German.lproj/Localizable.strings
trans.es_AR = UI/PreferencesUI/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/PreferencesUI/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/PreferencesUI/Basque.lproj/Localizable.strings
trans.fi = UI/PreferencesUI/Finnish.lproj/Localizable.strings
trans.fr = UI/PreferencesUI/French.lproj/Localizable.strings
trans.hu = UI/PreferencesUI/Hungarian.lproj/Localizable.strings
@@ -64,6 +66,7 @@ trans.da_DK = UI/Scheduler/Danish.lproj/Localizable.strings
trans.de = UI/Scheduler/German.lproj/Localizable.strings
trans.es_AR = UI/Scheduler/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/Scheduler/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/Scheduler/Basque.lproj/Localizable.strings
trans.fi = UI/Scheduler/Finnish.lproj/Localizable.strings
trans.fr = UI/Scheduler/French.lproj/Localizable.strings
trans.hu = UI/Scheduler/Hungarian.lproj/Localizable.strings
@@ -90,6 +93,7 @@ trans.da_DK = UI/Contacts/Danish.lproj/Localizable.strings
trans.de = UI/Contacts/German.lproj/Localizable.strings
trans.es_AR = UI/Contacts/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/Contacts/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/Contacts/Basque.lproj/Localizable.strings
trans.fi = UI/Contacts/Finnish.lproj/Localizable.strings
trans.fr = UI/Contacts/French.lproj/Localizable.strings
trans.hu = UI/Contacts/Hungarian.lproj/Localizable.strings
@@ -116,6 +120,7 @@ trans.da_DK = UI/MainUI/Danish.lproj/Localizable.strings
trans.de = UI/MainUI/German.lproj/Localizable.strings
trans.es_AR = UI/MainUI/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/MainUI/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/MainUI/Basque.lproj/Localizable.strings
trans.fi = UI/MainUI/Finnish.lproj/Localizable.strings
trans.fr = UI/MainUI/French.lproj/Localizable.strings
trans.hu = UI/MainUI/Hungarian.lproj/Localizable.strings
@@ -142,6 +147,7 @@ trans.da_DK = UI/Common/Danish.lproj/Localizable.strings
trans.de = UI/Common/German.lproj/Localizable.strings
trans.es_AR = UI/Common/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/Common/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/Common/Basque.lproj/Localizable.strings
trans.fi = UI/Common/Finnish.lproj/Localizable.strings
trans.fr = UI/Common/French.lproj/Localizable.strings
trans.hu = UI/Common/Hungarian.lproj/Localizable.strings
@@ -168,6 +174,7 @@ trans.da_DK = UI/AdministrationUI/Danish.lproj/Localizable.strings
trans.de = UI/AdministrationUI/German.lproj/Localizable.strings
trans.es_AR = UI/AdministrationUI/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/AdministrationUI/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/AdministrationUI/Basque.lproj/Localizable.strings
trans.fi = UI/AdministrationUI/Finnish.lproj/Localizable.strings
trans.fr = UI/AdministrationUI/French.lproj/Localizable.strings
trans.hu = UI/AdministrationUI/Hungarian.lproj/Localizable.strings
@@ -194,6 +201,7 @@ trans.da_DK = SoObjects/Appointments/Danish.lproj/Localizable.strings
trans.de = SoObjects/Appointments/German.lproj/Localizable.strings
trans.es_AR = SoObjects/Appointments/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = SoObjects/Appointments/SpanishSpain.lproj/Localizable.strings
trans.eu = SoObjects/Appointments/Basque.lproj/Localizable.strings
trans.fi = SoObjects/Appointments/Finnish.lproj/Localizable.strings
trans.fr = SoObjects/Appointments/French.lproj/Localizable.strings
trans.hu = SoObjects/Appointments/Hungarian.lproj/Localizable.strings
@@ -220,6 +228,7 @@ trans.da_DK = SoObjects/Contacts/Danish.lproj/Localizable.strings
trans.de = SoObjects/Contacts/German.lproj/Localizable.strings
trans.es_AR = SoObjects/Contacts/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = SoObjects/Contacts/SpanishSpain.lproj/Localizable.strings
trans.eu = SoObjects/Contacts/Basque.lproj/Localizable.strings
trans.fi = SoObjects/Contacts/Finnish.lproj/Localizable.strings
trans.fr = SoObjects/Contacts/French.lproj/Localizable.strings
trans.hu = SoObjects/Contacts/Hungarian.lproj/Localizable.strings
@@ -246,6 +255,7 @@ trans.da_DK = SoObjects/Mailer/Danish.lproj/Localizable.strings
trans.de = SoObjects/Mailer/German.lproj/Localizable.strings
trans.es_AR = SoObjects/Mailer/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = SoObjects/Mailer/SpanishSpain.lproj/Localizable.strings
trans.eu = SoObjects/Mailer/Basque.lproj/Localizable.strings
trans.fi = SoObjects/Mailer/Finnish.lproj/Localizable.strings
trans.fr = SoObjects/Mailer/French.lproj/Localizable.strings
trans.hu = SoObjects/Mailer/Hungarian.lproj/Localizable.strings
@@ -272,6 +282,7 @@ trans.da_DK = UI/MailPartViewers/Danish.lproj/Localizable.strings
trans.de = UI/MailPartViewers/German.lproj/Localizable.strings
trans.es_AR = UI/MailPartViewers/SpanishArgentina.lproj/Localizable.strings
trans.es_ES = UI/MailPartViewers/SpanishSpain.lproj/Localizable.strings
trans.eu = UI/MailPartViewers/Basque.lproj/Localizable.strings
trans.fi = UI/MailPartViewers/Finnish.lproj/Localizable.strings
trans.fr = UI/MailPartViewers/French.lproj/Localizable.strings
trans.hu = UI/MailPartViewers/Hungarian.lproj/Localizable.strings
+25 -22
View File
@@ -1,6 +1,6 @@
/*
Copyright (c) 2014, Inverse inc.
Copyright (c) 2015, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -40,35 +40,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@implementation NGMimeMessage (ActiveSync)
- (NSArray *) allRecipients
- (void) _addRecipients: (NSEnumerator *) enumerator
toArray: (NSMutableArray *) recipients
{
NSEnumerator *enumerator, *addressList;
NSMutableArray *recipients;
NGMailAddressParser *parser;
NSEnumerator *addressList;
NGMailAddress *address;
NSString *s;
while ((s = [enumerator nextObject]))
{
parser = [NGMailAddressParser mailAddressParserWithString: s];
addressList = [[parser parseAddressList] objectEnumerator];
while ((address = [addressList nextObject]))
[recipients addObject: [address address]];
}
}
- (NSArray *) allRecipients
{
NSMutableArray *recipients;
recipients = [NSMutableArray array];
enumerator = [[self headersForKey: @"to"] objectEnumerator];
while ((s = [enumerator nextObject]))
{
parser = [NGMailAddressParser mailAddressParserWithString: s];
addressList = [[parser parseAddressList] objectEnumerator];
while ((address = [addressList nextObject]))
[recipients addObject: [address address]];
}
[self _addRecipients: [[self headersForKey: @"to"] objectEnumerator]
toArray: recipients];
enumerator = [[self headersForKey: @"cc"] objectEnumerator];
while ((s = [enumerator nextObject]))
{
parser = [NGMailAddressParser mailAddressParserWithString: s];
addressList = [[parser parseAddressList] objectEnumerator];
while ((address = [addressList nextObject]))
[recipients addObject: [address address]];
}
[self _addRecipients: [[self headersForKey: @"cc"] objectEnumerator]
toArray: recipients];
[self _addRecipients: [[self headersForKey: @"bcc"] objectEnumerator]
toArray: recipients];
return recipients;
}
+4 -2
View File
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSString+misc.h>
@@ -193,11 +194,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ((o = [self note]))
{
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
o = [o activeSyncRepresentationInContext: context];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Truncated>%d</Truncated>", 0];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
@@ -229,7 +231,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ((o = [theValues objectForKey: @"Birthday"]))
{
o = [o calendarDate];
[self setBday: [o descriptionWithCalendarFormat: @"%Y-%m-%d"]];
[self setBday: [o descriptionWithCalendarFormat: @"%Y-%m-%d" timeZone: nil locale: nil]];
}
//
+17 -7
View File
@@ -32,7 +32,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/NSProcessInfo.h>
#import <Foundation/NSString.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NSObject+Logs.h>
#include <wbxml/wbxml.h>
#include <wbxml/wbxml_conv.h>
@@ -44,11 +47,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (void) _dumpToFile
{
NSString *path;
BOOL debugOn;
path = [NSString stringWithFormat: @"/tmp/%@.data", [[NSProcessInfo processInfo] globallyUniqueString]];
[self writeToFile: path atomically: YES];
NSLog(@"Original data written to: %@", path);
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] easDebugEnabled];
if (debugOn)
{
NSString *path;
path = [NSString stringWithFormat: @"/tmp/%@.data", [[NSProcessInfo processInfo] globallyUniqueString]];
[self writeToFile: path atomically: YES];
[self errorWithFormat: @"Original data written to: %@", path];
}
}
//
@@ -81,7 +91,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
NSLog(@"wbxml2xmlFromContent: failed: %s\n", wbxml_errors_string(ret));
[self errorWithFormat: @"wbxml2xmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
return nil;
}
@@ -114,7 +124,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
NSLog(@"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret));
[self logWithFormat: @"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
return nil;
}
@@ -129,7 +139,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ret != WBXML_OK)
{
NSLog(@"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret));
[self errorWithFormat: @"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
[self _dumpToFile];
free(wbxml);
wbxml_conv_xml2wbxml_destroy(conv);
+4 -1
View File
@@ -1,6 +1,6 @@
/*
Copyright (c) 2014, Inverse inc.
Copyright (c) 2014-2015, Inverse inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (NSString *) deviceType;
- (NSString *) attachmentName;
- (NSString *) command;
- (NSString *) collectionid;
- (NSString *) itemid;
- (BOOL) acceptsMultiPart;
- (NSData *) convertHexStringToBytes;
@end
+45 -3
View File
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <Foundation/NSCalendarDate.h>
#include <Foundation/NSData.h>
#include <Foundation/NSDate.h>
#include <Foundation/NSTimeZone.h>
#include <SOGo/NSString+Utilities.h>
#include <SOGo/NSData+Crypto.h>
@@ -127,13 +128,17 @@ static NSArray *easCommandParameters = nil;
//
- (NSCalendarDate *) calendarDate
{
NSString *s;
id o;
o = [NSCalendarDate dateWithString: self calendarFormat: @"%Y%m%dT%H%M%SZ"];
// We force parsing in the GMT timezone. If we don't do that, the date will be parsed
// in the default timezone.
s = [NSString stringWithFormat: @"%@ GMT", self];
o = [NSCalendarDate dateWithString: s calendarFormat: @"%Y%m%dT%H%M%SZ %Z"];
if (!o)
o = [NSCalendarDate dateWithString: self calendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ"];
o = [NSCalendarDate dateWithString: s calendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ %Z"];
return o;
}
@@ -293,6 +298,43 @@ static NSArray *easCommandParameters = nil;
return s;
}
- (NSString *) itemid
{
NSString *s;
s = [self _valueForParameter: @"ITEMID="];
if (!s)
s = @"Unknown";
return s;
}
- (NSString *) collectionid
{
NSString *s;
s = [self _valueForParameter: @"COLLECTIONID="];
if (!s)
s = @"Unknown";
return s;
}
- (BOOL) acceptsMultiPart
{
NSString *s;
s = [self _valueForParameter: @"OPTIONS="];
if (s && [s rangeOfString: @"AcceptMultiPart" options: NSCaseInsensitiveSearch].location != NSNotFound)
return YES;
return NO;
}
//
// FIXME: combine with our OpenChange code.
//
+1 -1
View File
@@ -4,7 +4,7 @@ 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
http://www.microsoft.com/en-us/legal/intellectualproperty/
and send an email to iplicreq@microsoft.com
+153 -54
View File
@@ -57,6 +57,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGCards/NGVCard.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <NGImap4/NSString+Imap4.h>
@@ -130,6 +131,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[[o properties] removeObjectForKey: @"SyncCache"];
[[o properties] removeObjectForKey: @"DateCache"];
[[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
[[o properties] addEntriesFromDictionary: values];
@@ -287,9 +289,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
case ActiveSyncMailFolder:
default:
{
// FIXME
//continue;
NSLog(@"BLARG!");
// FIXME - what to do?
[self errorWithFormat: @"Fatal error occured - tried to call -processSyncAddCommand: ... on a mail folder. We abort."];
abort();
}
}
@@ -531,6 +532,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (void) processSyncGetChanges: (id <DOMElement>) theDocumentElement
inCollection: (id) theCollection
withWindowSize: (unsigned int) theWindowSize
withMaxSyncResponseSize: (unsigned int) theMaxSyncResponseSize
withSyncKey: (NSString *) theSyncKey
withFolderType: (SOGoMicrosoftActiveSyncFolderType) theFolderType
withFilterType: (NSCalendarDate *) theFilterType
@@ -539,6 +541,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
NSMutableDictionary *folderMetadata, *dateCache, *syncCache;
NSString *davCollectionTagToStore;
NSAutoreleasePool *pool;
NSMutableString *s;
@@ -562,7 +565,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dateCache = [folderMetadata objectForKey: @"DateCache"];
if ((theFolderType == ActiveSyncMailFolder || theFolderType == ActiveSyncEventFolder || theFolderType == ActiveSyncTaskFolder) &&
!([folderMetadata objectForKey: @"MoreAvailable"]) && // previous sync operation reached the windowSize
!([folderMetadata objectForKey: @"MoreAvailable"]) && // previous sync operation reached the windowSize or maximumSyncReponseSize
!([theSyncKey isEqualToString: @"-1"]) && // new sync operation
theFilterType)
{
@@ -590,7 +593,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
softdelete_count++;
}
if (softdelete_count >= theWindowSize)
if (softdelete_count >= theWindowSize || (theMaxSyncResponseSize > 0 && [s length] >= theMaxSyncResponseSize))
{
[folderMetadata setObject: [NSNumber numberWithBool: YES] forKey: @"MoreAvailable"];
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
@@ -617,6 +620,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
more_available = NO;
davCollectionTagToStore = [theCollection davCollectionTag];
switch (theFolderType)
{
// Handle all the GCS components
@@ -653,7 +658,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pool = [[NSAutoreleasePool alloc] init];
// Check for the WindowSize and slice accordingly
if (return_count >= theWindowSize)
if (return_count >= theWindowSize || (theMaxSyncResponseSize > 0 && [s length] >= theMaxSyncResponseSize))
{
more_available = YES;
@@ -668,7 +673,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
deleted = [[component objectForKey: @"c_deleted"] intValue];
if (!deleted && ![[component objectForKey: @"c_component"] isEqualToString: component_name])
continue;
{
DESTROY(pool);
continue;
}
uid = [[component objectForKey: @"c_name"] sanitizedServerIdWithType: theFolderType];
@@ -692,10 +700,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (![syncCache objectForKey: uid])
updated = NO;
else if ([[component objectForKey: @"c_lastmodified"] intValue] == [[syncCache objectForKey: uid] intValue])
continue;
{
DESTROY(pool);
continue;
}
return_count++;
sogoObject = [theCollection lookupName: [uid sanitizedServerIdWithType: theFolderType]
inContext: context
acquire: 0];
@@ -705,7 +716,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
componentObject = [sogoObject component: NO secure: NO];
//
// We do NOT synchronize NEW events that are in fact, invitations
// to events. This is due to the fact that Outlook 2013 creates
@@ -727,22 +737,34 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
partstat = [attendee participationStatus];
if (partstat == iCalPersonPartStatNeedsAction)
continue;
{
DESTROY(pool);
continue;
}
}
}
[syncCache setObject: [component objectForKey: @"c_lastmodified"] forKey: uid];
// No need to set dateCache for Contacts
if ((theFolderType == ActiveSyncEventFolder || theFolderType == ActiveSyncTaskFolder))
{
NSCalendarDate *d;
if ([[component objectForKey: @"c_cycleenddate"] intValue])
d = [NSCalendarDate dateWithTimeIntervalSince1970: [[component objectForKey: @"c_cycleenddate"] intValue]];
else if ([[component objectForKey: @"c_enddate"] intValue])
d = [NSCalendarDate dateWithTimeIntervalSince1970: [[component objectForKey: @"c_enddate"] intValue]];
else
d = [NSCalendarDate distantFuture];
[dateCache setObject: d forKey: uid];
}
if (updated)
[s appendString: @"<Change xmlns=\"AirSync:\">"];
else
{
// no need to set dateCache for Contacts
if ((theFolderType == ActiveSyncEventFolder || theFolderType == ActiveSyncTaskFolder))
[dateCache setObject: [componentObject startDate] ? [componentObject startDate] : [NSCalendarDate date] forKey: uid]; // FIXME: need to set proper date for recurring events - softDelete
[s appendString: @"<Add xmlns=\"AirSync:\">"];
}
[s appendFormat: @"<ServerId xmlns=\"AirSync:\">%@</ServerId>", uid];
[s appendString: @"<ApplicationData xmlns=\"AirSync:\">"];
@@ -757,10 +779,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendString: @"</Add>"];
return_count++;
DESTROY(pool);
}
} // for ...
DESTROY(pool);
} // for (i = 0; i < max; i++) ...
if (more_available)
{
@@ -770,7 +792,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
{
[folderMetadata removeObjectForKey: @"MoreAvailable"];
[folderMetadata setObject: [theCollection davCollectionTag] forKey: @"SyncKey"];
[folderMetadata setObject: davCollectionTagToStore forKey: @"SyncKey"];
}
[self _setFolderMetadata: folderMetadata
@@ -791,7 +813,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
int j, k, return_count;
BOOL found_in_cache;
allMessages = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType];
max = [allMessages count];
@@ -829,7 +850,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
found_in_cache = NO;
if (found_in_cache)
k = j+1;
else
@@ -847,7 +867,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pool = [[NSAutoreleasePool alloc] init];
// Check for the WindowSize and slice accordingly
if (return_count >= theWindowSize)
if (return_count >= theWindowSize || (theMaxSyncResponseSize > 0 && [s length] >= theMaxSyncResponseSize))
{
NSString *lastSequence;
more_available = YES;
@@ -947,7 +967,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
{
[folderMetadata removeObjectForKey: @"MoreAvailable"];
[folderMetadata setObject: [theCollection davCollectionTag] forKey: @"SyncKey"];
[folderMetadata setObject: davCollectionTagToStore forKey: @"SyncKey"];
}
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
@@ -1003,7 +1023,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ([[element tagName] isEqualToString: @"Add"])
{
// Add
[self processSyncAddCommand: aCommand
[self processSyncAddCommand: element
inCollection: theCollection
withType: theFolderType
inBuffer: theBuffer];
@@ -1012,7 +1032,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else if ([[element tagName] isEqualToString: @"Change"])
{
// Change
[self processSyncChangeCommand: aCommand
[self processSyncChangeCommand: element
inCollection: theCollection
withType: theFolderType
inBuffer: theBuffer];
@@ -1021,7 +1041,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else if ([[element tagName] isEqualToString: @"Delete"])
{
// Delete
[self processSyncDeleteCommand: aCommand
[self processSyncDeleteCommand: element
inCollection: theCollection
withType: theFolderType
inBuffer: theBuffer];
@@ -1030,7 +1050,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else if ([[element tagName] isEqualToString: @"Fetch"])
{
// Fetch
[self processSyncFetchCommand: aCommand
[self processSyncFetchCommand: element
inCollection: theCollection
withType: theFolderType
inBuffer: theBuffer];
@@ -1047,14 +1067,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (void) processSyncCollection: (id <DOMElement>) theDocumentElement
inBuffer: (NSMutableString *) theBuffer
changeDetected: (BOOL *) changeDetected
maxSyncResponseSize: (int) theMaxSyncResponseSize
{
NSString *collectionId, *realCollectionId, *syncKey, *davCollectionTag, *bodyPreferenceType, *lastServerKey;
NSString *collectionId, *realCollectionId, *syncKey, *davCollectionTag, *bodyPreferenceType, *mimeSupport, *lastServerKey, *syncKeyInCache;
SOGoMicrosoftActiveSyncFolderType folderType;
id collection, value;
NSMutableString *changeBuffer, *commandsBuffer;
BOOL getChanges, first_sync;
unsigned int windowSize, v, status;
NSMutableDictionary *folderMetadata, *folderOptions;
changeBuffer = [NSMutableString string];
commandsBuffer = [NSMutableString string];
@@ -1076,7 +1098,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//[theBuffer appendFormat: @"<CollectionId>%@</CollectionId>", collectionId];
//[theBuffer appendFormat: @"<Status>%d</Status>", 8];
//[theBuffer appendString: @"</Collection>"];
return;
}
@@ -1104,20 +1125,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
first_sync = NO;
folderMetadata = [self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]];
if ([syncKey isEqualToString: @"0"])
{
davCollectionTag = @"-1";
first_sync = YES;
*changeDetected = YES;
}
else if ((![syncKey isEqualToString: @"-1"]) && !([[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"SyncCache"]))
else if ((![syncKey isEqualToString: @"-1"]) && !([folderMetadata objectForKey: @"SyncCache"]))
{
//NSLog(@"Reset folder: %@", [collection nameInContainer]);
davCollectionTag = @"0";
first_sync = YES;
*changeDetected = YES;
if (!([[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"displayName"]))
if (!([folderMetadata objectForKey: @"displayName"]))
status = 12; // need folderSync
else
status = 3; // do a complete resync
@@ -1127,7 +1150,40 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
bodyPreferenceType = [[(id)[[(id)[theDocumentElement getElementsByTagName: @"BodyPreference"] lastObject] getElementsByTagName: @"Type"] lastObject] textValue];
if (!bodyPreferenceType)
bodyPreferenceType = @"1";
{
bodyPreferenceType = [[folderMetadata objectForKey: @"FolderOptions"] objectForKey: @"BodyPreferenceType"];
// By default, send MIME mails. See #3146 for details.
if (!bodyPreferenceType)
bodyPreferenceType = @"4";
}
else
{
mimeSupport = [[(id)[theDocumentElement getElementsByTagName: @"MIMESupport"] lastObject] textValue];
if (!mimeSupport)
mimeSupport = [[folderMetadata objectForKey: @"FolderOptions"] objectForKey: @"MIMESupport"];
if (!mimeSupport)
mimeSupport = @"0";
if ([mimeSupport isEqualToString: @"1"] && [bodyPreferenceType isEqualToString: @"4"])
bodyPreferenceType = @"2";
else if ([mimeSupport isEqualToString: @"2"] && [bodyPreferenceType isEqualToString: @"4"])
bodyPreferenceType = @"4";
else if ([mimeSupport isEqualToString: @"0"] && [bodyPreferenceType isEqualToString: @"4"])
bodyPreferenceType = @"2";
// Avoid writing to cache if there is nothing to change.
if (![[[folderMetadata objectForKey: @"FolderOptions"] objectForKey: @"BodyPreferenceType"] isEqualToString: bodyPreferenceType] ||
![[[folderMetadata objectForKey: @"FolderOptions"] objectForKey: @"MIMESupport"] isEqualToString: mimeSupport])
{
folderOptions = [[NSDictionary alloc] initWithObjectsAndKeys: mimeSupport, @"MIMESupport", bodyPreferenceType, @"BodyPreferenceType", nil];
[folderMetadata setObject: folderOptions forKey: @"FolderOptions"];
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: collection withType: folderType]];
}
}
[context setObject: bodyPreferenceType forKey: @"BodyPreferenceType"];
@@ -1139,6 +1195,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[self processSyncGetChanges: theDocumentElement
inCollection: collection
withWindowSize: windowSize
withMaxSyncResponseSize: theMaxSyncResponseSize
withSyncKey: syncKey
withFolderType: folderType
withFilterType: [NSCalendarDate dateFromFilterType: [[(id)[theDocumentElement getElementsByTagName: @"FilterType"] lastObject] textValue]]
@@ -1169,6 +1226,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[commandsBuffer appendFormat: @"<Responses>%@</Responses>", s];
}
folderMetadata = [self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]];
// If we got any changes or if we have applied any commands
// let's regenerate our SyncKey based on the collection tag.
if ([changeBuffer length] || [commandsBuffer length])
@@ -1179,7 +1238,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
// Use the SyncKey saved by processSyncGetChanges - if processSyncGetChanges is not called (because of getChanges=false)
// SyncKey has the value of the previous sync operation.
davCollectionTag = [[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"SyncKey"];
davCollectionTag = [folderMetadata objectForKey: @"SyncKey"];
if (!davCollectionTag)
davCollectionTag = [collection davCollectionTag];
@@ -1189,8 +1248,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
else
{
if (folderType == ActiveSyncMailFolder && [syncKey isEqualToString: @"-1"])
davCollectionTag = [collection davCollectionTag];
// Make sure that client is updated with the right syncKey. - This keeps vtodo's and vevent's syncKey in sync.
syncKeyInCache = [folderMetadata objectForKey: @"SyncKey"];
if (syncKeyInCache && !([davCollectionTag isEqualToString:syncKeyInCache]) && ![davCollectionTag isEqualToString: @"-1"])
{
davCollectionTag = syncKeyInCache;
*changeDetected = YES;
}
}
// Generate the response buffer
@@ -1211,7 +1275,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// MoreAvailable breaks Windows Mobile devices if not between <Status> and <Commands>
// https://social.msdn.microsoft.com/Forums/en-US/040b254e-f47e-4cc1-a397-6d8393cdb819/airsyncmoreavailable-breaks-windows-mobile-devices-what-am-i-doing-wrong?forum=os_exchangeprotocols
if ([[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"MoreAvailable"])
if ([folderMetadata objectForKey: @"MoreAvailable"])
[theBuffer appendString: @"<MoreAvailable/>"];
[theBuffer appendString: commandsBuffer];
@@ -1324,21 +1388,42 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NSArray *allCollections;
NSData *d;
int i, j, defaultInterval, heartbeatInterval, internalInterval;
int i, j, defaultInterval, heartbeatInterval, internalInterval, maxSyncResponseSize;
BOOL changeDetected;
changeDetected = NO;
maxSyncResponseSize = [[SOGoSystemDefaults sharedSystemDefaults] maximumSyncResponseSize];
// We initialize our output buffer
output = [[NSMutableString alloc] init];
[output appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
[output appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
[output appendString: @"<Sync xmlns=\"AirSync:\">"];
//
// We don't support yet empty Sync requests. See: http://msdn.microsoft.com/en-us/library/ee203280(v=exchg.80).aspx
// We return '13' - see http://msdn.microsoft.com/en-us/library/gg675457(v=exchg.80).aspx
//
if (!theDocumentElement || [[(id)[theDocumentElement getElementsByTagName: @"Partial"] lastObject] textValue])
{
[output appendString: @"<Status>13</Status>"];
[output appendString: @"</Sync>"];
d = [[output dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
[theResponse setContent: d];
return;
}
defaults = [SOGoSystemDefaults sharedSystemDefaults];
heartbeatInterval = [[[(id)[theDocumentElement getElementsByTagName: @"HeartbeatInterval"] lastObject] textValue] intValue];
defaultInterval = [defaults maximumSyncInterval];
internalInterval = [defaults internalSyncInterval];
// If the request doesn't contain "HeartbeatInterval" there is no reason to delay the response.
if (heartbeatInterval == 0)
heartbeatInterval = internalInterval = 1;
// We check to see if our heartbeat interval falls into the supported ranges.
if (heartbeatInterval > defaultInterval || heartbeatInterval < 1)
{
@@ -1355,7 +1440,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
allCollections = (id)[theDocumentElement getElementsByTagName: @"Collection"];
// We enter our loop detection change
for (i = 0; i < (defaultInterval/internalInterval); i++)
for (i = 0; i < (heartbeatInterval/internalInterval); i++)
{
s = [NSMutableString string];
@@ -1363,36 +1448,50 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
aCollection = [allCollections objectAtIndex: j];
[self processSyncCollection: aCollection inBuffer: s changeDetected: &changeDetected];
[self processSyncCollection: aCollection
inBuffer: s
changeDetected: &changeDetected
maxSyncResponseSize: maxSyncResponseSize];
if (maxSyncResponseSize > 0 && [s length] >= maxSyncResponseSize)
break;
}
if (changeDetected)
{
NSLog(@"Change detected, we push the content.");
[self logWithFormat: @"Change detected, we push the content."];
break;
}
else if (heartbeatInterval > 1)
{
[self logWithFormat: @"Sleeping %d seconds while detecting changes...", internalInterval];
sleep(internalInterval);
}
else
{
NSLog(@"Sleeping %d seconds while detecting changes...", internalInterval);
sleep(internalInterval);
break;
}
}
// We always return the last generated response.
// If we only return <Sync><Collections/></Sync>,
// iOS powered devices will simply crash.
[output appendString: s];
[output appendString: @"</Collections></Sync>"];
// Only send a response if there are changes or MS-ASProtocolVersion is either 2.5 or 12.0 oterwise send an empty response.
if (changeDetected || [[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"] || [[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"12.0"])
{
// We always return the last generated response.
// If we only return <Sync><Collections/></Sync>,
// iOS powered devices will simply crash.
[output appendString: s];
[output appendString: @"</Collections></Sync>"];
d = [output dataUsingEncoding: NSUTF8StringEncoding];
d = [d xml2wbxml];
[theResponse setContent: d];
}
// Avoid overloading the autorelease pool here, as Sync command can
// generate fairly large responses.
d = [output dataUsingEncoding: NSUTF8StringEncoding];
RELEASE(output);
d = [d xml2wbxml];
[theResponse setContent: d];
}
@end
File diff suppressed because it is too large. Load diff
+316 -39
View File
@@ -47,7 +47,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGExtensions/NSString+Encoding.h>
#import <NGImap4/NGImap4Envelope.h>
#import <NGImap4/NGImap4EnvelopeAddress.h>
#import <NGImap4/NSString+Imap4.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOApplication.h>
#import <NGMime/NGMimeBodyPart.h>
#import <NGMime/NGMimeFileData.h>
@@ -57,6 +59,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGMail/NGMimeMessage.h>
#import <NGMail/NGMimeMessageGenerator.h>
#import <Mailer/SOGoMailLabel.h>
#import <SOGo/SOGoUserDefaults.h>
#include "iCalTimeZone+ActiveSync.h"
#include "NSData+ActiveSync.h"
#include "NSDate+ActiveSync.h"
@@ -69,6 +75,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <SOGo/SOGoUser.h>
#include <SOGo/NSString+Utilities.h>
#import <Appointments/SOGoAptMailNotification.h>
typedef struct {
uint32_t dwLowDateTime;
uint32_t dwHighDateTime;
@@ -204,12 +212,15 @@ struct GlobalObjectId {
//
//
- (NSData *) _preferredBodyDataInMultipartUsingType: (int) theType
nativeTypeFound: (int *) theNativeTypeFound
{
NSString *encoding, *key, *plainKey, *htmlKey, *type, *subtype;
NSDictionary *textParts, *part;
NSEnumerator *e;
NSData *d;
BOOL ignore;
textParts = [self fetchPlainTextParts];
e = [textParts keyEnumerator];
plainKey = nil;
@@ -218,10 +229,35 @@ struct GlobalObjectId {
while ((key = [e nextObject]))
{
// Walk the hierarchy up and check whether parents are of type mulipart - i.e. ignore message/rfc822
if ([key countOccurrencesOfString: @"."] > 0)
{
NSMutableArray *a;
a = [[[key componentsSeparatedByString: @"."] mutableCopy] autorelease];
ignore = NO;
while ([a count] > 0)
{
[a removeLastObject];
part = [self lookupInfoForBodyPart: [a componentsJoinedByString: @"."]];
if (![[part valueForKey: @"type"] isEqualToString: @"multipart"])
ignore = YES;
}
if (ignore)
continue;
}
part = [self lookupInfoForBodyPart: key];
type = [part valueForKey: @"type"];
subtype = [part valueForKey: @"subtype"];
// Don't select an attachment as body
if ([[[part valueForKey: @"disposition"] valueForKey: @"type"] isEqualToString: @"attachment"])
continue;
if ([type isEqualToString: @"text"] && [subtype isEqualToString: @"html"])
htmlKey = key;
else if ([type isEqualToString: @"text"] && [subtype isEqualToString: @"plain"])
@@ -229,11 +265,22 @@ struct GlobalObjectId {
}
key = nil;
*theNativeTypeFound = 1;
if (theType == 2)
key = htmlKey;
else if (theType == 1)
if (theType == 2 && htmlKey)
{
key = htmlKey;
*theNativeTypeFound = 2;
}
else if (theType == 1 && plainKey)
key = plainKey;
else if (theType == 2 && plainKey)
key = plainKey;
else if (theType == 1 && htmlKey)
{
key = htmlKey;
*theNativeTypeFound = 2;
}
if (key)
{
@@ -251,9 +298,17 @@ struct GlobalObjectId {
charset = [[[self lookupInfoForBodyPart: key] objectForKey: @"parameterList"] objectForKey: @"charset"];
if (![charset length])
charset = @"us-ascii";
charset = @"utf-8";
s = [NSString stringWithData: d usingEncodingNamed: charset];
// We fallback to ISO-8859-1 string encoding
if (!s)
s = [[[NSString alloc] initWithData: d encoding: NSISOLatin1StringEncoding] autorelease];
if (theType == 1 && *theNativeTypeFound == 2)
s = [s htmlToText];
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
@@ -298,7 +353,7 @@ struct GlobalObjectId {
[[[thePart contentType] type] isEqualToString: @"text"] &&
([[[thePart contentType] subType] isEqualToString: @"plain"] || [[[thePart contentType] subType] isEqualToString: @"html"]))
{
// We make sure everything is encoded in UTF-8
// We make sure everything is encoded in UTF-8.
NGMimeType *mimeType;
NSString *s;
@@ -309,9 +364,13 @@ struct GlobalObjectId {
charset = [[thePart contentType] valueOfParameter: @"charset"];
if (![charset length])
charset = @"us-ascii";
charset = @"utf-8";
s = [NSString stringWithData: body usingEncodingNamed: charset];
s = [NSString stringWithData: body usingEncodingNamed: charset];
// We fallback to ISO-8859-1 string encoding. We avoid #3103.
if (!s)
s = [[[NSString alloc] initWithData: body encoding: NSISOLatin1StringEncoding] autorelease];
}
else
{
@@ -407,14 +466,14 @@ struct GlobalObjectId {
// We get the right part based on the preference
if (theType == 1 || theType == 2)
{
if ([type isEqualToString: @"text"])
if ([type isEqualToString: @"text"] && ![subtype isEqualToString: @"calendar"])
{
NSString *s, *charset;
charset = [[[self lookupInfoForBodyPart: @""] objectForKey: @"parameterList"] objectForKey: @"charset"];
if (![charset length])
charset = @"us-ascii";
charset = @"utf-8";
d = [[self fetchPlainTextParts] objectForKey: @""];
@@ -428,25 +487,30 @@ struct GlobalObjectId {
d = [d dataByDecodingQuotedPrintableTransferEncoding];
s = [NSString stringWithData: d usingEncodingNamed: charset];
// We fallback to ISO-8859-1 string encoding. We avoid #3103.
if (!s)
s = [[[NSString alloc] initWithData: d encoding: NSISOLatin1StringEncoding] autorelease];
// Check if we must convert html->plain
if (theType == 1 && [subtype isEqualToString: @"html"])
{
s = [s htmlToText];
}
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
else if ([type isEqualToString: @"multipart"])
{
d = [self _preferredBodyDataInMultipartUsingType: theType];
d = [self _preferredBodyDataInMultipartUsingType: theType nativeTypeFound: theNativeType];
}
}
else if (theType == 4)
{
// We sanitize the content *ONLY* for Outlook clients. Outlook has strange issues
// We sanitize the content *ONLY* for Outlook clients and if the content-transfer-encoding is 8bit. Outlook has strange issues
// with quoted-printable/base64 encoded text parts. It just doesn't decode them.
if ([[context objectForKey: @"DeviceType"] isEqualToString: @"WindowsOutlook15"])
encoding = [[self lookupInfoForBodyPart: @""] objectForKey: @"encoding"];
if ([[context objectForKey: @"DeviceType"] isEqualToString: @"WindowsOutlook15"] || ([encoding caseInsensitiveCompare: @"8bit"] == NSOrderedSame))
d = [self _sanitizedMIMEMessage];
else
d = [self content];
@@ -461,9 +525,37 @@ struct GlobalObjectId {
- (iCalCalendar *) calendarFromIMIPMessage
{
NSDictionary *part;
NSString *type, *subtype;
NSArray *parts;
int i;
type = [[[self bodyStructure] valueForKey: @"type"] lowercaseString];
subtype = [[[self bodyStructure] valueForKey: @"subtype"] lowercaseString];
// process mail of type text/calendar
if ([type isEqualToString: @"text"] && [subtype isEqualToString: @"calendar"])
{
iCalCalendar *calendar;
NSString *encoding;
NSData *calendarData;
encoding = [[[self bodyStructure] valueForKey: @"encoding"] lowercaseString];
calendarData = [[self fetchPlainTextParts] objectForKey: @""];
if ([encoding caseInsensitiveCompare: @"base64"] == NSOrderedSame)
calendarData = [calendarData dataByDecodingBase64];
else if ([encoding caseInsensitiveCompare: @"quoted-printable"] == NSOrderedSame)
calendarData = [calendarData dataByDecodingQuotedPrintableTransferEncoding];
NS_DURING
calendar = [iCalCalendar parseSingleFromSource: calendarData];
NS_HANDLER
calendar = nil;
NS_ENDHANDLER
return calendar;
}
// We check if we have at least 2 parts and if one of them is a text/calendar
parts = [[self bodyStructure] objectForKey: @"parts"];
@@ -512,6 +604,10 @@ struct GlobalObjectId {
NSData *d, *globalObjId;
NSArray *attachmentKeys;
NSMutableString *s;
uint32_t v;
NSString *p;
id value;
iCalCalendar *calendar;
@@ -552,8 +648,34 @@ struct GlobalObjectId {
if (value)
[s appendFormat: @"<Cc xmlns=\"Email:\">%@</Cc>", [value activeSyncRepresentationInContext: context]];
// Importance - FIXME
[s appendFormat: @"<Importance xmlns=\"Email:\">%@</Importance>", @"1"];
// Importance
v = 0x1;
value = [[self mailHeaders] objectForKey: @"x-priority"];
if ([value isKindOfClass: [NSArray class]])
p = [value lastObject];
else
p = value;
if (p)
{
if ([p hasPrefix: @"1"]) v = 0x2;
else if ([p hasPrefix: @"2"]) v = 0x2;
else if ([p hasPrefix: @"4"]) v = 0x0;
else if ([p hasPrefix: @"5"]) v = 0x0;
}
else
{
value = [[self mailHeaders] objectForKey: @"importance"];
if ([value isKindOfClass: [NSArray class]])
p = [value lastObject];
else
p = value;
if ([p hasPrefix: @"High"]) v = 0x2;
else if ([p hasPrefix: @"Low"]) v = 0x0;
}
[s appendFormat: @"<Importance xmlns=\"Email:\">%d</Importance>", v];
// Read
[s appendFormat: @"<Read xmlns=\"Email:\">%d</Read>", ([self read] ? 1 : 0)];
@@ -617,18 +739,18 @@ struct GlobalObjectId {
[s appendFormat: @"<AllDayEvent xmlns=\"Email:\">%d</AllDayEvent>", ([event isAllDay] ? 1 : 0)];
// StartTime -- http://msdn.microsoft.com/en-us/library/ee157132(v=exchg.80).aspx
// StartTime -- https://msdn.microsoft.com/en-us/library/ee203365%28v=exchg.80%29.aspx
if ([event startDate])
[s appendFormat: @"<StartTime xmlns=\"Email:\">%@</StartTime>", [[event startDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
[s appendFormat: @"<StartTime xmlns=\"Email:\">%@</StartTime>", [[event startDate] activeSyncRepresentationInContext: context]];
if ([event timeStampAsDate])
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event timeStampAsDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event timeStampAsDate] activeSyncRepresentationInContext: context]];
else if ([event created])
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event created] activeSyncRepresentationWithoutSeparatorsInContext: context]];
[s appendFormat: @"<DTStamp xmlns=\"Email:\">%@</DTStamp>", [[event created] activeSyncRepresentationInContext: context]];
// EndTime -- http://msdn.microsoft.com/en-us/library/ee157945(v=exchg.80).aspx
// EndTime -- https://msdn.microsoft.com/en-us/library/ee158628(v=exchg.80).aspx
if ([event endDate])
[s appendFormat: @"<EndTime xmlns=\"Email:\">%@</EndTime>", [[event endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
[s appendFormat: @"<EndTime xmlns=\"Email:\">%@</EndTime>", [[event endDate] activeSyncRepresentationInContext: context]];
// FIXME: Single appointment - others are not supported right now
[s appendFormat: @"<InstanceType xmlns=\"Email:\">%d</InstanceType>", 0];
@@ -676,7 +798,9 @@ struct GlobalObjectId {
[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];
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"14.1"])
[s appendFormat: @"<MeetingMessageType xmlns=\"Email2:\">%d</MeetingMessageType>", 1];
[s appendString: @"</MeetingRequest>"];
// ContentClass
@@ -703,6 +827,42 @@ struct GlobalObjectId {
nativeBodyType = 1;
d = [self _preferredBodyDataUsingType: preferredBodyType nativeType: &nativeBodyType];
if (calendar && !d)
{
WOApplication *app;
SOGoAptMailNotification *p;
NSString *pageName;
nativeBodyType = 2;
/* get WOApplication instance */
app = [WOApplication application];
/* create page name */
pageName = [NSString stringWithFormat: @"SOGoAptMail%@", @"Invitation"];
/* construct message content */
p = [app pageWithName: pageName inContext: context];
[p setApt: (iCalEvent *) [[calendar events] lastObject]];
if ([[ [[calendar events] lastObject] organizer] cn] && [[[ [[calendar events] lastObject] organizer] cn] length])
{
[p setOrganizerName: [[ [[calendar events] lastObject] organizer] cn]];
}
else
{
[p setOrganizerName: [[SOGoUser userWithLogin: owner] cn]];
}
if (preferredBodyType == 1 && nativeBodyType == 2)
d = [[[p getBody] htmlToText] dataUsingEncoding: NSUTF8StringEncoding];
else
{
preferredBodyType = 2;
d = [[p getBody] dataUsingEncoding: NSUTF8StringEncoding];
}
}
if (d)
{
@@ -728,17 +888,31 @@ struct GlobalObjectId {
len = [content length];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", preferredBodyType];
[s appendFormat: @"<Truncated>%d</Truncated>", truncated];
[s appendFormat: @"<Preview></Preview>"];
if (!truncated)
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
{
[s appendFormat: @"<Data>%@</Data>", content];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", len];
[s appendFormat: @"<Body xmlns=\"Email:\">%@</Body>", content];
[s appendFormat: @"<BodyTruncated xmlns=\"Email:\">%d</BodyTruncated>", truncated];
}
[s appendString: @"</Body>"];
else
{
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
// Set the correct type if client requested text/html but we got text/plain
if (preferredBodyType == 2 && nativeBodyType == 1)
[s appendString: @"<Type>1</Type>"];
else
[s appendFormat: @"<Type>%d</Type>", preferredBodyType];
[s appendFormat: @"<Truncated>%d</Truncated>", truncated];
[s appendFormat: @"<Preview></Preview>"];
if (!truncated)
{
[s appendFormat: @"<Data>%@</Data>", content];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", len];
}
[s appendString: @"</Body>"];
}
}
// Attachments -namespace 16
@@ -746,9 +920,12 @@ struct GlobalObjectId {
if ([attachmentKeys count])
{
int i;
[s appendString: @"<Attachments xmlns=\"AirSyncBase:\">"];
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
[s appendString: @"<Attachments xmlns=\"Email:\">"];
else
[s appendString: @"<Attachments xmlns=\"AirSyncBase:\">"];
for (i = 0; i < [attachmentKeys count]; i++)
{
value = [attachmentKeys objectAtIndex: i];
@@ -759,11 +936,22 @@ struct GlobalObjectId {
// 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"]];
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
[s appendFormat: @"<AttName>mail/%@/%@/%@</AttName>", [[[self container] relativeImap4Name] stringByEscapingURL], [self nameInContainer], [value objectForKey: @"path"]];
else
[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];
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
{
[s appendFormat: @"<AttMethod>%d</AttMethod>", 1];
[s appendFormat: @"<AttSize>%d</AttSize>", [[value objectForKey: @"size"] intValue]];
}
else
{
[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>"];
}
@@ -774,10 +962,40 @@ struct GlobalObjectId {
[s appendString: @"<Flag xmlns=\"Email:\">"];
[s appendFormat: @"<FlagStatus>%d</FlagStatus>", ([self flagged] ? 2 : 0)];
[s appendString: @"</Flag>"];
// Categroies/Labels
NSEnumerator *categories;
categories = [[[self fetchCoreInfos] objectForKey: @"flags"] objectEnumerator];
if (categories)
{
NSString *currentFlag;
NSDictionary *v;
v = [[[context activeUser] userDefaults] mailLabelsColors];
[s appendFormat: @"<Categories xmlns=\"Email:\">"];
while ((currentFlag = [categories nextObject]))
{
if ([[v objectForKey: currentFlag] objectAtIndex:0])
[s appendFormat: @"<Category>%@</Category>", [[[v objectForKey: currentFlag] objectAtIndex:0] activeSyncRepresentationInContext: context]];
}
[s appendFormat: @"</Categories>"];
}
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"14.0"] ||
[[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"14.1"])
{
if ([self inReplyTo])
[s appendFormat: @"<ConversationId xmlns=\"Email2:\">%@</ConversationId>", [[[self inReplyTo] dataUsingEncoding: NSUTF8StringEncoding] activeSyncRepresentationInContext: context]];
else if ([self messageId])
[s appendFormat: @"<ConversationId xmlns=\"Email2:\">%@</ConversationId>", [[[self messageId] dataUsingEncoding: NSUTF8StringEncoding] activeSyncRepresentationInContext: context]];
}
// 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.
@@ -836,6 +1054,65 @@ struct GlobalObjectId {
else
[self removeFlags: @"seen"];;
}
if ((o = [theValues objectForKey: @"Categories"]))
{
NSEnumerator *categories;
NSString *currentFlag;
NSDictionary *v;
v = [[[context activeUser] userDefaults] mailLabelsColors];
// add categories/labels sent from client
if ([o isKindOfClass: [NSArray class]])
{
NSEnumerator *enumerator;
NSMutableArray *labels;
NSEnumerator *flags;
id key;
labels = [NSMutableArray array];
enumerator = [v keyEnumerator];
flags = [o objectEnumerator];
while ((currentFlag = [flags nextObject]))
{
while ((key = [enumerator nextObject]))
{
if (([currentFlag isEqualToString:[[v objectForKey:key] objectAtIndex:0]]))
{
[labels addObject: key];
break;
}
}
}
[self addFlags: [labels componentsJoinedByString: @" "]];
}
categories = [[[self fetchCoreInfos] objectForKey: @"flags"] objectEnumerator];
// remove all categories/labels from server which were not it the list sent from client
if (categories)
{
while ((currentFlag = [categories nextObject]))
{
// only deal with lables and don't touch flags like seen and flagged
if (([v objectForKey: currentFlag]))
{
if (![o isKindOfClass: [NSArray class]])
{
[self removeFlags: currentFlag];
}
else if (([o indexOfObject: [[v objectForKey:currentFlag] objectAtIndex:0]] == NSNotFound))
{
[self removeFlags: currentFlag];
}
}
}
}
}
}
@end
+1 -1
View File
@@ -55,7 +55,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[o setUID: theUID];
[o setSequence: theSequence];
return o;
return [o autorelease];
}
- (void) dealloc
@@ -61,7 +61,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[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: @"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,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
[response setHeader: @"OPTIONS, POST" forKey: @"Public"];
}
+37 -31
View File
@@ -40,6 +40,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGExtensions/NSString+misc.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WORequest.h>
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalDateTime.h>
@@ -274,11 +275,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
o = [o activeSyncRepresentationInContext: context];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
{
[s appendFormat: @"<Body xmlns=\"Calendar:\">%@</Body>", o];
[s appendString: @"<BodyTruncated xmlns=\"Calendar:\">0</BodyTruncated>"];
}
else
{
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
}
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
@@ -332,7 +342,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
iCalTimeZone *tz;
id o;
NSInteger tzOffset;
BOOL isAllDay;
if ((o = [theValues objectForKey: @"UID"]))
@@ -384,15 +393,28 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Some Windows devices don't send during event updates.
//if ((o = [theValues objectForKey: @"TimeZone"]))
// {
userTimeZone = [[[context activeUser] userDefaults] timeZone];
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
[(iCalCalendar *) parent addTimeZone: tz];
//}
// }
//else
{
// We haven't received a timezone, let's use the user's timezone
// specified in SOGo 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 ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
{
if ((o = [theValues objectForKey: @"Body"]))
[self setComment: o];
}
else
{
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setComment: o];
}
if ((o = [theValues objectForKey: @"Location"]))
[self setLocation: o];
@@ -402,21 +424,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
[start setTimeZone: tz];
if (isAllDay)
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
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];
}
}
@@ -429,19 +443,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (isAllDay)
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[end setDate: o];
[end setTimeZone: nil];
}
else
{
tzOffset = [userTimeZone secondsFromGMTForDate: o];
o = [o dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[end setDateTime: o];
}
}
+46 -23
View File
@@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGExtensions/NSString+misc.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WORequest.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
@@ -49,6 +50,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "NSDate+ActiveSync.h"
#include "NSString+ActiveSync.h"
@implementation iCalToDo (ActiveSync)
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
@@ -62,11 +64,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
s = [NSMutableString string];
// Complete
o = [self completed];
[s appendFormat: @"<Complete xmlns=\"Tasks:\">%d</Complete>", (o ? 1 : 0)];
[s appendFormat: @"<Complete xmlns=\"Tasks:\">%d</Complete>", [[self status] isEqualToString: @"COMPLETED"] ? 1 : 0];
// DateCompleted
if (o)
if ((o = [self completed]))
[s appendFormat: @"<DateCompleted xmlns=\"Tasks:\">%@</DateCompleted>", [o activeSyncRepresentationInContext: context]];
// Start date
@@ -97,6 +98,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Reminder - FIXME
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
// Sensitivity
if ([[self accessClass] isEqualToString: @"PRIVATE"])
v = 2;
else if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
@@ -104,6 +106,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else
v = 0;
[s appendFormat: @"<Sensitivity xmlns=\"Tasks:\">%d</Sensitivity>", v];
categories = [self categories];
if ([categories count])
@@ -126,11 +130,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
o = [o activeSyncRepresentationInContext: context];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
{
[s appendFormat: @"<Body xmlns=\"Tasks:\">%@</Body>", o];
[s appendString: @"<BodyTruncated xmlns=\"Tasks:\">0</BodyTruncated>"];
}
else
{
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
[s appendFormat: @"<Data>%@</Data>", o];
[s appendString: @"</Body>"];
}
}
return s;
@@ -143,8 +156,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
iCalTimeZone *tz;
id o;
NSInteger tzOffset;
userTimeZone = [[[context activeUser] userDefaults] timeZone];
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
[(iCalCalendar *) parent addTimeZone: tz];
@@ -154,9 +165,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[self setSummary: o];
// FIXME: merge with iCalEvent
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setComment: o];
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
{
if ((o = [theValues objectForKey: @"Body"]))
[self setComment: o];
}
else
{
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
[self setComment: o];
}
if ([[theValues objectForKey: @"Complete"] intValue] &&
((o = [theValues objectForKey: @"DateCompleted"])) )
@@ -165,27 +183,32 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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"];
}
else
{
[self setStatus: @"IN-PROCESS"];
[self setCompleted: nil];
}
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];
}
if ((o = [theValues objectForKey: @"StartDate"]))
{
iCalDateTime *due;
o = [o calendarDate];
due = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
[due setTimeZone: tz];
[due setDateTime: o];
}
+3769
View File
File diff suppressed because it is too large. Load diff
+176 -31
View File
@@ -167,9 +167,9 @@ Operating System Requirements
The following 32-bit and 64-bit operating systems are currently
supported by SOGo:
* Red Hat Enterprise Linux (RHEL) Server 5 and 6
* Community ENTerprise Operating System (CentOS) 5 and 6
* Debian GNU/Linux 5.0 (Lenny) to 7.0 (Wheezy)
* Red Hat Enterprise Linux (RHEL) Server 5, 6 and 7
* Community ENTerprise Operating System (CentOS) 5, 6 and 7
* Debian GNU/Linux 6.0 (Squeeze) to 8.0 (Jessie)
* Ubuntu 10.04 (Lucid) to 14.04 (Trusty)
Make sure the required components are started automatically at boot time
@@ -194,7 +194,8 @@ Installation
This section will guide you through the installation of SOGo together
with its dependencies. The steps described here apply to an RPM-based
installation for a Red Hat or CentOS distribution.
installation for a Red Hat or CentOS 6 distribution. Most of these steps
should apply to all supported operating systems.
Software Downloads
~~~~~~~~~~~~~~~~~~
@@ -566,17 +567,29 @@ usernames like this: `SOGoSuperUsernames = (<username1>[, <username2>, ...]);`
for SOGo. Possible values are:
[options="compact"]
* `Arabic`
* `Basque`
* `BrazilianPortuguese`
* `Catalan`
* `Czech`
* `Danish`
* `Dutch`
* `English`
* `Finnish`
* `French`
* `German`
* `Hungarian`
* `Icelandic`
* `Italian`
* `NorwegianBokmal`
* `NorwegianNynorsk`
* `Polish`
* `Russian`
* `Spanish`
* `Slovak`
* `SpanishSpain`
* `SpanishArgentina`
* `Swedish`
* `Ukrainian`
* `Welsh`
|D |SOGoNotifyOnPersonalModifications
@@ -649,7 +662,7 @@ of 1 day by default.
|Parameter used to configure which languages are available from SOGo's
Web interface. Available languages are specified as an array of string.
The default value is: `( "Czech", "Welsh", "English", "Spanish", "French", "German", "Italian", "Hungarian", "Dutch", "BrazilianPortuguese", "Polish", "Russian", Ukrainian", "Swedish" )`
The default value is: `( "Arabic", "Basque", "Catalan", "Czech", "Dutch", "Danish", "Welsh", "English", "SpanishSpain", "SpanishArgentina", "Finnish", "French", "German", "Icelandic", "Italian", "Hungarian", "BrazilianPortuguese", "NorwegianBokmal", "NorwegianNynorsk", "Polish", "Russian", "Slovak", "Ukrainian", "Swedish" )`
|D |SOGoHideSystemEMail
|Parameter used to control if SOGo should hide or not the system email
@@ -843,7 +856,7 @@ source:
[cols="^3,>47,50a"]
|=======================================================================
.33+|D <|SOGoUserSources
.34+|D <|SOGoUserSources
|Parameter used to set the LDAP and/or SQL sources used for
authentication and global address books. Multiple sources can be
specified as an array of dictionaries. A dictionary that defines an LDAP
@@ -911,7 +924,8 @@ resource if the entry has the calendarresource objectClass set.
to which a resource can be part of at any point in time.
If this is set to `0`, or if the attribute is missing, it means no
limit.
limit. If set to `-1`, no limit is imposed but the resource will
be marked as busy the first time it is booked.
|filter (optional)
|The filter to use for LDAP queries, it should be defined as an
@@ -998,7 +1012,17 @@ context as Dovecot stores in its database.
|passwordPolicy
|If set to `YES`, SOGo will use the extended LDAP Password Policies
attributes. If you LDAP server does not support those and you activate
this feature, every LDAP requests will fail.
this feature, every LDAP requests will fail. Note that some LDAP servers
require LDAP/SSL for password policies to work. This is the case for
example with 389 Directory Server.
|updateSambaNTLMPasswords
|If set to `YES`, SOGo will automatically update the sambaNTPassword
and sambaLMPassword attributes when changing passwords. The attributes
must be called sambaNTPassword and sambaLMPassword. You must also make
sure the correct ACL is set in your LDAP server to allow users to change
their own sambaNTPassword and sambaLMPassword password attributes.
Defaults to `NO` when unset.
|isAddressBook
|If set to `YES`, this LDAP source is used as a shared address book
@@ -1037,6 +1061,11 @@ of supported attributes.
user addressbooks (see _abOU_ below), this list of object classes will
be applied to new records as they are created.
|GroupObjectClasses
|A list (array) of names identifying groups within the LDAP source. If not
set, SOGo will use `group`, `groupofnames`, `groupofuniquenames`
and `posixgroup`.
|modifiers
|A list (array) of usernames that are authorized to perform
modifications to the address book defined by this LDAP source.
@@ -1326,27 +1355,27 @@ The following table describes the parameters that were set:
[cols="3,47,50a"]
|=======================================================================
|D |SOGoProfileURL
|S |SOGoProfileURL
|Parameter used to set the database URL so that SOGo can retrieve user
profiles.
For MySQL, set the database URL to something like:
`mysql://sogo:sogo@localhost:3306/sogo/sogo_user_profile`.
|D |OCSFolderInfoURL
|S |OCSFolderInfoURL
|Parameter used to set the database URL so that SOGo can retrieve the
location of user folders (address books and calendars).
For Oracle, set the database URL to something like:
`oracle://sogo:sogo@localhost:1526/sogo/sogo_folder_info`.
|D |OCSSessionsFolderURL
|S |OCSSessionsFolderURL
|Parameter used to set the database URL so that SOGo can store and
retrieve secured user sessions information. For PostgreSQL, the database
URL could be set to something like:
`postgresql://sogo:sogo@localhost:5432/sogo/sogo_sessions_folder`.
|D |OCSEMailAlarmsFolderURL
|S |OCSEMailAlarmsFolderURL
|Parameter used to set the database URL for email-based alarms (that can
be set on events and tasks). This parameter is relevant only if
_SOGoEnableEMailAlarms_ is set to `YES`. For PostgreSQL, the database
@@ -1476,7 +1505,10 @@ case, SOGo will consider the returned entry to be a resource.
which a resource can be part of at any point in time.
If this is set to `0`, or if the attribute is missing, it means no
limit.
limit and the resource will always be marked as free. If set to `-1`,
no limit is imposed but the resource will be marked as busy the first
time it is booked. If greater than 0, the resource will get marked as
busy once it reaches the value.
|DomainFieldName (optional)
|If set, SOGo will use the value of that field as the domain associated
@@ -1675,6 +1707,13 @@ cronjob `sogo-tmpwatch`.
Defaults to `/var/spool/sogo`.
|S |NGMimeBuildMimeTempDirectory
|Parameter used to set the path where temporary files will be stored
by SOPE when dealing with MIME messages.
Defaults to `/tmp`.
|S |NGImap4DisableIMAP4Pooling
|Disables IMAP pooling when set to `YES`. Enable pooling by setting to
`NO` or using a caching proxy like imapproxy.
@@ -1778,6 +1817,12 @@ host.
Defaults to `NO` when unset.
|D |SOGoForwardConstraints
|Parameter used to set constraints on possible addresses used when
automatically forwarding mails. When set to `0` (default), no constraint
is enforced. When set to `1`, only internal domains can be used. When
set to `2`, only external domains can be used.
|D |SOGoSieveScriptsEnabled
|Parameter used to activate the edition from the preferences windows of
server-side mail filters. Requires Sieve script support on the IMAP
@@ -2091,7 +2136,8 @@ Multi-domains Configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want your installation to isolate two groups of users, you must
define a distinct authentication source for each _domain_. Following is
define a distinct authentication source for each _domain_. Your domain keys
must have the same value as your email domain you want to add. Following is
the same configuration that now includes two domains (acme.com and
coyote.com):
@@ -2099,7 +2145,7 @@ coyote.com):
{
...
domains = {
acme = {
acme.com = {
SOGoMailDomain = acme.com;
SOGoDraftsFolderName = Drafts;
SOGoUserSources = (
@@ -2120,7 +2166,7 @@ coyote.com):
}
);
};
coyote = {
coyote.com = {
SOGoMailDomain = coyote.com;
SOGoIMAPServer = imap.coyote.com;
SOGoUserSources = (
@@ -2151,7 +2197,7 @@ domains.
[cols="3,47,50a"]
|=======================================================================
|S |SOGoEnableDomainBasedUID
|Parameter used to activate user identification by domain. Users will be
|Parameter used to enable user identification by domain. Users will be
able (without being required) to login using the form `username@domain`,
meaning that values of _UIDFieldName_ no longer have to be unique among
all domains but only within the same domain. Internally, users will
@@ -2340,8 +2386,8 @@ easier. These GUI utilities can make use of templates to create and
pre-configure typical user accounts or any standardized LDAP record,
along with the correct object classes, fields and default values.
Microsoft ActiveSync
--------------------
Microsoft Enterprise ActiveSync
-------------------------------
SOGo supports the Microsoft ActiveSync protocol.
@@ -2390,6 +2436,15 @@ _SOGoMaximumPingInterval_.
If not set, it defaults to `10` seconds.
|S |SOGoMaximumSyncResponseSize
|Parameter used to overwrite the maximum response size during
a Sync operation. The value is in kilobytes. Setting this to 512
means the response size will be of 524288 bytes or less. Note that
if you set the value too low and a mail message (or any other object)
surpasses it, it will still be synced but only this item will be.
Defaults to `0`, which means no overwrite is performed.
|S |SOGoMaximumSyncWindowSize
|Parameter used to overwrite the maximum number of items returned during
a Sync operation.
@@ -2398,28 +2453,31 @@ Defaults to `0`, which means no overwrite is performed.
Setting this parameter to a value greater than `512` will
have unexpected behaviour with various ActiveSync clients.
|S |SOGoEASDebugEnabled
|Parameter used to log the complete request and response of every single
EAS command.
Defaults to `NO`, which means no logging is performed.
|=======================================================================
Please be aware of the following limitations:
* Currently, only the personal calendar and address book are
synchronized. Adding support for all folders is planned.
* When creating an Outlook 2013 profile, you must actually kill Outlook
before the end of the creation process. See http://www.vionblog.com/connect-zimbra-community-with-outlook-2013
for a procedure example.
* Outlook 2013 does not search the GAL. One possible alternative
solution is to configure Outlook to use a LDAP server (over SSL) with
authentication. Alternatively, when supporting more than just the
personal address book, we'll also be able to expose the LDAP/SQL based
address books in SOGo over ActiveSync.
authentication. Outlook 2013 also does not seem to support multiple
address books over ActiveSync.
* To successfully synchronize Outlook email categories, a corresponding
mail label (Preferences->Mail Options) has to be created manually in SOGo
for each label defined in Outlook. The name in SOGo and in Outlook must be
identical.
* Make sure you do not use a self-signed certificate. While this will
work, Outlook will work intermittently as it will raise popups for
certificate validation, sometimes in background, preventing the user to
see the warning and thus, preventing any synchronization to happen.
* ActiveSync clients keep connections open for a while. Each connection
will grab a hold on a sogod process so you will need a lot of processes
to handle many clients. This limitation will eventually be overcome in
SOGo.
to handle many clients. Make sure you tune your SOGo server when having
lots of ActiveSync clients.
* Repetitive events with occurrences exceptions are currently not
supported.
* Outlook 2013 Autodiscovery is currently not supported.
@@ -2441,13 +2499,90 @@ user base.
To contact Microsoft, please visit:
http://www.microsoft.com/en-us/legal/intellectualproperty/IPLicensing/Programs/exchangeactivesyncprotocol.aspx
http://www.microsoft.com/en-us/legal/intellectualproperty/
 
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.
Microsoft Enterprise ActiveSync Tuning
--------------------------------------
First of all, it is important to know that most EAS devices will keep
HTTP connections open to SOGo (and thus, Apache) for a long time. This
is required for "push" to work properly. Connections can stay open for
up to one hour, or 3600 seconds.
The first parameter to check is related to Apache's proxying to
SOGo:
----
ProxyPass /Microsoft-Server-ActiveSync \
http://127.0.0.1:20000/SOGo/Microsoft-Server-ActiveSync \
retry=60 connectiontimeout=5 timeout=360
----
The above line sets a timeout for up to 360 seconds, or 6 minutes. If
you want to let EAS clients keep their HTTP connections open for up
to an hour, you must change the timeout parameter and set it to 3600.
If you change this value, the WOWatchDogRequestTimeout parameter must be changed
accordingly in SOGo's configuration file (/etc/sogo/sogo.conf). By default,
a SOGo child process is allowed to handle a request that can take up
to 10 minutes before it gets killed by its parent process. When using
EAS "push", the client expects to keep its connection open for up to one
hour - so the WOWatchDogRequestTimeout, which is set in minutes,
must be adjusted accordingly.
EAS clients will keep HTTP connections open for a long time
during these two EAS commands: Ping and Sync. By default, SOGo will prevent
EAS clients from keeping connections for a long time. This is to avoid the
situation where all SOGo child processes would be monopolized by EAS clients -
rendering the SOGo web interface or DAV interface unavailable. The
default SOGo behavior is thus similar to disable EAS push entirely.
Two SOGo configuration parameters are available to modify this behavior:
SOGoMaximumPingInterval (set by default to 10 seconds) and
SOGoMaximumSyncInterval (set by default to 30 seconds). If you want
connection to stay open for up to one hour, you should set these
slightly under 3600 seconds (say 3540 - or 59 minutes). During a
long-lived HTTP connection, the SOGo child process will perform
internal polling to detect changes and return them to the EAS client
if any changes are found. The parameter used to control this
is SOGoInternalSyncInterval. By default, polling is done every 10
seconds. This might generate too much load on large-scale system.
The last configuration parameter to adjust is WOWorkersCount - which sets the
number of SOGo child process that will be used to handle requests.
You should have at least one child per EAS device configured to use
"push". You must also have more children than you have EAS devices
configured to use "push" - in order to handle normal SOGo requests to
its Web or DAV interfaces.
Here are some usage examples for EAS devices using "push". In all
cases, the Apache timeout is set to 3600 and the
WOWatchDogRequestTimeout parameter is set to 60.
Example 1 - 100 users, 10 EAS devices:
----
WOWorkersCount = 15;
SOGoMaximumPingInterval = 3540;
SOGoMaximumSyncInterval = 3540;
SOGoInternalSyncInterval = 30;
----
Example 2 - 1000 users, 100 EAS devices:
----
WOWorkersCount = 120;
SOGoMaximumPingInterval = 3540;
SOGoMaximumSyncInterval = 3540;
SOGoInternalSyncInterval = 60;
----
Using SOGo
----------
@@ -2577,6 +2712,16 @@ current version of SOGo from the previous release.
[cols="100a"]
|=======================================================================
h|2.3.0
|Run the shell script `sql-update-2.2.17_to_2.3.0.sh` or
`sql-update-2.2.17_to_2.3.0-mysql.sh` (if you use MySQL).
This will grow the "participant states" field of calendar quick tables to a larger
size and add the the "c_description" column to calendar quick tables.
Moreover, if you are using a multi-domain configuration, make sure the keys for
your domains match the email domains you have defined.
h|2.2.8
|The configuration configuration parameters were renamed:
@@ -239,7 +239,7 @@ Red Hat Enterprise Linux v6 x86_64
If you are using Red Hat Enterprise Linux version 6 x86_64, packages
for Samba 4, OpenChange and SOGo and the SOGo OpenChange backend are
available from SOGo's web site. Please follow the instructions from
http://www.sogo.nu/english/downloads/backend_nightly.html.
http://www.sogo.nu/english/downloads/backend.html.
In order to satisfy certain dependencies, you should also add the EPEL
source corresponding to your distribution and architecture. More
@@ -266,32 +266,30 @@ from this guide.
[NOTE]
Samba4/OpenChange are not available for now on CentOS 5 i386/x86_64,
CentOS 6 i386 and CentOS 7.
and CentOS 7. On Debian-based systems, packages are available only on
the x86_64 platform.
Debian 7.0 (Wheezy) and Ubuntu 12.04 (Precise Pangolin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Debian 7 (Wheezy) and Ubuntu 12.04 (Precise Pangolin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SOGo, OpenChange and the SOGo OpenChange backend are now
available from SOGo's web site. Please follow the instructions from
http://www.sogo.nu/english/downloads/backend.html to setup your
apt sources.
For Samba 4, you need to use the _wheezy-backports_ repository. To do so, create
`/etc/apt/sources.list.d/backports.list`:
On Debian7, for some Samba 4 dependencies, you need to use the
_wheezy-backports_ repository. To do so, create
`/etc/apt/sources.list.d/backports.list` with the following
content:
deb http://http.debian.net/debian wheezy-backports main
On Ubuntu 12.04, you will also have to add the Wheezy sources:
deb http://ftp.us.debian.org/debian wheezy main
deb http://security.debian.org/ wheezy/updates main
Then install Samba 4 on top of an existing SOGo
installation:
----
apt-get update
apt-get -t wheezy-backports install samba samba-dev
apt-get install samba samba-dev
----
Once completed, install the packages related to OpenChange and the SOGo
@@ -303,7 +301,12 @@ apt-get install openchangeserver \
openchangeproxy \
python-ocsmanager \
mysql-server \
python-mysqldb
python-mysqldb \
openchange-ocsmanager \
openchange-rpcproxy \
python-sievelib \
python-spyne \
python-rpclib
----
Once the packages are installed, refer to the _Configuration_ chapter
@@ -315,10 +318,8 @@ disable the upstart check. For more details, refer to:
https://wiki.samba.org/index.php/Samba4/InitScript
Ubuntu 14.04 (Trusty Tahr)
~~~~~~~~~~~~~~~~~~~~~~~~~~
For Ubuntu 14.04, you must not use the Debian Wheezy backports.
Debian 8 (Jessie) and Ubuntu 14.04 (Trusty Tahr)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Please follow the instructions from
http://www.sogo.nu/english/downloads/backend.html to setup your
@@ -341,12 +342,26 @@ apt-get install openchangeserver \
openchangeproxy \
python-ocsmanager \
mysql-server \
python-mysqldb
python-mysqldb \
openchange-ocsmanager \
openchange-rpcproxy \
python-sievelib \
python-spyne \
python-rpclib
----
Once the packages are installed, refer to the _Configuration_ chapter
from this guide.
[NOTE]
The `ocsmanager.conf` and `rpcproxy.conf` are currently located in
`/etc/apache2/conf.d`. These should be moved to `/etc/apache2/conf-available`.
This is a packaging error that will soon be fixed.
[NOTE]
You might have to adjust the `rpcproxy.conf` configuration file to add the
`Require all granted` permission if you get Apache errors such as
`client denied by server configuration`.
Configuration
-------------
@@ -390,6 +405,7 @@ Add the following parameters to the `[global]` section of the
----
### Configuration required by OpenChange server ###
dsdb:schema update allowed = true
dcerpc endpoint servers = epmapper, mapiproxy, dnsserver
dcerpc_mapiproxy:server = true
dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
@@ -407,6 +423,7 @@ Your Samba 4 configuration file should look like this:
netbios name = sogo
passdb backend = samba4
### Configuration required by OpenChange server ###
dsdb:schema update allowed = true
dcerpc endpoint servers = +epmapper, +mapiproxy
dcerpc_mapiproxy:server = true
dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
@@ -533,7 +550,7 @@ services can be found in `/etc/httpd/conf.d/ocsmanager.conf` and
`/etc/httpd/conf.d/rpcproxy.conf`.
For Debian-based distributions, these files can be found
in `/etc/apache2/conf.d/`.
in `/etc/apache2/conf.d/` or `/etc/apache2/conf-available`.
The configuration requires three Apache modules:  _mod_proxy_,
_mod_proxy_http_ and _mod_wsgi_. These are usually already installed but
@@ -541,13 +558,17 @@ might need to be activated on Debian-based installations:
a2enmod proxy proxy_http wsgi
The OCS Manager and RPC Proxy configuration module can be enabled using:
a2enconf ocsmanager
a2enconf rpcproxy
On RHEL-based distributions, make sure the `LoadModule` directive is
uncommented in `/etc/httpd/conf.d/wsgi.conf` (or
`python26-mod_wsgi.conf` on RHELv5).
uncommented in `/etc/httpd/conf.d/wsgi.conf`.
The _reqtimeout_ apache module is known to cause problems when using the
default configuration shipped with Debian-based systems. On such
distributions, apache will close (HTTP/1.1 500) any HTTP request for
distributions, Apache will close (HTTP/1.1 500) any HTTP request for
which the HTTP body hasn't arrived in 10 seconds.
While this is arguably good practice with regular HTTP, it will disrupt
@@ -567,9 +588,102 @@ On Debian-based distributions, do:
update-rc.d apache2 defaults && /etc/init.d/apache2 restart
[NOTE]
Debian-based distributions are not supported anymore for
OCSManager/rpcproxy. Support will soon resume.
Finally, you must adjust the OCS Manager configuration file, which is
located in `/etc/ocsmanager/ocsmanager.ini`. You should enable LDAP-based
authentication in the `main` section and configure it accordingly. You should
also enable rpcproxy. You file should be similar to this one:
----
[DEFAULT]
debug = true
email_to = you@yourdomain.com
smtp_server = localhost
error_email_from = paste@localhost
[main]
auth = ldap
mapistore_root = /var/lib/samba/private
mapistore_data = /var/lib/samba/private/mapistore
debug = yes
[auth:file]
[auth:ldap]
host = ldap://127.0.0.1
port = 389
bind_dn = cn=administrator,cn=Users,dc=example,dc=com
bind_pw = %1OpenChange
basedn = cn=Users,dc=example,dc=com
[auth:single]
username = openchange
password = {SSHA}I6Hy5Wv0wuxyXvMBFWFQDVVN12_CLaX9
[server:main]
use = egg:Paste#http
host = 127.0.0.1
port = 5000
protocol_version = HTTP/1.1
[app:main]
use = egg:ocsmanager
full_stack = true
static_files = true
cache_dir = %(here)s/data
beaker.session.key = ocsmanager
beaker.session.secret = SDyKK3dKyDgW0mlpqttTMGU1f
app_instance_uuid = {ee533ebc-f266-49d1-ae10-d017ee6aa98c}
NTLMAUTHHANDLER_WORKDIR = /var/cache/ntlmauthhandler
SAMBA_HOST = 127.0.0.1
[rpcproxy:ldap]
host = localhost
port = 389
basedn = CN=Users,DC=example,DC=com
set debug = true
----
----
[autodiscover]
[autodiscover:rpcproxy]
enabled = true
[outofoffice]
[outofoffice:file]
sieve_script_path = /var/vmail/$domain/$user/sieve-script
sieve_script_path_mkdir = false
[outofoffice:managesieve]
secret = secret
[loggers]
keys = root
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = INFO
handlers = console
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s
----
Once completed, start the OCS Manager service:
/etc/init.d/openchange-ocsmanager start
Name Service Configuration for Web Services
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+3 -3
View File
@@ -1,7 +1,7 @@
<!-- TODO have the build system take care of this -->
<releaseinfo>Version 2.2.12 - December 2014</releaseinfo>
<subtitle>for version 2.2.12</subtitle>
<date>2014-12-18</date>
<releaseinfo>Version 2.3.0 - June 2015</releaseinfo>
<subtitle>for version 2.3.0</subtitle>
<date>2015-06-01</date>
<legalnotice>
<para>Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".</para>
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

@@ -6,13 +6,13 @@
Authors:
- Inverse inc. <info@inverse.ca>
Copyright (C) 2008-2014 Inverse inc.
Copyright (C) 2008-2015 Inverse inc.
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
////
// TODO have the build system take care of this
:release_version: 2.2.12
:release_version: 2.3.0
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:
+2 -2
View File
@@ -245,7 +245,7 @@ static BOOL debugLeaks;
}
else
{
NSLog (@"No value specified for '%@'", *urlString);
[self errorWithFormat: @"No value specified for '%@'", *urlString];
ok = NO;
}
}
@@ -441,7 +441,7 @@ static BOOL debugLeaks;
if (debugLeaks)
{
if (debugOn)
NSLog (@"allocated classes:\n%s", GSDebugAllocationList (YES));
[self logWithFormat: @"allocated classes:\n%s", GSDebugAllocationList (YES)];
else
{
debugOn = YES;
+4 -4
View File
@@ -1,15 +1,15 @@
/*
Copyright (C) 2004-2005 SKYRIX Software AG
Copyright (C) 2006-2009 Inverse inc.
Copyright (C) 2006-2015 Inverse inc.
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.
+172 -3
View File
@@ -1,3 +1,172 @@
2.3.0 (2015-06-01)
-------------------
New features
- Internet headers are now shown in Outlook (Zentyal)
Enhancements
- improved multipart handling using EAS
- added systemd startup script (PR#76)
- added Basque translation - thanks to Gorka Gonzalez
- updated Brazilian (Portuguese), Dutch, Norwegian (Bokmal), Polish, Russian, and Spanish (Spain) translations Enhancements
- sharing request among different Outlook versions (Zentyal)
- improve sync speed from Outlook by non-reprocessing already downloaded unread mails (Zentyal)
- give support to calendar sharing invitations
- missing contact fields are now saved and available when sharing it (Office, Profession, Manager's name, Assistant's name, Spouse/Partner, Anniversary) (Zentyal)
- appointment color and importance work now between Outlooks (Zentyal)
- synchronize events, contacts and tasks in reverse chronological order (Zentyal)
- during login, we now extract the domain from the user to accelerate authentication requests on sources
- make sure sure email invitations can always be read by EAS clients
- now able to print event/task's description (new components only) in the list view (#2881)
- now possible to log EAS commands using the SOGoEASDebugEnabled system defaults
- many improvements to EAS SmartReply/SmartForward commands
- event invitation response mails are now sent
- mail subfolders created in WebMail are created when Outlook synchronises
- mail root folder created in WebMail (same level INBOX) are created on Outlook logon
Bug fixes
- now keep the BodyPreference for future EAS use and default to MIME if none set (#3146)
- EAS reply fix when message/rfc822 parts are included in the original mail (#3153)
- fixed yet an other potential crash during freebusy lookups during timezone changes
- fixed display of freebusy information in event attendees editor during timezone changes
- fixed timezone of MSExchange freebusy information
- fixed a potential EAS error with multiple email priority flags
- fixed paragraphs margins in HTML messages (#3163)
- fixed regression when loading the inbox for the first time
- fixed serialization of the PreventInvitationsWhitelist settings
- fixed md4 support (for NTLM password changes) with GNU TLS
- fixed edition of attachment URL in event/task editor
- sent mails are not longer in Drafts folder using Outlook (Zentyal)
- deleted mails are properly synced between Outlook profiles from the same account (Zentyal)
- does not create a mail folder in other user's mailbox (Zentyal)
- fix server-side crash with invalid events (Zentyal)
- fix setting permissions for a folder with several users (Zentyal)
- fix reception of calendar event invitations on optional attendees (Zentyal)
- fix server side crash parsing rtf without color table (Zentyal)
- weekly recurring events created in SOGo web interface are now shown in Outlook (Zentyal)
- fix exception modifications import in recurrence series (Zentyal)
- fix server side crash parsing rtf emails with images (with word97 format) (Zentyal)
- fix sender on importing email messages like event invitations (Zentyal)
- fix Outlook crashes when modifying the view of a folder (Zentyal)
- fix server side crash when reading some recurrence appointments (Zentyal)
- Outlook clients can use reply all functionality on multidomain environment (Zentyal)
- optional attendes on events are now shown properly (Zentyal)
- fixed the EAS maximum response size being per-folder, and not global
- now set MeetingMessageType only for EAS 14.1
- now correctly handle external invitations using EAS
- now correctly handle multiple email addresses in the GAL over EAS (#3102)
- now handle very large amount of participants correctly (#3175)
- fix message bodies not shown on some EAS devices (#3173)
- avoid appending the domain unconditionally when SOGoEnableDomainBasedUID is set to YES
- recurrent all day events are now shown properly in Outlook
2.2.17a (2015-03-15)
--------------------
Bug fixes
- avoid calling -stringByReplacingOccurrencesOfString:... for old GNUstep runtime
2.2.17 (2015-03-24)
-------------------
Enhancements
- support for mail prority using EAS
- immediately delete mails from EAS clients when they are marked as deleted on the IMAP server
- now favor login@domain as the default email address if multiple mail: fields are specified
- enable by default HTML mails support using EAS on Windows and BB phones
- now possible to configure objectClass names for LDAP groups using GroupObjectClasses (#1499)
Bug fixes
- fixed login issue after password change (#2601)
- fixed potential encoding issue using EAS and 8-bit mails (#3116)
- multiple collections support for GetItemEstimate using EAS
- fixed empty sync responses for EAS 2.5 and 12.0 clients
- use the correct mail body element for EAS 2.5 clients
- fixed tasks disappearing issue with RoadSync
- use the correct body element for events for EAS 2.5 clients
- SmartReply improvements for missing body attributes
- do not use syncKey from cache when davCollectionTag = -1
- use correct mail attachment elements for EAS 2.5 clients
- fixed contacts lookup by UID in freebusy
- reduced telephone number to a single value in JSON response of contacts list
- fixed freebusy data when 'busy off hours' is enabled and period starts during the weekend
- fixed fetching of freebusy data from the Web interface
- fixed EAS handling of Bcc in emails (#3138)
- fixed Language-Region tags in Web interface (#3121)
- properly fallback over EAS to UTF-8 and then Latin1 for messages w/o charset (#3103)
- prevent potential freebusy lookup crashes during timezone changes with repetitive events
- improved GetItemEstimate to count all vasnished/deleted mails too
- improvements to EAS SyncKey handling to avoid missing mails (#3048, #3058)
- fixed EAS replies decoding from Outlook (#3123)
2.2.16 (2015-02-12)
-------------------
New features
- now possible for SOGo to change the sambaNTPassword/sambaLMPassword
- now possible to limit automatic forwards to internal/external domains
Enhancements
- added support for email categories using EAS (#2995)
- now possible to always send vacation messages (#2332)
- added EAS best practices to the documentation
- improved fetching of text parts over EAS
- updated Czech, Finnish, French, German and Hungarian translations
Bug fixes
- (regression) fixed sending a message when mail module is not active (#3088)
- mail labels with blanks are not handled correctly (#3078)
- fixed BlackBerry issues sending multiple mails over EAS (#3095)
- fixed plain/text mails showing on one line on Android/EAS (#3055)
- fixed exception in sogo-tool when parsing arguments of a set operation
2.2.15 (2015-01-30)
-------------------
Enhancements
- improved handling of EAS Push when no heartbeat is provided
- no longer need to kill Outlook 2013 when creating EAS profiles (#3076)
- improved server-side CSS cleaner (#3040)
- unified the logging messages in sogo.log file (#2534/#3063)
- updated Brazilian (Portuguese) and Hungarian translations
2.2.14 (2015-01-20)
-------------------
Enhancements
- MultipleBookingsFieldName can be set to -1 to show busy status when booked at least once
- handle multipart objects in EAS/ItemOperations
Bug fixes
- fixed calendar selection in event and task editors (#3049, #3050)
- check for resources existence when listing subscribed ones (#3054)
- correctly recognize Apple Calendar on Yosemite (#2960)
- fixed two potential autorelease pool leaks (#3026 and #3051)
- fixed birthday offset in EAS
- fixed From's full name over EAS
- fixed potential issue when handling multiple Add/Change/Delete/Fetch EAS commands (#3057)
- fixed wrong timezone calculation on recurring events
2.2.13 (2014-12-30)
-------------------
Enhancements
- initial support for empty sync request/response for EAS
- added the SOGoMaximumSyncResponseSize EAS configuration parameter to
support memory-limited sync response sizes
- we now not only use the creation date for event's cutoff date (EAS)
Bug fixes
- fixed contact description truncation on WP8 phones (#3028)
- fixed freebusy information not always returned
- fixed tz issue when the user one was different from the system one with EAS
2.2.12a (2014-12-19)
--------------------
Bug fixes
- fixed empty HTML mails being sent (#3034)
2.2.12 (2014-12-18)
-------------------
@@ -12,12 +181,12 @@ Enhancements
- updated Czech, Dutch, Finnish, French, German, Polish and Spanish (Spain) translations
Bug fixes
- fix for privacy and categories for EAS (#3022)
- fixed for privacy and categories for EAS (#3022)
- correctly set MeetingStatus for EAS on iOS devices
- Ubuntu Lucid fixes for EAS
- fix calendar reminders for future events (#3008)
- fixed calendar reminders for future events (#3008)
- make sure all text parts are UTF-8 re-encoded for Outlook 2013 over EAS (#3003)
- fix task description truncation affecting WP8 phones over EAS (#3028)
- fixed task description truncation affecting WP8 phones over EAS (#3028)
2.2.11a (2014-12-10)
--------------------
+34
View File
@@ -0,0 +1,34 @@
/* Codepages.h - this file is part of SOGo
*
* Copyright (C) 2014 Jesús García Sáez
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSDictionary.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSString.h>
@interface Codepages
+ (NSDictionary *) getCodepagesTable;
+ (NSDictionary *) getReverseCodepagesTable;
+ (NSNumber *) getCodepageFromName: (NSString *) name;
+ (NSString *) getNameFromCodepage: (NSNumber *) codepage;
@end
+214
View File
@@ -0,0 +1,214 @@
/* Codepages.m - this file is part of SOGo
*
* Copyright (C) 2014 Jesús García Sáez
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import "Codepages.h"
#import <Foundation/NSArray.h>
@implementation Codepages
+ (NSDictionary *) getCodepagesTable
{
static NSDictionary *table = nil;
if (table == nil)
{
/* http://msdn.microsoft.com/en-us/library/dd317756%28v=vs.85%29.aspx */
table = [[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt: 37], @"ibm037",
[NSNumber numberWithInt: 437], @"ibm437",
[NSNumber numberWithInt: 500], @"ibm500",
[NSNumber numberWithInt: 708], @"asmo-708",
[NSNumber numberWithInt: 720], @"dos-720",
[NSNumber numberWithInt: 737], @"ibm737",
[NSNumber numberWithInt: 775], @"ibm775",
[NSNumber numberWithInt: 850], @"ibm850",
[NSNumber numberWithInt: 852], @"ibm852",
[NSNumber numberWithInt: 855], @"ibm855",
[NSNumber numberWithInt: 857], @"ibm857",
[NSNumber numberWithInt: 858], @"ibm00858",
[NSNumber numberWithInt: 860], @"ibm860",
[NSNumber numberWithInt: 861], @"ibm861",
[NSNumber numberWithInt: 862], @"dos-862",
[NSNumber numberWithInt: 863], @"ibm863",
[NSNumber numberWithInt: 864], @"ibm864",
[NSNumber numberWithInt: 865], @"ibm865",
[NSNumber numberWithInt: 866], @"cp866",
[NSNumber numberWithInt: 869], @"ibm869",
[NSNumber numberWithInt: 870], @"ibm870",
[NSNumber numberWithInt: 874], @"windows-874",
[NSNumber numberWithInt: 875], @"cp875",
[NSNumber numberWithInt: 932], @"shift_jis",
[NSNumber numberWithInt: 936], @"gb2312",
[NSNumber numberWithInt: 949], @"ks_c_5601-1987",
[NSNumber numberWithInt: 950], @"big5",
[NSNumber numberWithInt: 1026], @"ibm1026",
[NSNumber numberWithInt: 1047], @"ibm01047",
[NSNumber numberWithInt: 1140], @"ibm01140",
[NSNumber numberWithInt: 1141], @"ibm01141",
[NSNumber numberWithInt: 1142], @"ibm01142",
[NSNumber numberWithInt: 1143], @"ibm01143",
[NSNumber numberWithInt: 1144], @"ibm01144",
[NSNumber numberWithInt: 1145], @"ibm01145",
[NSNumber numberWithInt: 1146], @"ibm01146",
[NSNumber numberWithInt: 1147], @"ibm01147",
[NSNumber numberWithInt: 1148], @"ibm01148",
[NSNumber numberWithInt: 1149], @"ibm01149",
[NSNumber numberWithInt: 1200], @"utf-16",
[NSNumber numberWithInt: 1201], @"unicodefffe",
[NSNumber numberWithInt: 1250], @"windows-1250",
[NSNumber numberWithInt: 1251], @"windows-1251",
[NSNumber numberWithInt: 1252], @"windows-1252",
[NSNumber numberWithInt: 1253], @"windows-1253",
[NSNumber numberWithInt: 1254], @"windows-1254",
[NSNumber numberWithInt: 1255], @"windows-1255",
[NSNumber numberWithInt: 1256], @"windows-1256",
[NSNumber numberWithInt: 1257], @"windows-1257",
[NSNumber numberWithInt: 1258], @"windows-1258",
[NSNumber numberWithInt: 1361], @"johab",
[NSNumber numberWithInt: 10000], @"macintosh",
[NSNumber numberWithInt: 10001], @"x-mac-japanese",
[NSNumber numberWithInt: 10002], @"x-mac-chinesetrad",
[NSNumber numberWithInt: 10003], @"x-mac-korean",
[NSNumber numberWithInt: 10004], @"x-mac-arabic",
[NSNumber numberWithInt: 10005], @"x-mac-hebrew",
[NSNumber numberWithInt: 10006], @"x-mac-greek",
[NSNumber numberWithInt: 10007], @"x-mac-cyrillic",
[NSNumber numberWithInt: 10008], @"x-mac-chinesesimp",
[NSNumber numberWithInt: 10010], @"x-mac-romanian",
[NSNumber numberWithInt: 10017], @"x-mac-ukrainian",
[NSNumber numberWithInt: 10021], @"x-mac-thai",
[NSNumber numberWithInt: 10029], @"x-mac-ce",
[NSNumber numberWithInt: 10079], @"x-mac-icelandic",
[NSNumber numberWithInt: 10081], @"x-mac-turkish",
[NSNumber numberWithInt: 10082], @"x-mac-croatian",
[NSNumber numberWithInt: 12000], @"utf-32",
[NSNumber numberWithInt: 12001], @"utf-32be",
[NSNumber numberWithInt: 20000], @"x-chinese-cns",
[NSNumber numberWithInt: 20001], @"x-cp20001",
[NSNumber numberWithInt: 20002], @"x-chinese-eten",
[NSNumber numberWithInt: 20003], @"x-cp20003",
[NSNumber numberWithInt: 20004], @"x-cp20004",
[NSNumber numberWithInt: 20005], @"x-cp20005",
[NSNumber numberWithInt: 20105], @"x-ia5",
[NSNumber numberWithInt: 20106], @"x-ia5-german",
[NSNumber numberWithInt: 20107], @"x-ia5-swedish",
[NSNumber numberWithInt: 20108], @"x-ia5-norwegian",
[NSNumber numberWithInt: 20127], @"us-ascii",
[NSNumber numberWithInt: 20261], @"x-cp20261",
[NSNumber numberWithInt: 20269], @"x-cp20269",
[NSNumber numberWithInt: 20273], @"ibm273",
[NSNumber numberWithInt: 20277], @"ibm277",
[NSNumber numberWithInt: 20278], @"ibm278",
[NSNumber numberWithInt: 20280], @"ibm280",
[NSNumber numberWithInt: 20284], @"ibm284",
[NSNumber numberWithInt: 20285], @"ibm285",
[NSNumber numberWithInt: 20290], @"ibm290",
[NSNumber numberWithInt: 20297], @"ibm297",
[NSNumber numberWithInt: 20420], @"ibm420",
[NSNumber numberWithInt: 20423], @"ibm423",
[NSNumber numberWithInt: 20424], @"ibm424",
[NSNumber numberWithInt: 20833], @"x-ebcdic-koreanextended",
[NSNumber numberWithInt: 20838], @"ibm-thai",
[NSNumber numberWithInt: 20866], @"koi8-r",
[NSNumber numberWithInt: 20871], @"ibm871",
[NSNumber numberWithInt: 20880], @"ibm880",
[NSNumber numberWithInt: 20905], @"ibm905",
[NSNumber numberWithInt: 20924], @"ibm00924",
[NSNumber numberWithInt: 20932], @"euc-jp",
[NSNumber numberWithInt: 20936], @"x-cp20936",
[NSNumber numberWithInt: 20949], @"x-cp20949",
[NSNumber numberWithInt: 21025], @"cp1025",
[NSNumber numberWithInt: 21866], @"koi8-u",
[NSNumber numberWithInt: 28591], @"iso-8859-1",
[NSNumber numberWithInt: 28592], @"iso-8859-2",
[NSNumber numberWithInt: 28593], @"iso-8859-3",
[NSNumber numberWithInt: 28594], @"iso-8859-4",
[NSNumber numberWithInt: 28595], @"iso-8859-5",
[NSNumber numberWithInt: 28596], @"iso-8859-6",
[NSNumber numberWithInt: 28597], @"iso-8859-7",
[NSNumber numberWithInt: 28598], @"iso-8859-8",
[NSNumber numberWithInt: 28599], @"iso-8859-9",
[NSNumber numberWithInt: 28603], @"iso-8859-13",
[NSNumber numberWithInt: 28605], @"iso-8859-15",
[NSNumber numberWithInt: 29001], @"x-europa",
[NSNumber numberWithInt: 38598], @"iso-8859-8-i",
[NSNumber numberWithInt: 50220], @"iso-2022-jp",
[NSNumber numberWithInt: 50221], @"csiso2022jp",
[NSNumber numberWithInt: 50222], @"iso-2022-jp",
[NSNumber numberWithInt: 50225], @"iso-2022-kr",
[NSNumber numberWithInt: 50227], @"x-cp50227",
[NSNumber numberWithInt: 51932], @"euc-jp",
[NSNumber numberWithInt: 51936], @"euc-cn",
[NSNumber numberWithInt: 51949], @"euc-kr",
[NSNumber numberWithInt: 52936], @"hz-gb-2312",
[NSNumber numberWithInt: 54936], @"gb18030",
[NSNumber numberWithInt: 57002], @"x-iscii-de",
[NSNumber numberWithInt: 57003], @"x-iscii-be",
[NSNumber numberWithInt: 57004], @"x-iscii-ta",
[NSNumber numberWithInt: 57005], @"x-iscii-te",
[NSNumber numberWithInt: 57006], @"x-iscii-as",
[NSNumber numberWithInt: 57007], @"x-iscii-or",
[NSNumber numberWithInt: 57008], @"x-iscii-ka",
[NSNumber numberWithInt: 57009], @"x-iscii-ma",
[NSNumber numberWithInt: 57010], @"x-iscii-gu",
[NSNumber numberWithInt: 57011], @"x-iscii-pa",
[NSNumber numberWithInt: 65000], @"utf-7",
[NSNumber numberWithInt: 65001], @"utf-8",
nil] retain];
}
return table;
}
+ (NSDictionary *) getReverseCodepagesTable
{
static NSDictionary *table = nil;
if (table == nil)
{
NSDictionary *codepages_table;
NSEnumerator *enumerator;
NSMutableArray *codepages, *names;
id key;
// Build reverse table: (NSNumber) codepage -> (NSString) encoding name
codepages_table = [self getCodepagesTable];
codepages = [NSMutableArray arrayWithCapacity: [codepages_table count]];
names = [NSMutableArray arrayWithCapacity: [codepages_table count]];
enumerator = [codepages_table keyEnumerator];
while ((key = [enumerator nextObject]))
{
[names addObject: key];
[codepages addObject: [codepages_table objectForKey: key]];
}
table = [[NSDictionary dictionaryWithObjects: names forKeys: codepages] retain];
}
return table;
}
+ (NSNumber *) getCodepageFromName: (NSString *) name
{
return [[self getCodepagesTable] objectForKey: [name lowercaseString]];
}
+ (NSString *) getNameFromCodepage: (NSNumber *) codepage
{
return [[self getReverseCodepagesTable] objectForKey: codepage];
}
@end
+8 -3
View File
@@ -31,7 +31,7 @@ endif
all::
@echo " Python executable: ${PYTHON}"
SAMBA_PRIVATE_DIR = $(shell $(PYTHON) ./samba-get-config.py "private dir")
SAMBA_PRIVATE_DIR = $(shell $(PYTHON) ./samba-get-config.py 'private dir' || echo /var/lib/samba/private)
$(SOGOBACKEND)_PRINCIPAL_CLASS = MAPIApplication
@@ -100,6 +100,7 @@ $(SOGOBACKEND)_OBJC_FILES += \
MAPIStoreMailAttachment.m \
MAPIStoreMailContext.m \
MAPIStoreMailFolder.m \
MAPIStoreMailFolderTable.m \
MAPIStoreMailMessage.m \
MAPIStoreMailVolatileMessage.m \
MAPIStoreMailMessageTable.m \
@@ -110,6 +111,8 @@ $(SOGOBACKEND)_OBJC_FILES += \
\
MAPIStoreFallbackContext.m \
\
MAPIStoreSharingMessage.m \
\
NSArray+MAPIStore.m \
NSData+MAPIStore.m \
NSDate+MAPIStore.m \
@@ -120,7 +123,9 @@ $(SOGOBACKEND)_OBJC_FILES += \
iCalEvent+MAPIStore.m \
iCalTimeZone+MAPIStore.m \
\
RTFHandler.m
RTFHandler.m \
\
Codepages.m
$(SOGOBACKEND)_RESOURCE_FILES += \
@@ -171,7 +176,7 @@ $(SOGOBACKEND)_LIB_DIRS += \
$(LIBMAPISTORE_LIBS)
ADDITIONAL_INCLUDE_DIRS += \
-Werror -Wall \
-Wall \
-DSAMBA_PRIVATE_DIR=@"\"$(SAMBA_PRIVATE_DIR)\"" \
$(LIBMAPI_CFLAGS) \
$(LIBMAPISTORE_CFLAGS) \
+94 -29
View File
@@ -45,6 +45,7 @@
#import "MAPIStoreRecurrenceUtils.h"
#import "MAPIStoreSamDBUtils.h"
#import "MAPIStoreTypes.h"
#import "NSArray+MAPIStore.h"
#import "NSData+MAPIStore.h"
#import "NSDate+MAPIStore.h"
#import "NSObject+MAPIStore.h"
@@ -263,7 +264,7 @@ static NSCharacterSet *hexCharacterSet = nil;
if (contactInfos)
{
username = [contactInfos objectForKey: @"c_uid"];
username = [contactInfos objectForKey: @"sAMAccountName"];
recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username);
}
@@ -272,7 +273,7 @@ static NSCharacterSet *hexCharacterSet = nil;
recipient->username = NULL;
entryId = MAPIStoreExternalEntryId (cn, email);
}
recipient->type = MAPI_TO;
recipient->type = [[person role] isEqualToString: @"OPT-PARTICIPANT"] ? MAPI_CC : MAPI_TO;
/* properties */
p = 0;
@@ -282,7 +283,7 @@ static NSCharacterSet *hexCharacterSet = nil;
// PR_OBJECT_TYPE = MAPI_MAILUSER (see MAPI_OBJTYPE)
recipient->data[p] = MAPILongValue (msgData, MAPI_MAILUSER);
p++;
// PR_DISPLAY_TYPE = DT_MAILUSER (see MS-NSPI)
recipient->data[p] = MAPILongValue (msgData, 0);
p++;
@@ -364,7 +365,7 @@ static NSCharacterSet *hexCharacterSet = nil;
if (contactInfos)
{
username = [contactInfos objectForKey: @"c_uid"];
username = [contactInfos objectForKey: @"sAMAccountName"];
recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username);
}
@@ -382,7 +383,7 @@ static NSCharacterSet *hexCharacterSet = nil;
// PR_OBJECT_TYPE = MAPI_MAILUSER (see MAPI_OBJTYPE)
recipient->data[p] = MAPILongValue (msgData, MAPI_MAILUSER);
p++;
// PR_DISPLAY_TYPE = DT_MAILUSER (see MS-NSPI)
recipient->data[p] = MAPILongValue (msgData, 0);
p++;
@@ -791,11 +792,20 @@ static NSCharacterSet *hexCharacterSet = nil;
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc;
NSCalendarDate *dateValue;
NSCalendarDate *dateValue, *start;
if ([event isRecurrent])
{
dateValue = [[event startDate] hour: 0 minute: 0 second: 0];
/* [MS-OXOCAL] For a recurring series, this property specifies
midnight in the user's machine time zone, on the date of the
first instance, then is persisted in UTC. */
start = [event startDate];
dateValue = [NSCalendarDate dateWithYear: [start yearOfCommonEra]
month: [start monthOfYear]
day: [start dayOfMonth]
hour: 0 minute: 0 second: 0
timeZone: timeZone];
[dateValue setTimeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
@@ -894,7 +904,7 @@ static NSCharacterSet *hexCharacterSet = nil;
}
else
dateValue = [NSCalendarDate dateWithYear: 4500 month: 8 day: 31
hour: 23 minute: 59 second: 59
hour: 23 minute: 59 second: 00
timeZone: utcTZ];
*data = [dateValue asFileTimeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
@@ -921,7 +931,7 @@ static NSCharacterSet *hexCharacterSet = nil;
contactInfos = [mgr contactInfosForUserWithUIDorEmail: email];
if (contactInfos)
{
username = [contactInfos objectForKey: @"c_uid"];
username = [contactInfos objectForKey: @"sAMAccountName"];
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username);
}
else
@@ -1191,11 +1201,31 @@ static NSCharacterSet *hexCharacterSet = nil;
return [self getYes: data inMemCtx: memCtx];
}
- (int) getPidTagSensitivity: (void **) data // not implemented, depends on CLASS
- (int) getPidTagSensitivity: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
// normal = 0, personal?? = 1, private = 2, confidential = 3
return [self getLongZero: data inMemCtx: memCtx];
/* See [MS-OXCICAL] Section 2.1.3.11.20.4 */
uint32_t v;
NSString *accessClass;
accessClass = [event accessClass];
if (accessClass)
{
if ([accessClass isEqualToString: @"X-PERSONAL"])
v = 0x1;
else if ([accessClass isEqualToString: @"PRIVATE"])
v = 0x2;
else if ([accessClass isEqualToString: @"CONFIDENTIAL"])
v = 0x3;
else
v = 0x0; /* PUBLIC */
}
else
v = 0x0; /* PUBLIC */
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
}
- (int) getPidTagImportance: (void **) data
@@ -1214,6 +1244,22 @@ static NSCharacterSet *hexCharacterSet = nil;
return MAPISTORE_SUCCESS;
}
- (int) getPidNameKeywords: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
/* See [MS-OXCICAL] Section 2.1.3.1.1.20.3 */
NSArray *categories;
categories = [event categories];
if (categories)
{
*data = [categories asMVUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
else
return MAPISTORE_ERR_NOT_FOUND;
}
- (int) getPidTagBody: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -1231,7 +1277,7 @@ static NSCharacterSet *hexCharacterSet = nil;
/* Avoiding those trail weird characters at event description */
range = [stringValue rangeOfString: trimingString
options: NSBackwardsSearch];
if (range.location > 0)
if (range.location != NSNotFound)
{
stringValue = [stringValue substringToIndex: (NSMaxRange(range) -1)];
}
@@ -1415,8 +1461,6 @@ static NSCharacterSet *hexCharacterSet = nil;
firstStartDate = [event firstRecurrenceStartDate];
if (firstStartDate)
{
[firstStartDate setTimeZone: timeZone];
arp = talloc_zero (NULL, struct AppointmentRecurrencePattern);
[rule fillRecurrencePattern: &arp->RecurrencePattern
withEvent: event
@@ -1426,6 +1470,12 @@ static NSCharacterSet *hexCharacterSet = nil;
arp->WriterVersion2 = 0x00003008; /* 0x3008 for compatibility with
ol2003 */
/* All day events' dates are specified in floating time
([MS-OXCICAL] 2.1.3.1.1.20.10). The StartTimeOffset and EndTimeOffset
fields are relative to midnight of those days ([MS-OXOCAL] 2.2.1.44.5),
so no time zone adjustment is needed */
if (![event isAllDay])
[firstStartDate setTimeZone: timeZone];
startMinutes = ([firstStartDate hourOfDay] * 60
+ [firstStartDate minuteOfHour]);
arp->StartTimeOffset = startMinutes;
@@ -1826,16 +1876,25 @@ ReservedBlockEE2Size: 00 00 00 00
NSArray *alarms;
NSUInteger count, max;
iCalAlarm *currentAlarm;
NSString *action;
NSString *action, *webstatus;
alarms = [event alarms];
max = [alarms count];
for (count = 0; !alarm && count < max; count++)
{
currentAlarm = [alarms objectAtIndex: count];
action = [[currentAlarm action] lowercaseString];
if (!action || [action isEqualToString: @"display"])
ASSIGN (alarm, currentAlarm);
// Only handle 'display' alarms
action = [currentAlarm action];
if ([action caseInsensitiveCompare: @"display"] != NSOrderedSame)
continue;
// Ignore alarms already triggered
webstatus = [[currentAlarm trigger] value: 0 ofAttribute: @"x-webstatus"];
if ([webstatus caseInsensitiveCompare: @"triggered"] == NSOrderedSame)
continue;
ASSIGN (alarm, currentAlarm);
}
alarmSet = YES;
@@ -2014,17 +2073,23 @@ ReservedBlockEE2Size: 00 00 00 00
enum mapistore_error rc;
iCalTimeZone *icalTZ;
if ([event isRecurrent])
/* [MS-OXOCAL] 3.1.5.5.1: This property is used in floating (all-day) events,
specified in floating time, to convert the start date from UTC to the user's
time zone */
if ([event isAllDay])
icalTZ = [iCalTimeZone timeZoneForName: [timeZone timeZoneName]];
else if ([event isRecurrent])
icalTZ = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] timeZone];
else
icalTZ = nil;
if (icalTZ)
{
icalTZ = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] timeZone];
if (icalTZ)
{
*data = [icalTZ asZoneTimeDefinitionWithFlags: TZRULE_FLAG_EFFECTIVE_TZREG | TZRULE_FLAG_RECUR_CURRENT_TZREG
inMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
else
rc = MAPISTORE_ERR_NOT_FOUND;
/* [MS-OXOCAL] 2.2.1.42: This property can only have the E flag set in the
TimeZoneDefinition struct */
*data = [icalTZ asZoneTimeDefinitionWithFlags: TZRULE_FLAG_EFFECTIVE_TZREG
inMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
else
rc = MAPISTORE_ERR_NOT_FOUND;
+27 -2
View File
@@ -100,6 +100,14 @@
[roles addObject: SOGoCalendarRole_PrivateViewer];
[roles addObject: SOGoCalendarRole_ConfidentialViewer];
}
if (rights & RightsFreeBusySimple)
{
[roles addObject: SOGoCalendarRole_PublicDAndTViewer];
}
if (rights & RightsFreeBusyDetailed)
{
[roles addObject: SOGoCalendarRole_ConfidentialDAndTViewer];
}
// [self logWithFormat: @"roles for rights %.8x = (%@)", rights, roles];
@@ -121,12 +129,21 @@
else if ([roles containsObject: SOGoCalendarRole_PublicViewer]
&& [roles containsObject: SOGoCalendarRole_PrivateViewer]
&& [roles containsObject: SOGoCalendarRole_ConfidentialViewer])
rights |= RightsReadItems | 0x1800;
// We have to set by hand other rights as only the highest role is returned
// See SOGoAppointmentFolder.m:aclsForUser for details
rights |= RightsReadItems | RightsFreeBusySimple | RightsFreeBusyDetailed;
if ([roles containsObject: SOGoCalendarRole_PublicDAndTViewer])
rights |= RightsFreeBusySimple;
if ([roles containsObject: SOGoCalendarRole_ConfidentialDAndTViewer])
rights |= RightsFreeBusyDetailed;
if (rights != 0)
rights |= RoleNone; /* actually "folder visible" */
// [self logWithFormat: @"rights for roles (%@) = %.8x", roles, rights];
return rights;
}
@@ -169,6 +186,14 @@
[(SOGoAppointmentFolder *) sogoObject aclSQLListingFilter]];
}
- (int) getPidTagContainerClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"IPF.Appointment" asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidTagDefaultPostMessageClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
+68 -88
View File
@@ -81,7 +81,7 @@
// extern void ndr_print_AppointmentRecurrencePattern(struct ndr_print *ndr, const char *name, const struct AppointmentRecurrencePattern *r);
static Class NSArrayK;
static Class NSArrayK, MAPIStoreAppointmentWrapperK;
@implementation SOGoAppointmentObject (MAPIStoreExtension)
@@ -97,6 +97,7 @@ static Class NSArrayK;
+ (void) initialize
{
NSArrayK = [NSArray class];
MAPIStoreAppointmentWrapperK = [MAPIStoreAppointmentWrapper class];
}
+ (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP
@@ -180,6 +181,12 @@ static Class NSArrayK;
else
{
origCalendar = [sogoObject calendar: YES secure: YES];
if (!origCalendar)
{
[self errorWithFormat: @"Incorrect calendar event %@. Empty message is created",
[self url]];
return self;
}
calendar = [origCalendar mutableCopy];
masterEvent = [[calendar events] objectAtIndex: 0];
[self _setupAttachmentParts];
@@ -205,13 +212,23 @@ static Class NSArrayK;
[super dealloc];
}
/* getters */
- (int) getPidLidFInvited: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
- (MAPIStoreAppointmentWrapper *) _appointmentWrapper
{
return [self getYes: data inMemCtx: memCtx];
NSUInteger i, max;
id proxy;
max = [proxies count];
for (i = 0; i < max; i++) {
proxy = [proxies objectAtIndex: i];
if ([proxy isKindOfClass: MAPIStoreAppointmentWrapperK])
{
return proxy;
}
}
return nil;
}
/* getters */
- (int) getPidTagMessageClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -324,100 +341,63 @@ static Class NSArrayK;
}
else
{
/* HACK: we know the first (and only) proxy is our appointment wrapper
instance, but this might not always be true */
[[proxies objectAtIndex: 0] fillMessageData: msgData
inMemCtx: memCtx];
[[self _appointmentWrapper] fillMessageData: msgData
inMemCtx: memCtx];
}
*dataPtr = msgData;
}
/* sender representing */
// - (int) getPidTagSentRepresentingEmailAddress: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagSenderEmailAddress: data inMemCtx: memCtx];
// }
// - (int) getPidTagSentRepresentingAddressType: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getSMTPAddrType: data inMemCtx: memCtx];
// }
// - (int) getPidTagSentRepresentingName: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagSenderName: data inMemCtx: memCtx];
// }
// - (int) getPidTagSentRepresentingEntryId: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagSenderEntryId: data inMemCtx: memCtx];
// }
/* attendee */
// - (int) getPidTagReceivedByAddressType: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [appointmentWrapper getPidTagReceivedByAddressType: data
// inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedByEmailAddress: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [appointmentWrapper getPidTagReceivedByEmailAddress: data
// inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedByName: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [appointmentWrapper getPidTagReceivedByName: data
// inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedByEntryId: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [appointmentWrapper getPidTagReceivedByEntryId: data
// inMemCtx: memCtx];
// }
// /* attendee representing */
// - (int) getPidTagReceivedRepresentingEmailAddress: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagReceivedByEmailAddress: data inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedRepresentingAddressType: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getSMTPAddrType: data inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedRepresentingName: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagReceivedByName: data inMemCtx: memCtx];
// }
// - (int) getPidTagReceivedRepresentingEntryId: (void **) data
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// return [self getPidTagReceivedByEntryId: data inMemCtx: memCtx];
// }
- (int) getPidTagResponseRequested: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getYes: data inMemCtx: memCtx];
}
/* This three methods: getPidTagNormalizedSubject,
getPidTagSensitivity and getPidTagImportance are implemented in
MAPIStoreMessage base class, then the proxy method is not reached
(see MAPIStoreObject).
*/
- (int) getPidTagNormalizedSubject: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
MAPIStoreAppointmentWrapper *appointmentWrapper;
appointmentWrapper = [self _appointmentWrapper];
if (appointmentWrapper)
return [appointmentWrapper getPidTagNormalizedSubject: data inMemCtx: memCtx];
return MAPISTORE_ERR_NOT_FOUND;
}
- (int) getPidTagSensitivity: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
MAPIStoreAppointmentWrapper *appointmentWrapper;
appointmentWrapper = [self _appointmentWrapper];
if (appointmentWrapper)
return [appointmentWrapper getPidTagSensitivity: data inMemCtx: memCtx];
return [self getLongZero: data inMemCtx: memCtx];
}
- (int) getPidTagImportance: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
MAPIStoreAppointmentWrapper *appointmentWrapper;
appointmentWrapper = [self _appointmentWrapper];
if (appointmentWrapper)
return [appointmentWrapper getPidTagImportance: data inMemCtx: memCtx];
*data = MAPILongValue (memCtx, 1);
return MAPISTORE_SUCCESS;
}
- (NSString *) _uidFromGlobalObjectId: (TALLOC_CTX *) memCtx
{
NSData *objectId;
@@ -182,6 +182,9 @@ static Class MAPIStoreCalendarMessageK = Nil;
forKey: MAPIPropertyKey (PR_CREATION_TIME)];
[knownProperties setObject: @"c_uid"
forKey: MAPIPropertyKey (PR_OWNER_APPT_ID)];
/* Use by oxcfxics to sort the latest first */
[knownProperties setObject: @"c_lastmodified"
forKey: MAPIPropertyKey (PidTagMessageDeliveryTime)];
}
return [knownProperties objectForKey: MAPIPropertyKey (property)];
+169 -1
View File
@@ -170,6 +170,21 @@
return MAPISTORE_SUCCESS;
}
- (int) getPidTagProfession: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[sogoObject vCard] role];
if (stringValue)
*data = [stringValue asUnicodeInMemCtx: memCtx];
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (int) getPidTagCompanyName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -723,6 +738,107 @@
return rc;
}
- (int) getPidTagWeddingAnniversary: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSCalendarDate *dateValue;
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-anniversary"]
flattenedValuesForKey: @""];
if (stringValue && ! [stringValue isEqualToString: @""])
{
dateValue = [NSCalendarDate dateWithString: stringValue
calendarFormat: @"%Y-%m-%d"];
*data = [dateValue asFileTimeInMemCtx: memCtx];
}
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (int) getPidTagSpouseName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-spouse"]
flattenedValuesForKey: @""];
if (stringValue)
*data = [stringValue asUnicodeInMemCtx: memCtx];
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (int) getPidTagManagerName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-manager"]
flattenedValuesForKey: @""];
if (stringValue)
*data = [stringValue asUnicodeInMemCtx: memCtx];
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (int) getPidTagAssistant: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-assistant"]
flattenedValuesForKey: @""];
if (stringValue)
*data = [stringValue asUnicodeInMemCtx: memCtx];
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (int) getPidTagOfficeLocation: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-office"]
flattenedValuesForKey: @""];
if (stringValue)
*data = [stringValue asUnicodeInMemCtx: memCtx];
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
- (int) getPidLidFreeBusyLocation: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *stringValue;
int rc = MAPISTORE_SUCCESS;
stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"fburl"]
flattenedValuesForKey: @""];
if (stringValue)
*data = [stringValue asUnicodeInMemCtx: memCtx];
else
rc = MAPISTORE_ERR_NOT_FOUND;
return rc;
}
//
// Decomposed fullname getters
//
@@ -1133,12 +1249,18 @@ fromProperties: (NSDictionary *) attachmentProps
//
// job title, nickname, company name, deparment, work url, im address/screen name and birthday
// job title, profession, nickname, company name, deparment, work url, im address/screen name and birthday
//
value = [properties objectForKey: MAPIPropertyKey(PR_TITLE_UNICODE)];
if (value)
[newCard setTitle: value];
value = [properties objectForKey: MAPIPropertyKey(PR_PROFESSION_UNICODE)];
if (value)
{
[newCard setRole: value];
}
value = [properties objectForKey: MAPIPropertyKey(PR_NICKNAME_UNICODE)];
if (value)
[newCard setNickname: value];
@@ -1173,6 +1295,52 @@ fromProperties: (NSDictionary *) attachmentProps
[newCard setBday: [value descriptionWithCalendarFormat: @"%Y-%m-%d"]];
}
//
// wedding anniversary, spouse's name, manager's name, assistant's name, office location, freebusy location
//
value = [properties objectForKey: MAPIPropertyKey(PidTagWeddingAnniversary)];
if (value)
{
[[newCard uniqueChildWithTag: @"x-ms-anniversary"]
setSingleValue: [value descriptionWithCalendarFormat: @"%Y-%m-%d"]
forKey: @""];
}
value = [properties objectForKey: MAPIPropertyKey(PR_SPOUSE_NAME_UNICODE)];
if (value)
{
[[newCard uniqueChildWithTag: @"x-ms-spouse"]
setSingleValue: value forKey: @""];
}
value = [properties objectForKey: MAPIPropertyKey(PR_MANAGER_NAME_UNICODE)];
if (value)
{
[[newCard uniqueChildWithTag: @"x-ms-manager"]
setSingleValue: value forKey: @""];
}
value = [properties objectForKey: MAPIPropertyKey(PR_ASSISTANT_UNICODE)];
if (value)
{
[[newCard uniqueChildWithTag: @"x-ms-assistant"]
setSingleValue: value forKey: @""];
}
value = [properties objectForKey: MAPIPropertyKey(PR_OFFICE_LOCATION_UNICODE)];
if (value)
{
[[newCard uniqueChildWithTag: @"x-ms-office"]
setSingleValue: value forKey: @""];
}
value = [properties objectForKey: MAPIPropertyKey(PidLidFreeBusyLocation)];
if (value)
{
[[newCard uniqueChildWithTag: @"fburl"]
setSingleValue: value forKey: @""];
}
/* photo */
if ([attachmentParts count] > 0)
{
@@ -220,6 +220,9 @@ static Class MAPIStoreContactsMessageK, NGMailAddressK, NSDataK, NSStringK;
forKey: MAPIPropertyKey (PidTagSubject)];
[knownProperties setObject: @"c_cn"
forKey: MAPIPropertyKey (PidTagNormalizedSubject)];
/* Use by oxcfxics to sort the latest first */
[knownProperties setObject: @"c_lastmodified"
forKey: MAPIPropertyKey (PidTagMessageDeliveryTime)];
}
return [knownProperties objectForKey: MAPIPropertyKey (property)];
+12 -10
View File
@@ -51,6 +51,7 @@
#import "MAPIStoreContext.h"
#undef DEBUG
#include <dlinklist.h>
#include <stdbool.h>
#include <gen_ndr/exchange.h>
#include <util/attr.h>
@@ -276,6 +277,11 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
{
NSString *username;
if (newConnInfo == NULL)
{
return nil;
}
if ((self = [self init]))
{
ASSIGN (contextUrl, newUrl);
@@ -367,8 +373,9 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
NSString *objectURL, *url;
// TDB_DATA key, dbuf;
url = [[contextUrl absoluteString]
stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
url = [contextUrl absoluteString];
// FIXME transform percent escapes but not for user part of the url
//stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
objectURL = [[userContext mapping] urlFromID: fmid];
if (objectURL)
{
@@ -412,7 +419,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
withFID: (uint64_t) newFid
{
enum mapistore_error rc;
MAPIStoreMapping *mapping;
MAPIStoreFolder *baseFolder;
SOGoFolder *currentFolder;
WOContext *woContext;
@@ -420,10 +426,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
NSArray *pathComponents;
NSUInteger count, max;
mapping = [userContext mapping];
if (![mapping urlFromID: newFid])
[mapping registerURL: [contextUrl absoluteString]
withID: newFid];
[userContext activateWithUser: activeUser];
woContext = [userContext woContext];
@@ -549,7 +551,7 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
{
uint64_t newVersionNumber;
if (openchangedb_get_new_changeNumber (connInfo->oc_ctx, &newVersionNumber)
if (openchangedb_get_new_changeNumber (connInfo->oc_ctx, connInfo->username, &newVersionNumber)
!= MAPI_E_SUCCESS)
abort ();
@@ -566,9 +568,9 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
memCtx = talloc_zero(NULL, TALLOC_CTX);
newChangeNumbers = [NSMutableArray arrayWithCapacity: max];
if (openchangedb_get_new_changeNumbers (connInfo->oc_ctx,
memCtx, max, &numbers)
memCtx, connInfo->username, max, &numbers)
!= MAPI_E_SUCCESS || numbers->cValues != max)
abort ();
for (count = 0; count < max; count++)
+23 -7
View File
@@ -138,7 +138,9 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
MAPIStoreMapping *mapping;
NSRange slashRange;
if (isMove && [targetFolder isKindOfClass: MAPIStoreDBFolderK])
pathComponent = nil;
if (isMove && ([targetFolder isKindOfClass: MAPIStoreDBFolderK] || !targetFolder))
{
path = [sogoObject path];
slashRange = [path rangeOfString: @"/" options: NSBackwardsSearch];
@@ -147,14 +149,28 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
format: @"db folder path must start with a '/'"];
else
pathComponent = [path substringFromIndex: slashRange.location + 1];
targetPath = [[targetFolder sogoObject] path];
newPath = [NSString stringWithFormat: @"%@/%@",
targetPath, pathComponent];
[dbFolder changePathTo: newPath];
if (targetFolder)
{
targetPath = [[targetFolder sogoObject] path];
newPath = [NSString stringWithFormat: @"%@/%@",
targetPath, pathComponent];
[dbFolder changePathTo: newPath
intoNewContainer: [targetFolder dbFolder]];
}
else
[dbFolder changePathTo: [NSString stringWithFormat: @"/fallback/%@", pathComponent]
intoNewContainer: nil];
mapping = [self mapping];
newURL = [NSString stringWithFormat: @"%@%@/",
[targetFolder url], pathComponent];
if (targetFolder)
newURL = [NSString stringWithFormat: @"%@%@/",
[targetFolder url], pathComponent];
else
newURL = [NSString stringWithFormat: @"sogo://%@@fallback/%@/",
[[self userContext] username], pathComponent];
[mapping updateID: [self objectId]
withURL: newURL];
+7 -4
View File
@@ -50,19 +50,22 @@
NSUInteger count;
enum MAPITAGS faiProperties[] = { 0x68350102, 0x683c0102, 0x683e0102,
0x683f0102, 0x68410003, 0x68420102,
0x68450102, 0x68460003 };
0x68450102, 0x68460003,
// PR_VD_NAME_W, PR_VD_FLAGS, PR_VD_VERSION, PR_VIEW_CLSID
0x7006001F, 0x70030003, 0x70070003, 0x68330048 };
size_t faiSize = sizeof(faiProperties) / sizeof(enum MAPITAGS);
properties = talloc_zero (memCtx, struct SPropTagArray);
properties->cValues = MAPIStoreSupportedPropertiesCount + 8;
properties->cValues = MAPIStoreSupportedPropertiesCount + faiSize;
properties->aulPropTag = talloc_array (properties, enum MAPITAGS,
MAPIStoreSupportedPropertiesCount + 8);
MAPIStoreSupportedPropertiesCount + faiSize);
for (count = 0; count < MAPIStoreSupportedPropertiesCount; count++)
properties->aulPropTag[count] = MAPIStoreSupportedProperties[count];
/* FIXME (hack): append a few undocumented properties that can be added to
FAI messages */
for (count = 0; count < 8; count++)
for (count = 0; count < faiSize; count++)
properties->aulPropTag[MAPIStoreSupportedPropertiesCount+count]
= faiProperties[count];
+9 -2
View File
@@ -30,6 +30,7 @@
#undef DEBUG
#include <inttypes.h>
#include <dlinklist.h>
#include <mapistore/mapistore.h>
@implementation MAPIStoreFallbackContext
@@ -55,7 +56,10 @@
NSString *baseURL, *url, *name;
MAPIStoreUserContext *userContext;
baseURL = [NSString stringWithFormat: @"sogo://%@@fallback/", userName];
baseURL = [NSString stringWithFormat: @"sogo://%@@fallback/",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"]];
context = talloc_zero (memCtx, struct mapistore_contexts_list);
context->url = [baseURL asUnicodeInMemCtx: context];
@@ -99,7 +103,10 @@
forUser: (NSString *) userName
{
return [NSString stringWithFormat: @"sogo://%@@fallback/0x%.16"PRIx64"/",
userName, (unsigned long long) fid];
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
(unsigned long long) fid];
}
@end
+1 -6
View File
@@ -150,6 +150,7 @@
/* helpers */
- (uint64_t) idForObjectWithKey: (NSString *) childKey;
- (MAPIStoreFolder *) rootContainer;
/* subclasses */
- (MAPIStoreMessage *) createMessage;
@@ -184,12 +185,6 @@
/* subclass helpers */
- (void) setupVersionsMessage;
- (void) ensureIDsForChildKeys: (NSArray *) keys;
- (void) postNotificationsForMoveCopyMessagesWithMIDs: (uint64_t *) srcMids
andMessageURLs: (NSArray *) oldMessageURLs
andCount: (uint32_t) midCount
fromFolder: (MAPIStoreFolder *) sourceFolder
withMIDs: (uint64_t *) targetMids
wantCopy: (uint8_t) wantCopy;
@end
+76 -184
View File
@@ -29,6 +29,7 @@
#import <Foundation/NSString.h>
#import <Foundation/NSURL.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <SOGo/SOGoContentObject.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoFolder.h>
@@ -52,6 +53,7 @@
#import <SOGo/SOGoCacheGCSFolder.h>
#import "SOGoMAPIDBMessage.h"
#import "SOGoCacheGCSObject+MAPIStore.h"
#import <Mailer/SOGoMailObject.h>
#include <gen_ndr/exchange.h>
@@ -100,6 +102,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSUInteger lastPartIdx;
MAPIStoreUserContext *userContext;
parts = 0;
lastPartIdx = 0;
folderURL = [NSURL URLWithString: [self url]];
/* note: -[NSURL path] returns an unescaped representation */
path = [folderURL path];
@@ -231,9 +235,15 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
SOGoFolder *sogoFolder;
WOContext *woContext;
childFolder = nil;
if ([[self folderKeys] containsObject: folderKey])
{
woContext = [[self userContext] woContext];
/* We activate the user for the context using the root folder
context as there are times where the active user is not
matching with the one stored in the application context
and SOGo object is storing cached data with the wrong user */
[[self userContext] activateWithUser: [woContext activeUser]];
sogoFolder = [sogoObject lookupName: folderKey inContext: woContext
acquire: NO];
if (sogoFolder && ![sogoFolder isKindOfClass: NSExceptionK])
@@ -278,6 +288,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
msgObject = [sogoObject lookupName: messageKey
inContext: nil
acquire: NO];
/* If the lookup in the indexing table works, but the IMAP does
not have the message, then the message does not exist in this
folder */
if (msgObject && [msgObject isKindOfClass: [SOGoMailObject class]]
&& ! [(SOGoMailObject *)msgObject doesMailExist])
return nil;
if (msgObject && ![msgObject isKindOfClass: NSExceptionK])
{
[msgObject setContext: [[self userContext] woContext]];
@@ -386,7 +402,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
withRow: (struct SRow *) aRow
andFID: (uint64_t) fid
{
int rc = MAPISTORE_SUCCESS;
BOOL mapped;
enum mapistore_error rc = MAPISTORE_SUCCESS;
MAPIStoreMapping *mapping;
NSString *baseURL, *childURL, *folderKey;
MAPIStoreFolder *childFolder;
@@ -414,7 +431,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
childURL = [NSString stringWithFormat: @"%@%@/",
baseURL,
[folderKey stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
[mapping registerURL: childURL withID: fid];
mapped = [mapping registerURL: childURL withID: fid];
if (!mapped)
/* Enforce the creation if the backend does know the fid */
[mapping updateURL: childURL withID: fid];
childFolder = [self lookupFolder: folderKey];
if (childFolder)
{
@@ -433,16 +455,11 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
return rc;
}
- (void) deleteFolderImpl
- (int) deleteFolder
{
// TODO: raise exception in case underlying delete fails?
// [propsMessage delete];
[dbFolder delete];
}
- (int) deleteFolder
{
[self deleteFolderImpl];
[self cleanupCaches];
@@ -503,6 +520,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
else
rc = MAPISTORE_ERR_DENIED;
}
else
{
/* Unregistering from indexing table as the backend says the
object was not found */
[mapping unregisterURLWithID: mid];
}
}
return rc;
@@ -564,12 +587,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSUInteger count, max;
id msgObject;
SOGoUser *ownerUser;
struct mapistore_connection_info *connInfo;
struct mapistore_object_notification_parameters *notif_parameters;
int rc;
/* flags that control the behaviour of the operation
(MAPISTORE_SOFT_DELETE or MAPISTORE_PERMANENT_DELETE) */
[self logWithFormat: @"-deleteMessageWithMID: mid: 0x%.16llx flags: %d", mid, flags];
mapping = [self mapping];
childURL = [mapping urlFromID: mid];
if (childURL)
@@ -602,51 +625,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
}
else
{
if (![message isNew])
{
/* folder notification */
notif_parameters
= talloc_zero(NULL,
struct mapistore_object_notification_parameters);
notif_parameters->object_id = [self objectId];
notif_parameters->tag_count = 5;
notif_parameters->tags = talloc_array (notif_parameters,
enum MAPITAGS, 5);
notif_parameters->tags[0] = PR_CONTENT_COUNT;
notif_parameters->tags[1] = PR_DELETED_COUNT_TOTAL;
notif_parameters->tags[2] = PR_MESSAGE_SIZE;
notif_parameters->tags[3] = PR_NORMAL_MESSAGE_SIZE;
notif_parameters->tags[4] = PR_DELETED_MSG_COUNT;
notif_parameters->new_message_count = true;
notif_parameters->message_count = [[self messageKeys]
count] - 1;
connInfo = [[self context] connectionInfo];
mapistore_push_notification (connInfo->mstore_ctx,
MAPISTORE_FOLDER,
MAPISTORE_OBJECT_MODIFIED,
notif_parameters);
talloc_free(notif_parameters);
/* message notification */
notif_parameters
= talloc_zero(NULL,
struct mapistore_object_notification_parameters);
notif_parameters->object_id = mid;
notif_parameters->folder_id = [self objectId];
/* Exchange sends a fnevObjectCreated!! */
mapistore_push_notification (connInfo->mstore_ctx,
MAPISTORE_MESSAGE,
MAPISTORE_OBJECT_CREATED,
notif_parameters);
talloc_free(notif_parameters);
/* table notification */
for (count = 0; count < max; count++)
[[activeTables objectAtIndex: count]
notifyChangesForChild: message];
}
[self logWithFormat: @"successfully deleted object at URL: %@", childURL];
[mapping unregisterURLWithID: mid];
/* Ensure we are respecting flags parameter */
[mapping unregisterURLWithID: mid andFlags: flags];
[self cleanupCaches];
rc = MAPISTORE_SUCCESS;
}
@@ -676,6 +657,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
//TALLOC_CTX *memCtx;
struct SRow aRow;
struct SPropValue property;
uint8_t deleteFlags;
[self logWithFormat: @"-moveCopyMessageWithMID: 0x%.16llx .. withMID: 0x%.16llx .. wantCopy: %d", srcMid, targetMid, wantCopy];
@@ -706,7 +688,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
}
[destMsg save: memCtx];
if (!wantCopy)
rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: 0];
/* We want to keep mid for restoring/shared data to work if mids are different. */
deleteFlags = (srcMid == targetMid) ? MAPISTORE_PERMANENT_DELETE : MAPISTORE_SOFT_DELETE;
rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: deleteFlags];
end:
//talloc_free (memCtx);
@@ -767,13 +751,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
/* Notifications */
if (rc == MAPISTORE_SUCCESS)
{
[self postNotificationsForMoveCopyMessagesWithMIDs: srcMids
andMessageURLs: oldMessageURLs
andCount: midCount
fromFolder: sourceFolder
withMIDs: targetMids
wantCopy: wantCopy];
// We cleanup cache of our source and destination folders
[self cleanupCaches];
[sourceFolder cleanupCaches];
@@ -845,7 +822,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (isMove)
{
fmid = [mapping idFromURL: [message url]];
[self deleteMessageWithMID: fmid andFlags: 0];
[self deleteMessageWithMID: fmid andFlags: MAPISTORE_PERMANENT_DELETE];
[mapping registerURL: [targetMessage url]
withID: fmid];
}
@@ -866,7 +843,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (isMove)
{
fmid = [mapping idFromURL: [message url]];
[self deleteMessageWithMID: fmid andFlags: 0];
[self deleteMessageWithMID: fmid andFlags: MAPISTORE_PERMANENT_DELETE];
[mapping registerURL: [targetMessage url]
withID: fmid];
}
@@ -893,16 +870,23 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
}
if (isMove)
{
fmid = [mapping idFromURL: [self url]];
[mapping unregisterURLWithID: fmid];
[self deleteFolderImpl];
[mapping registerURL: [newFolder url]
withID: fmid];
}
[self deleteFolder];
[targetFolder cleanupCaches];
}
[self cleanupCaches];
/* We perform the mapping operations at the
end as objectId is required to be available
until the caches are cleaned up */
if (isMove && rc == MAPISTORE_SUCCESS)
{
fmid = [mapping idFromURL: [self url]];
[mapping unregisterURLWithID: fmid];
[mapping registerURL: [newFolder url]
withID: fmid];
}
}
else
rc = MAPISTORE_ERR_DENIED;
@@ -946,6 +930,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSString *baseURL, *URL, *key;
NSArray *newIDs;
uint64_t idNbr;
bool softDeleted;
baseURL = [self url];
@@ -956,8 +941,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
{
key = [keys objectAtIndex: count];
URL = [NSString stringWithFormat: @"%@%@", baseURL, key];
idNbr = [mapping idFromURL: URL];
if (idNbr == NSNotFound)
idNbr = [mapping idFromURL: URL isSoftDeleted: &softDeleted];
if (idNbr == NSNotFound && !softDeleted)
[missingURLs addObject: URL];
}
@@ -967,113 +952,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
withIDs: newIDs];
}
- (void) postNotificationsForMoveCopyMessagesWithMIDs: (uint64_t *) srcMids
andMessageURLs: (NSArray *) oldMessageURLs
andCount: (uint32_t) midCount
fromFolder: (MAPIStoreFolder *) sourceFolder
withMIDs: (uint64_t *) targetMids
wantCopy: (uint8_t) wantCopy
{
NSArray *activeTables;
NSUInteger count, tableCount, max;
MAPIStoreMessage *message;
NSString *messageURL;
MAPIStoreMapping *mapping;
struct mapistore_object_notification_parameters *notif_parameters;
struct mapistore_connection_info *connInfo;
connInfo = [[self context] connectionInfo];
// For the "source folder, we ensure the table caches are loaded so
// that old and new state can be compared
activeTables = [sourceFolder activeMessageTables];
max = [activeTables count];
for (count = 0; count < max; count++)
[[activeTables objectAtIndex: count] restrictedChildKeys];
if (!wantCopy)
{
// We notify the client. We start with the source folder.
notif_parameters = talloc_zero(NULL, struct mapistore_object_notification_parameters);
notif_parameters->object_id = [sourceFolder objectId];
notif_parameters->tag_count = 5;
notif_parameters->tags = talloc_array (notif_parameters, enum MAPITAGS, 5);
notif_parameters->tags[0] = PR_CONTENT_COUNT;
notif_parameters->tags[1] = PR_DELETED_COUNT_TOTAL;
notif_parameters->tags[2] = PR_MESSAGE_SIZE;
notif_parameters->tags[3] = PR_NORMAL_MESSAGE_SIZE;
notif_parameters->tags[4] = PR_RECIPIENT_ON_NORMAL_MSG_COUNT;
notif_parameters->new_message_count = true;
notif_parameters->message_count = [[sourceFolder messageKeys] count] - midCount;
mapistore_push_notification (connInfo->mstore_ctx,
MAPISTORE_FOLDER,
MAPISTORE_OBJECT_MODIFIED,
notif_parameters);
talloc_free(notif_parameters);
}
// move/copy notification of the copied/moved message
for (count = 0; count < midCount; count++)
{
notif_parameters = talloc_zero (NULL, struct mapistore_object_notification_parameters);
notif_parameters->tag_count = 0;
notif_parameters->new_message_count = true;
notif_parameters->message_count = 0;
notif_parameters->object_id = targetMids[count];
notif_parameters->folder_id = [self objectId];
notif_parameters->old_object_id = srcMids[count];
notif_parameters->old_folder_id = [sourceFolder objectId];
mapistore_push_notification (connInfo->mstore_ctx,
MAPISTORE_MESSAGE,
(wantCopy ? MAPISTORE_OBJECT_COPIED : MAPISTORE_OBJECT_MOVED),
notif_parameters);
talloc_free (notif_parameters);
message = [sourceFolder lookupMessageByURL: [oldMessageURLs objectAtIndex: count]];
// table notification
for (tableCount = 0; tableCount < max; tableCount++)
[[activeTables objectAtIndex: tableCount]
notifyChangesForChild: message];
}
// For the "destination folder, we ensure the table caches are loaded so
// that old and new state can be compared
activeTables = [self activeMessageTables];
max = [activeTables count];
for (count = 0; count < max; count++)
[[activeTables objectAtIndex: count] restrictedChildKeys];
notif_parameters = talloc_zero(NULL, struct mapistore_object_notification_parameters);
notif_parameters->object_id = [self objectId];
notif_parameters->tag_count = 5;
notif_parameters->tags = talloc_array (notif_parameters, enum MAPITAGS, 5);
notif_parameters->tags[0] = PR_CONTENT_COUNT;
notif_parameters->tags[1] = PR_DELETED_COUNT_TOTAL;
notif_parameters->tags[2] = PR_MESSAGE_SIZE;
notif_parameters->tags[3] = PR_NORMAL_MESSAGE_SIZE;
notif_parameters->tags[4] = PR_RECIPIENT_ON_NORMAL_MSG_COUNT;
notif_parameters->new_message_count = true;
notif_parameters->message_count = [[self messageKeys] count] + midCount;
connInfo = [[self context] connectionInfo];
mapistore_push_notification (connInfo->mstore_ctx,
MAPISTORE_FOLDER,
MAPISTORE_OBJECT_MODIFIED,
notif_parameters);
talloc_free(notif_parameters);
// table notification
mapping = [self mapping];
for (count = 0; count < midCount; count++)
{
messageURL = [mapping urlFromID: targetMids[count]];
message = [self lookupMessageByURL: messageURL];
for (tableCount = 0; tableCount < max; tableCount++)
[[activeTables objectAtIndex: tableCount]
notifyChangesForChild: message];
}
}
- (int) getDeletedFMIDs: (struct UI8Array_r **) fmidsPtr
andCN: (uint64_t *) cnPtr
fromChangeNumber: (uint64_t) changeNum
@@ -1088,6 +966,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
MAPIStoreMapping *mapping;
struct UI8Array_r *fmids;
uint64_t fmid;
bool softDeleted;
keys = [self getDeletedKeysFromChangeNumber: changeNum andCN: &cnNbr
inTableType: tableType];
@@ -1114,10 +993,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
{
url = [NSString stringWithFormat: format,
baseURL, [keys objectAtIndex: count]];
fmid = [mapping idFromURL: url];
fmid = [mapping idFromURL: url isSoftDeleted: &softDeleted];
if (fmid != NSNotFound) /* if no fmid is returned, then the object
"never existed" in the OpenChange
databases */
databases. Soft-deleted messages are returned back */
{
fmids->lpui8[fmids->cValues] = fmid;
fmids->cValues++;
@@ -1713,10 +1592,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
aclFolder = [self aclFolder];
users = [aclFolder aclUsers];
users = [[aclFolder aclUsers] copy];
max = [users count];
for (count = 0; count < max; count++)
[aclFolder removeUserFromAcls: [users objectAtIndex: count]];
[users release];
}
- (int) modifyPermissions: (struct PermissionData *) permissions
@@ -1864,6 +1745,17 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
inFolderURL: [self url]];
}
- (MAPIStoreFolder *) rootContainer
{
/* Return the oldest ancestor, which does not have
container. If there is not container, it returns itself.
*/
if (container)
return [container rootContainer];
else
return self;
}
- (NSDate *) creationTime
{
return [dbFolder creationDate];
+6 -2
View File
@@ -82,7 +82,9 @@
andTDBIndexing: indexing];
parentFolder = [[userContext rootFolders] objectForKey: moduleName];
baseUrl = [NSString stringWithFormat: @"sogo://%@@%@/",
userName, moduleName];
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
moduleName];
subfolders = [parentFolder subFolders];
max = [subfolders count];
@@ -127,7 +129,9 @@
if (![parentFolder newFolderWithName: folderName
nameInContainer: &nameInContainer])
mapistoreURI = [NSString stringWithFormat: @"sogo://%@@%@/%@/",
userName, moduleName, nameInContainer];
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
moduleName, nameInContainer];
else
mapistoreURI = nil;
[MAPIApp setUserContext: nil];
+19 -6
View File
@@ -163,8 +163,15 @@
- (int) getPidTagDisplayName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [[bodyInfo objectForKey: @"description"]
asUnicodeInMemCtx: memCtx];
NSString *fileName;
fileName = [self _fileName];
if ([fileName isEqualToString: @"sharing_metadata.xml"])
/* Required to disallow user from seeing the attachment by default */
*data = [@"sharing_metadata.xml" asUnicodeInMemCtx: memCtx];
else
*data = [[bodyInfo objectForKey: @"description"]
asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
@@ -181,11 +188,17 @@
- (int) getPidTagAttachMimeTag: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSString *mimeTag;
NSString *mimeTag, *fileName;
fileName = [self _fileName];
if ([fileName isEqualToString: @"sharing_metadata.xml"])
/* Required by [MS-OXWSMSHR] Section 3.1.1 */
mimeTag = [NSString stringWithFormat: @"application/x-sharing-metadata-xml"];
else
mimeTag = [NSString stringWithFormat: @"%@/%@",
[bodyInfo objectForKey: @"type"],
[bodyInfo objectForKey: @"subtype"]];
mimeTag = [NSString stringWithFormat: @"%@/%@",
[bodyInfo objectForKey: @"type"],
[bodyInfo objectForKey: @"subtype"]];
*data = [[mimeTag lowercaseString] asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
+35 -10
View File
@@ -87,7 +87,7 @@ MakeDisplayFolderName (NSString *folderName)
inMemCtx: (TALLOC_CTX *) memCtx
{
struct mapistore_contexts_list *firstContext = NULL, *context;
NSString *urlBase, *stringData, *currentName, *inboxName, *draftsName, *sentName, *trashName;
NSString *urlBase, *stringData, *currentName, *realName, *inboxName, *draftsName, *sentName, *trashName;
NSArray *unprefixedFolders;
NSMutableArray *secondaryFolders;
enum mapistore_context_role role[] = {MAPISTORE_MAIL_ROLE,
@@ -126,7 +126,11 @@ MakeDisplayFolderName (NSString *folderName)
trashName = [NSString stringWithFormat: @"folder%@",
[unprefixedFolders componentsJoinedByString: @"/folder"]];
urlBase = [NSString stringWithFormat: @"sogo://%@:%@@mail/", userName, userName];
urlBase = [NSString stringWithFormat: @"sogo://%@:%@@mail/",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"]];
for (count = 0; count < 3; count++)
{
context = talloc_zero (memCtx, struct mapistore_contexts_list);
@@ -142,6 +146,9 @@ MakeDisplayFolderName (NSString *folderName)
DLIST_ADD_END (firstContext, context, void);
}
/* FIXME: Flush any cache before retrieving the hierarchy */
[accountFolder flushMailCaches];
secondaryFolders = [[accountFolder toManyRelationshipKeysWithNamespaces: NO]
mutableCopy];
[secondaryFolders autorelease];
@@ -153,12 +160,23 @@ MakeDisplayFolderName (NSString *folderName)
for (count = 0; count < max; count++)
{
context = talloc_zero (memCtx, struct mapistore_contexts_list);
// secondaryFolders has the names (1) Imap4Encoded and (2) asCSSIdentifier
// e.g.: Probl&AOg-mes_SP_de_SP_synchronisation
currentName = [secondaryFolders objectAtIndex: count];
stringData = [NSString stringWithFormat: @"%@%@",
urlBase, [currentName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
context->url = [stringData asUnicodeInMemCtx: context];
stringData = [[[currentName substringFromIndex: 6] fromCSSIdentifier] stringByDecodingImap4FolderName];
context->name = [stringData asUnicodeInMemCtx: context];
// To get the real name we have to revert that (applying the decode functions)
// in reverse order
// e.g.: Problèmes de synchronisation
realName = [[currentName fromCSSIdentifier]
stringByDecodingImap4FolderName];
// And finally to represent that as URI we have to (1) asCSSIdentifier,
// (2) Imap4Encode and (3) AddPercentEscapes
// e.g.: Probl&AOg-mes_SP_de_SP_synchronisation
// In the example there are no percent escapes added because is already ok
stringData = [[[realName asCSSIdentifier]
stringByEncodingImap4FolderName]
stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
context->url = [[NSString stringWithFormat: @"%@%@", urlBase, stringData] asUnicodeInMemCtx: context];
context->name = [[realName substringFromIndex: 6] asUnicodeInMemCtx: context];
context->main_folder = false;
context->role = MAPISTORE_MAIL_ROLE;
context->tag = "tag";
@@ -188,7 +206,10 @@ MakeDisplayFolderName (NSString *folderName)
inContainer: accountFolder];
if ([newFolder create])
mapistoreURI = [NSString stringWithFormat: @"sogo://%@:%@@mail/%@/",
userName, userName,
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
[[folderName stringByEncodingImap4FolderName] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
else
mapistoreURI = nil;
@@ -264,8 +285,12 @@ MakeDisplayFolderName (NSString *folderName)
componentsSeparatedByString: @"/"];
folderName = [NSString stringWithFormat: @"folder%@",
[unprefixedFolders componentsJoinedByString: @"/folder"]];
url = [NSString stringWithFormat: @"sogo://%@:%@@outbox/%@", userName,
userName, folderName];
url = [NSString stringWithFormat: @"sogo://%@:%@@outbox/%@",
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
folderName];
context = talloc_zero (memCtx, struct mapistore_contexts_list);
context->url = [url asUnicodeInMemCtx: context];
+8
View File
@@ -44,6 +44,9 @@
/* synchronisation & versioning */
- (BOOL) synchroniseCache;
- (void) synchronizeUpdatedFolder: (NSNumber *) lastModseq
withMapping: (NSMutableDictionary *) mapping;
- (BOOL) synchroniseCacheForUID: (NSString *) messageUID;
- (NSNumber *) modseqFromMessageChangeNumber: (NSString *) changeNum;
- (NSString *) messageUIDFromMessageKey: (NSString *) messageKey;
- (NSString *) changeNumberForMessageUID: (NSString *) messageUid;
@@ -52,6 +55,11 @@
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey;
- (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey;
/* Extra properties from mail messages that already hit the server */
- (void) setExtraProperties: (NSDictionary *) props
forMessage: (NSString *) messageKey;
- (NSDictionary *) extraPropertiesForMessage: (NSString *) messageKey;
@end
/* MAPIStoreOutboxFolder is a special subclass of MAPIStoreMailFolder where
+371 -41
View File
@@ -52,6 +52,7 @@
#import "MAPIStoreFAIMessage.h"
#import "MAPIStoreMailContext.h"
#import "MAPIStoreMailMessage.h"
#import "MAPIStoreMailFolderTable.h"
#import "MAPIStoreMailMessageTable.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreTypes.h"
@@ -70,6 +71,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
#undef DEBUG
#include <util/attr.h>
#include <libmapi/libmapi.h>
#include <libmapiproxy.h>
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
@@ -153,6 +155,11 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
return [MAPIStoreMailMessageTable tableForContainer: self];
}
- (MAPIStoreFolderTable *) folderTable
{
return [MAPIStoreMailFolderTable tableForContainer: self];
}
- (enum mapistore_error) createFolder: (struct SRow *) aRow
withFID: (uint64_t) newFID
andKey: (NSString **) newKeyP
@@ -163,6 +170,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
int i;
nameInContainer = nil;
rc = MAPISTORE_ERROR;
folderName = nil;
for (i = 0; !folderName && i < aRow->cValues; i++)
@@ -177,6 +185,12 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
{
nameInContainer = [NSString stringWithFormat: @"folder%@",
[[folderName stringByEncodingImap4FolderName] asCSSIdentifier]];
/* it may be the operation is interleaved with operations
from other users having cached information in the thread
with the other user, so it'd better activate the user again here... */
[[self userContext] activateWithUser: [[[self userContext] woContext] activeUser]];
newFolder = [SOGoMailFolderK objectWithName: nameInContainer
inContainer: sogoObject];
if ([newFolder create])
@@ -351,19 +365,54 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
- (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings
{
NSArray *filteredSubfolderKeys;
NSMutableArray *subfolderKeys;
NSMutableArray *subfolderKeysQualifying;
NSString *subfolderKey;
NSUInteger count, max;
if ([self ensureFolderExists])
{
/* Only folder name can be used as qualifier key */
if (qualifier)
[self errorWithFormat: @"qualifier is not used for folders"];
[self warnWithFormat: @"qualifier is only used for folders with name"];
if (sortOrderings)
[self errorWithFormat: @"sort orderings are not used for folders"];
/* FIXME: Flush any cache before retrieving the hierarchy, this
slows things down but it is safer */
if (!qualifier)
[sogoObject flushMailCaches];
subfolderKeys = [[sogoObject toManyRelationshipKeys] mutableCopy];
[subfolderKeys autorelease];
[self _cleanupSubfolderKeys: subfolderKeys];
if (qualifier)
{
subfolderKeysQualifying = [NSMutableArray array];
max = [subfolderKeys count];
for (count = 0; count < max; count++) {
subfolderKey = [subfolderKeys objectAtIndex: count];
/* Remove "folder" prefix */
subfolderKey = [subfolderKey substringFromIndex: 6];
subfolderKey = [[subfolderKey fromCSSIdentifier] stringByDecodingImap4FolderName];
[subfolderKeysQualifying addObject: [NSDictionary dictionaryWithObject: subfolderKey
forKey: @"name"]];
}
filteredSubfolderKeys = [subfolderKeysQualifying filteredArrayUsingQualifier: qualifier];
max = [filteredSubfolderKeys count];
subfolderKeys = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{
subfolderKey = [[filteredSubfolderKeys objectAtIndex: count] valueForKey: @"name"];
subfolderKey = [NSString stringWithFormat: @"folder%@", [[subfolderKey stringByEncodingImap4FolderName] asCSSIdentifier]];
[subfolderKeys addObject: subfolderKey];
}
}
}
else
subfolderKeys = nil;
@@ -511,7 +560,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
*nextModseq;
NSString *changeNumber, *uid, *messageKey;
uint64_t lastModseqNbr;
EOQualifier *kvQualifier, *searchQualifier;
EOQualifier *searchQualifier;
NSArray *uids, *changeNumbers;
NSUInteger count, max;
NSArray *fetchResults;
@@ -552,14 +601,11 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
{
lastModseqNbr = [lastModseq unsignedLongLongValue];
nextModseq = [NSNumber numberWithUnsignedLongLong: lastModseqNbr + 1];
kvQualifier = [[EOKeyValueQualifier alloc]
searchQualifier = [[EOKeyValueQualifier alloc]
initWithKey: @"modseq"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: nextModseq];
searchQualifier = [[EOAndQualifier alloc]
initWithQualifiers:
kvQualifier, [self nonDeletedQualifier], nil];
[kvQualifier release];
[searchQualifier autorelease];
}
else
@@ -587,7 +633,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
fetchResults
= [(NSDictionary *) [sogoObject fetchUIDs: uids
parts: [NSArray arrayWithObject: @"modseq"]]
parts: [NSArray arrayWithObjects: @"modseq", @"flags", nil]]
objectForKey: @"fetch"];
/* NOTE: we sort items manually because Cyrus does not properly sort
@@ -623,58 +669,230 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
if (!lastModseq
|| ([lastModseq compare: modseq] == NSOrderedAscending))
lastModseq = modseq;
if ([[result objectForKey: @"flags"] containsObject: @"deleted"])
[currentProperties setObject: changeNumber
forKey: @"SyncLastDeleteChangeNumber"];
}
[currentProperties setObject: lastModseq forKey: @"SyncLastModseq"];
foundChange = YES;
}
/* 2. we synchronise deleted UIDs */
/* 2. we synchronise expunged UIDs */
if (initialLastModseq)
{
fetchResults = [(SOGoMailFolder *) sogoObject
fetchUIDsOfVanishedItems: lastModseqNbr];
max = [fetchResults count];
changeNumbers = [[self context] getNewChangeNumbers: max];
changeNumber = nil;
for (count = 0; count < max; count++)
{
uid = [fetchResults objectAtIndex: count];
uid = [[fetchResults objectAtIndex: count] stringValue];
if ([messages objectForKey: uid])
{
newChangeNum = [[changeNumbers objectAtIndex: count]
unsignedLongLongValue];
changeNumber = [NSString stringWithUnsignedLongLong: newChangeNum];
if (!changeNumber)
{
newChangeNum = [[self context] getNewChangeNumber];
changeNumber = [NSString stringWithUnsignedLongLong: newChangeNum];
}
[messages removeObjectForKey: uid];
[self logWithFormat: @"removed message entry for uid %@", uid];
[self logWithFormat: @"Removed message entry for UID %@", uid];
}
else
{
[self logWithFormat:@"Message entry not found for UID %@", uid];
}
}
if (changeNumber)
{
[currentProperties setObject: changeNumber
forKey: @"SyncLastDeleteChangeNumber"];
[mapping setObject: lastModseq forKey: changeNumber];
foundChange = YES;
}
}
if (foundChange)
{
[self synchronizeUpdatedFolder: lastModseq
withMapping: mapping];
ti = [NSNumber numberWithDouble: [now timeIntervalSince1970]];
[currentProperties setObject: ti
forKey: @"SyncLastSynchronisationDate"];
[versionsMessage save];
}
return rc;
}
- (void) synchronizeUpdatedFolder: (NSNumber *) lastModseq
withMapping: (NSMutableDictionary *) mapping
{
/* This method should be called whenever something has changed on the folder.
Then we will perform two actions:
1 - Update the PidTagChangeNumber property of the root container.
2 - Store relationship PidTagChangenumber with lastModseq value on the
mapping given as parameter for this folder */
uint64_t *current_cn;
struct SRow row;
struct SPropValue prop;
uint64_t fid;
const char *username;
struct openchangedb_context *oc_ctx;
enum MAPISTATUS retval;
TALLOC_CTX *local_mem_ctx = NULL;
row.cValues = 1;
prop.ulPropTag = PidTagChangeNumber;
prop.value.d = 0; // It doesn't matter, it will be autogenerated
row.lpProps = &prop;
/* We are doing a "touch" operation to update change number of the root container.
We get the root container as it has the properties in the OpenChange DB */
username = [[self context] connectionInfo]->username;
oc_ctx = [[self context] connectionInfo]->oc_ctx;
fid = [[self rootContainer] objectId];
retval = openchangedb_set_folder_properties(oc_ctx, username, fid, &row);
if (retval != MAPI_E_SUCCESS)
{
[self errorWithFormat:@"%s: Error setting change number on %"PRIu64,
__PRETTY_FUNCTION__, fid];
return;
}
local_mem_ctx = talloc_named(NULL, 0, __PRETTY_FUNCTION__);
if (local_mem_ctx == NULL)
{
[self errorWithFormat:@"%s: Error with talloc_named, out of memory?",
__PRETTY_FUNCTION__];
return;
}
retval = openchangedb_get_folder_property(local_mem_ctx, oc_ctx, username,
PidTagChangeNumber, fid,
(void **) &current_cn);
if (retval != MAPI_E_SUCCESS)
{
[self errorWithFormat:@"%s: Error getting change number on %"PRIu64,
__PRETTY_FUNCTION__, fid];
talloc_free(local_mem_ctx);
return;
}
[mapping setObject: lastModseq
forKey: [NSString stringWithUnsignedLongLong: *current_cn]];
talloc_free(local_mem_ctx);
}
- (BOOL) synchroniseCacheForUID: (NSString *) messageUID
{
/* Try to synchronise old UIDs in versions.plist cache using an
specific UID. It returns a boolean indicating if the
synchronisation were done.
It should be used as last resort, keeping synchroniseCache to main
sync entry point.
*/
NSMutableDictionary *currentProperties, *messages, *messageEntry, *mapping;
NSArray *fetchResults;
uint64_t changeNumber;
NSDictionary *result;
NSNumber *modseq;
NSString *changeNumberStr;
NSData *changeKey;
[versionsMessage reloadIfNeeded];
currentProperties = [versionsMessage properties];
messages = [currentProperties objectForKey: @"Messages"];
messageEntry = [messages objectForKey: messageUID];
if (!messageEntry)
{
fetchResults = [(NSDictionary *) [sogoObject fetchUIDs: [NSArray arrayWithObject: messageUID]
parts: [NSArray arrayWithObjects: @"modseq", @"flags", nil]]
objectForKey: @"fetch"];
if ([fetchResults count] == 1)
{
result = [fetchResults objectAtIndex: 0];
modseq = [result objectForKey: @"modseq"];
changeNumber = [[self context] getNewChangeNumber];
changeNumberStr = [NSString stringWithUnsignedLongLong: changeNumber];
/* Create new message entry in Messages dict */
messageEntry = [NSMutableDictionary new];
[messages setObject: messageEntry forKey: messageUID];
[messageEntry release];
/* Store the modseq and change number */
[messageEntry setObject: modseq forKey: @"modseq"];
[messageEntry setObject: changeNumberStr forKey: @"version"];
/* Store the change key */
changeKey = [self getReplicaKeyFromGlobCnt: changeNumber >> 16];
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
/* Store the changeNumber -> modseq mapping */
mapping = [currentProperties objectForKey: @"VersionMapping"];
[mapping setObject: modseq forKey: changeNumberStr];
/* Store the last deleted change number if it is soft-deleted */
if ([[result objectForKey: @"flags"] containsObject: @"deleted"])
[currentProperties setObject: changeNumberStr
forKey: @"SyncLastDeleteChangeNumber"];
/* Save the message */
[versionsMessage save];
return YES;
}
else
{
return NO;
}
}
/* If message entry exists, then synchroniseCache did its job */
return YES;
}
- (NSNumber *) modseqFromMessageChangeNumber: (NSString *) changeNum
{
NSDictionary *mapping;
NSNumber *modseq;
NSEnumerator *enumerator;
id key;
uint64_t found, target, current, replica_id, current_cn;
NSString *closestChangeNum;
mapping = [[versionsMessage properties] objectForKey: @"VersionMapping"];
modseq = [mapping objectForKey: changeNum];
if (modseq) return modseq;
// Not found from stored change numbers for this folder.
// Get the closest modseq for the change number given.
// O(n) cost but will be unusual behaviour.
target = exchange_globcnt([changeNum unsignedLongLongValue] >> 16);
replica_id = [changeNum unsignedLongLongValue] & 0xFFFF;
found = 0;
enumerator = [mapping keyEnumerator];
while ((key = [enumerator nextObject]))
{
current_cn = [(NSString *)key unsignedLongLongValue];
if ((current_cn & 0xFFFF) != replica_id)
continue;
current = exchange_globcnt(current_cn >> 16);
if (current < target && current > found)
found = current;
}
if (found)
{
closestChangeNum = [NSString stringWithUnsignedLongLong:
(exchange_globcnt(found) << 16 | replica_id)];
modseq = [mapping objectForKey: closestChangeNum];
}
return modseq;
}
@@ -688,7 +906,11 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
if (dotRange.location != NSNotFound)
messageUid = [messageKey substringToIndex: dotRange.location];
else
messageUid = nil;
{
messageUid = nil;
[self errorWithFormat:@"%s: Unexpected messageKey value [%@]",
__PRETTY_FUNCTION__, messageKey];
}
return messageUid;
}
@@ -710,12 +932,24 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
{
NSMutableDictionary *messages, *messageEntry;
NSString *messageUid;
BOOL synced;
messageUid = [self messageUIDFromMessageKey: messageKey];
messages = [[versionsMessage properties] objectForKey: @"Messages"];
messageEntry = [messages objectForKey: messageUid];
if (!messageEntry)
abort ();
{
[self warnWithFormat: @"attempting to synchronise to set the change key for "
@"this message %@", messageKey];
synced = [self synchroniseCacheForUID: messageUid];
if (synced)
messageEntry = [[[versionsMessage properties] objectForKey: @"Messages"] objectForKey: messageUid];
if (!messageEntry)
{
[self errorWithFormat: @"still nothing. We crash!"];
abort ();
}
}
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
[versionsMessage save];
@@ -784,6 +1018,37 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
return list;
}
/* Management for extra properties once they already hit the IMAP server */
- (void) setExtraProperties: (NSDictionary *) props
forMessage: (NSString *) messageKey
{
NSMutableDictionary *extraProps, *currentProperties;
NSString *messageUid;
messageUid = [self messageUIDFromMessageKey: messageKey];
currentProperties = [versionsMessage properties];
extraProps = [currentProperties objectForKey: @"ExtraMessagesProperties"];
if (!extraProps)
{
extraProps = [NSMutableDictionary new];
[currentProperties setObject: extraProps forKey: @"ExtraMessagesProperties"];
[extraProps release];
}
[extraProps setObject: props
forKey: messageUid];
[versionsMessage save];
}
- (NSDictionary *) extraPropertiesForMessage: (NSString *) messageKey
{
NSString *messageUid;
messageUid = [self messageUIDFromMessageKey: messageKey];
return [[[versionsMessage properties] objectForKey: @"ExtraMessagesProperties"]
objectForKey: messageUid];
}
- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum
andCN: (NSNumber **) cnNbr
inTableType: (uint8_t) tableType
@@ -792,6 +1057,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
NSString *changeNumber;
uint64_t modseq;
NSDictionary *versionProperties;
EOQualifier *deletedQualifier, *kvQualifier, *searchQualifier;
if (tableType == MAPISTORE_MESSAGE_TABLE)
{
@@ -800,8 +1066,33 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
unsignedLongLongValue];
if (modseq > 0)
{
/* Hard deleted items */
deletedUIDs = [(SOGoMailFolder *) sogoObject
fetchUIDsOfVanishedItems: modseq];
/* Soft deleted items */
kvQualifier = [[EOKeyValueQualifier alloc]
initWithKey: @"modseq"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: [NSNumber numberWithUnsignedLongLong: modseq]];
deletedQualifier
= [[EOKeyValueQualifier alloc]
initWithKey: @"FLAGS"
operatorSelector: EOQualifierOperatorContains
value: [NSArray arrayWithObject: @"Deleted"]];
searchQualifier = [[EOAndQualifier alloc]
initWithQualifiers:
kvQualifier, deletedQualifier, nil];
deletedUIDs = [deletedUIDs arrayByAddingObjectsFromArray:
[sogoObject fetchUIDsMatchingQualifier: searchQualifier
sortOrdering: nil]];
[deletedQualifier release];
[kvQualifier release];
[searchQualifier release];
deletedKeys = [deletedUIDs stringsWithFormat: @"%@.eml"];
if ([deletedUIDs count] > 0)
{
@@ -857,6 +1148,8 @@ _parseIMAPRange (const unichar *uniString, NSArray **UIDsP)
uint32_t currentUid, rangeMin;
BOOL done = NO, inRange = NO;
rangeMin = 0;
currentUid = 0;
UIDs = [NSMutableArray array];
while (!done)
{
@@ -981,13 +1274,20 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
if (![[result objectForKey: @"result"] boolValue])
return MAPISTORE_ERROR;
/* "Move" treatment: Store \Deleted and unregister urls */
/* "Move" treatment: Store \Deleted and unregister urls as soft-deleted */
if (!wantCopy)
{
[client storeFlags: [NSArray arrayWithObject: @"Deleted"] forUIDs: uids
addOrRemove: YES];
for (count = 0; count < midCount; count++)
[mapping unregisterURLWithID: srcMids[count]];
{
/* Using soft-deleted to make deleted fmids to return the
srcMids.
See [MAPIStoreFolder getDeletedFMIDs:andCN:fromChangeNumber:inTableType:inMemCtx]
for details */
[mapping unregisterURLWithID: srcMids[count]
andFlags: MAPISTORE_SOFT_DELETE];
}
}
/* Registration of target messages */
@@ -1036,13 +1336,6 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
}
}
[self postNotificationsForMoveCopyMessagesWithMIDs: srcMids
andMessageURLs: oldMessageURLs
andCount: midCount
fromFolder: sourceFolder
withMIDs: targetMids
wantCopy: wantCopy];
// We cleanup cache of our source and destination folders
[self cleanupCaches];
[sourceFolder cleanupCaches];
@@ -1061,6 +1354,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
struct SRow folderRow;
struct SPropValue nameProperty;
MAPIStoreMailFolder *newFolder;
SOGoMailAccount *accountFolder;
SOGoMailFolder *targetSOGoFolder;
NSMutableArray *uids;
NSArray *childKeys;
@@ -1068,12 +1362,12 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
NGImap4Connection *connection;
NGImap4Client *client;
NSString *newURL, *parentDBFolderPath, *childKey, *folderIMAPName,
*urlNamePart, *newFolderIMAPName;
*urlNamePart, *newFolderIMAPName, *newFolderDBName;
NSException *error;
MAPIStoreMapping *mapping;
NSDictionary *result;
if ([targetFolder isKindOfClass: MAPIStoreMailFolderK])
if ([targetFolder isKindOfClass: MAPIStoreMailFolderK] || (!targetFolder && isMove))
{
folderURL = [sogoObject imap4URL];
if (!newFolderName)
@@ -1081,9 +1375,23 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
targetSOGoFolder = [targetFolder sogoObject];
if (isMove)
{
urlNamePart = [newFolderName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
newFolderURL = [NSURL URLWithString: urlNamePart
relativeToURL: [targetSOGoFolder imap4URL]];
newFolderDBName = [[newFolderName stringByEncodingImap4FolderName] asCSSIdentifier];
if (targetSOGoFolder)
{
/* Mimetise [SOGoMailFolderK imap4URLString] */
urlNamePart = [[newFolderName stringByEncodingImap4FolderName] stringByEscapingURL];
newFolderURL = [NSURL URLWithString: urlNamePart
relativeToURL: [targetSOGoFolder imap4URL]];
}
else
{
/* Mimetise what createRootSecondaryFolderWithFID does */
accountFolder = [[[self userContext] rootFolders] objectForKey: @"mail"];
targetSOGoFolder = [SOGoMailFolder objectWithName: [NSString stringWithFormat: @"folder%@",
newFolderDBName]
inContainer: accountFolder];
newFolderURL = [targetSOGoFolder imap4URL];
}
error = [[sogoObject imap4Connection]
moveMailboxAtURL: folderURL
toURL: newFolderURL];
@@ -1093,16 +1401,29 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
{
rc = MAPISTORE_SUCCESS;
mapping = [self mapping];
newURL = [NSString stringWithFormat: @"%@folder%@/",
[targetFolder url], urlNamePart];
if (targetFolder)
newURL = [NSString stringWithFormat: @"%@folder%@/",
[targetFolder url], newFolderDBName];
else
newURL = [NSString stringWithFormat: @"sogo://%@:%@@mail/folder%@/",
[[self userContext] username], [[self userContext] username],
newFolderDBName];
[mapping updateID: [self objectId] withURL: newURL];
parentDBFolderPath = [[targetFolder dbFolder] path];
if (!parentDBFolderPath)
parentDBFolderPath = @"";
[dbFolder changePathTo: [NSString stringWithFormat:
@"%@/folder%@",
parentDBFolderPath,
newFolderName]];
if (targetFolder)
{
parentDBFolderPath = [[targetFolder dbFolder] path];
if (!parentDBFolderPath)
parentDBFolderPath = @"";
[dbFolder changePathTo: [NSString stringWithFormat:
@"%@/folder%@",
parentDBFolderPath,
newFolderDBName]
intoNewContainer: [targetFolder dbFolder]];
}
else
[dbFolder changePathTo: [NSString stringWithFormat:
@"/mail/folder%@", newFolderDBName]
intoNewContainer: nil];
}
}
else
@@ -1290,6 +1611,15 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
{
[bodyPartKeys addObject: bodyPartKey];
messageUid = [self messageUIDFromMessageKey: messageKey];
/* If the bodyPartKey include peek, remove it as it is not returned
as key in the IMAP server response.
IMAP conversation example:
a4 UID FETCH 1 (UID BODY.PEEK[text])
* 1 FETCH (UID 1 BODY[TEXT] {1677}
*/
bodyPartKey = [bodyPartKey stringByReplacingOccurrencesOfString: @"body.peek"
withString: @"body"];
[keyAssoc setObject: bodyPartKey forKey: messageUid];
}
}
+31
View File
@@ -0,0 +1,31 @@
/* MAPIStoreMailFolderTable.h - this file is part of SOGo
*
* Copyright (C) 2015 Enrique J. Hernández
*
* Author: Enrique J. Hernández <ejhernandez@zentyal.com>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef MAPISTOREMAILFOLDERTABLE_H
#define MAPISTOREMAILFOLDERTABLE_H
#import "MAPIStoreFolderTable.h"
@interface MAPIStoreMailFolderTable : MAPIStoreFolderTable
@end
#endif /* MAPISTOREMAILFOLDERTABLE_H */
+42
View File
@@ -0,0 +1,42 @@
/* MAPIStoreMailFolderTable.m - this file is part of SOGo
*
* Copyright (C) 2015 Enrique J. Hernández
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSString.h>
#import "MAPIStoreMailFolderTable.h"
#import "MAPIStoreTypes.h"
@implementation MAPIStoreMailFolderTable
- (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property
{
switch(property)
{
case PR_DISPLAY_NAME:
case PR_DISPLAY_NAME_UNICODE:
return @"name";
default:
return nil;
}
}
@end
+2
View File
@@ -35,6 +35,8 @@
{
BOOL headerSetup;
BOOL mailIsEvent;
BOOL mailIsMeetingRequest;
BOOL mailIsSharingObject;
NSString *mimeKey;
NSString *headerCharset;
NSString *headerEncoding;
+150 -37
View File
@@ -32,6 +32,7 @@
#import <NGImap4/NGImap4EnvelopeAddress.h>
#import <NGMail/NGMailAddress.h>
#import <NGMail/NGMailAddressParser.h>
#import <NGMail/NGMimeMessageGenerator.h>
#import <NGCards/iCalCalendar.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSString+Utilities.h>
@@ -40,6 +41,7 @@
#import <Mailer/SOGoMailBodyPart.h>
#import <Mailer/SOGoMailObject.h>
#import "Codepages.h"
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
@@ -50,6 +52,7 @@
#import "MAPIStoreMailFolder.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreSamDBUtils.h"
#import "MAPIStoreSharingMessage.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
@@ -63,7 +66,7 @@
@class iCalCalendar, iCalEvent;
static Class NSExceptionK;
static Class NSExceptionK, MAPIStoreSharingMessageK;
@interface NSString (MAPIStoreMIME)
@@ -106,6 +109,7 @@ static Class NSExceptionK;
+ (void) initialize
{
NSExceptionK = [NSException class];
MAPIStoreSharingMessageK = [MAPIStoreSharingMessage class];
}
- (id) init
@@ -114,6 +118,8 @@ static Class NSExceptionK;
{
mimeKey = nil;
mailIsEvent = NO;
mailIsMeetingRequest = NO;
mailIsSharingObject = NO;
headerCharset = nil;
headerEncoding = nil;
headerMimeType = nil;
@@ -132,6 +138,7 @@ static Class NSExceptionK;
[bodyContent release];
[headerMimeType release];
[headerCharset release];
[headerEncoding release];
[appointmentWrapper release];
[super dealloc];
}
@@ -151,6 +158,30 @@ static Class NSExceptionK;
return [sogoObject date];
}
- (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP
inMemCtx: (TALLOC_CTX *) memCtx
{
BOOL listedProperties[65536];
NSUInteger count;
uint16_t propId;
if (mailIsSharingObject)
{
memset (listedProperties, NO, 65536 * sizeof (BOOL));
[super getAvailableProperties: propertiesP inMemCtx: memCtx];
for (count = 0; count < (*propertiesP)->cValues; count++)
{
propId = ((*propertiesP)->aulPropTag[count] >> 16) & 0xffff;
listedProperties[propId] = YES;
}
[MAPIStoreSharingMessage fillAvailableProperties: *propertiesP
withExclusions: listedProperties];
return MAPISTORE_SUCCESS;
}
else
return [super getAvailableProperties: propertiesP inMemCtx: memCtx];
}
static NSComparisonResult
_compareBodyKeysByPriority (id entry1, id entry2, void *data)
{
@@ -200,9 +231,11 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
- (void) _fetchHeaderData
{
MAPIStoreSharingMessage *sharingMessage;
NSMutableArray *keys;
NSArray *acceptedTypes;
NSDictionary *messageData, *partHeaderData, *parameters;
NSString *sharingHeader;
acceptedTypes = [NSArray arrayWithObjects: @"text/calendar",
@"application/ics",
@@ -226,7 +259,27 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
ASSIGN (headerCharset, [parameters objectForKey: @"charset"]);
if ([headerMimeType isEqualToString: @"text/calendar"]
|| [headerMimeType isEqualToString: @"application/ics"])
{
mailIsEvent = YES;
if ([[parameters objectForKey: @"method"] isEqualToString: @"REQUEST"])
mailIsMeetingRequest = YES;
}
else
{
sharingHeader = [[sogoObject mailHeaders] objectForKey: @"x-ms-sharing-localtype"];
if (sharingHeader)
{
mailIsSharingObject = YES;
/* It is difficult to subclass this in folder class, that's why
a sharing object is a proxy in a mail message */
sharingMessage = [[MAPIStoreSharingMessage alloc]
initWithMailHeaders: [sogoObject mailHeaders]
andConnectionInfo: [[self context] connectionInfo]
fromMessage: self];
[self addProxy: sharingMessage];
[sharingMessage release];
}
}
}
headerSetup = YES;
@@ -368,6 +421,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
{
uint64_t version = ULLONG_MAX;
NSString *uid, *changeNumber;
BOOL synced;
uid = [(MAPIStoreMailFolder *)
container messageUIDFromMessageKey: [self nameInContainer]];
@@ -386,8 +440,19 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
[self logWithFormat: @"got one"];
else
{
[self errorWithFormat: @"still nothing. We crash!"];
abort();
[self warnWithFormat: @"attempting to get change number"
@" by synchronising this specific message..."];
synced = [(MAPIStoreMailFolder *) container synchroniseCacheForUID: uid];
if (synced)
{
changeNumber = [(MAPIStoreMailFolder *) container
changeNumberForMessageUID: uid];
}
else
{
[self errorWithFormat: @"still nothing. We crash!"];
abort();
}
}
}
version = [changeNumber unsignedLongLongValue] >> 16;
@@ -504,36 +569,31 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if (mailIsEvent)
[[self _appointmentWrapper] getPidTagMessageClass: data
inMemCtx: memCtx];
else if (mailIsSharingObject)
*data = talloc_strdup (memCtx, "IPM.Sharing");
else
*data = talloc_strdup (memCtx, "IPM.Note");
return MAPISTORE_SUCCESS;
}
/* Note: this applies to regular mails... */
// - (int) getPidTagReplyRequested: (void **) data // TODO
// inMemCtx: (TALLOC_CTX *) memCtx
// {
// if (!headerSetup)
// [self _fetchHeaderData];
// return (mailIsEvent
// ? [self getYes: data inMemCtx: memCtx]
// : [self getNo: data inMemCtx: memCtx]);
// }
/* ... while this applies to invitations. */
- (int) getPidTagResponseRequested: (void **) data // TODO
inMemCtx: (TALLOC_CTX *) memCtx
- (int) getPidTagReplyRequested: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
if (!headerSetup)
[self _fetchHeaderData];
return (mailIsEvent
? [self getNo: data inMemCtx: memCtx]
return (mailIsMeetingRequest
? [self getYes: data inMemCtx: memCtx]
: MAPISTORE_ERR_NOT_FOUND);
}
- (int) getPidTagResponseRequested: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidTagReplyRequested: data inMemCtx: memCtx];
}
- (int) getPidTagLatestDeliveryTime: (void **) data // DOUBT
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -741,7 +801,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
contactInfos = [mgr contactInfosForUserWithUIDorEmail: email];
if (contactInfos)
{
username = [contactInfos objectForKey: @"c_uid"];
username = [contactInfos objectForKey: @"sAMAccountName"];
samCtx = [[self context] connectionInfo]->sam_ctx;
entryId = MAPIStoreInternalEntryId (samCtx, username);
}
@@ -923,15 +983,17 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
- (int) getPidTagInternetCodepage: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
/* ref:
http://msdn.microsoft.com/en-us/library/dd317756%28v=vs.85%29.aspx
minimal list that should be handled:
us-ascii: 20127
iso-8859-1: 28591
iso-8859-15: 28605
utf-8: 65001 */
*data = MAPILongValue(memCtx, 65001);
NSNumber *codepage;
codepage = [Codepages getCodepageFromName: headerCharset];
if (!codepage)
{
[self warnWithFormat: @"Couldn't find codepage from `%@`. "
@"Using UTF-8 by default", headerCharset];
codepage = [Codepages getCodepageFromName: @"utf-8"];
}
*data = MAPILongValue(memCtx, [codepage intValue]);
return MAPISTORE_SUCCESS;
}
@@ -1333,6 +1395,41 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
: MAPISTORE_ERR_NOT_FOUND);
}
- (int) getPidTagTransportMessageHeaders: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
NSDictionary *mailHeaders;
NSEnumerator *keyEnumerator;
NSMutableArray *headers;
NGMimeMessageGenerator *g;
NSString *headerKey, *fullHeader, *headerGenerated;
id headerValue;
NSData *headerData;
/* Let's encode each mail header and put them on 'headers' array */
mailHeaders = [sogoObject mailHeaders];
headers = [NSMutableArray arrayWithCapacity: [mailHeaders count]];
g = [[NGMimeMessageGenerator alloc] init];
keyEnumerator = [mailHeaders keyEnumerator];
while ((headerKey = [keyEnumerator nextObject]))
{
headerValue = [mailHeaders objectForKey: headerKey];
headerData = [g generateDataForHeaderField: headerKey value: headerValue];
headerGenerated = [[NSString alloc] initWithData: headerData encoding:NSUTF8StringEncoding];
fullHeader = [NSString stringWithFormat:@"%@: %@", headerKey, headerGenerated];
[headerGenerated release];
[headers addObject: fullHeader];
}
[g release];
*data = [[headers componentsJoinedByString:@"\n"] asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (void) getMessageData: (struct mapistore_message **) dataPtr
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -1402,10 +1499,10 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if ([cn length] == 0)
cn = email;
contactInfos = [mgr contactInfosForUserWithUIDorEmail: email];
if (contactInfos)
{
username = [contactInfos objectForKey: @"c_uid"];
username = [contactInfos objectForKey: @"sAMAccountName"];
recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (samCtx, username);
}
@@ -1566,11 +1663,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if (!headerSetup)
[self _fetchHeaderData];
if ([mimeKey hasPrefix: @"body.peek"])
bodyPartKey = [NSString stringWithFormat: @"body[%@]",
[mimeKey _strippedBodyKey]];
else
bodyPartKey = mimeKey;
bodyPartKey = mimeKey;
return bodyPartKey;
}
@@ -1584,6 +1677,21 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
bodySetup = YES;
}
- (MAPIStoreSharingMessage *) _sharingObject
{
/* Get the sharing object if available */
NSUInteger i, max;
id proxy;
max = [proxies count];
for (i = 0; i < max; i++) {
proxy = [proxies objectAtIndex: i];
if ([proxy isKindOfClass: MAPIStoreSharingMessageK])
return proxy;
}
return nil;
}
- (void) save: (TALLOC_CTX *) memCtx
{
NSNumber *value;
@@ -1597,6 +1705,11 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
else /* 0: unflagged, 1: follow up complete */
[sogoObject removeFlags: @"\\Flagged"];
}
if (mailIsSharingObject)
[[self _sharingObject] saveWithMessage: self
andSOGoObject: sogoObject];
}
@end
+208 -27
View File
@@ -28,9 +28,10 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSScanner.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <Foundation/NSValue.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NGHashMap.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+Encoding.h>
@@ -43,6 +44,7 @@
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSCalendarDate+SOGo.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoCacheObject.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoMailer.h>
#import <SOGo/SOGoUser.h>
@@ -50,6 +52,7 @@
#import <Mailer/SOGoMailFolder.h>
#import <Mailer/NSString+Mail.h>
#import "Codepages.h"
#import "MAPIStoreAttachment.h"
#import "MAPIStoreAttachmentTable.h"
#import "MAPIStoreContext.h"
@@ -62,13 +65,13 @@
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import <SOGo/SOGoCacheObject.h>
#import "MAPIStoreMailVolatileMessage.h"
#undef DEBUG
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
#include <mapistore/mapistore_nameid.h>
static Class NSNumberK = Nil;
@@ -383,7 +386,7 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
contactInfos = [mgr contactInfosForUserWithUIDorEmail: email];
if (contactInfos)
{
username = [contactInfos objectForKey: @"c_uid"];
username = [contactInfos objectForKey: @"sAMAccountName"];
recipient->username = [username asUnicodeInMemCtx: msgData];
entryId = MAPIStoreInternalEntryId (samCtx, username);
}
@@ -531,13 +534,112 @@ QuoteSpecials (NSString *address)
return result;
}
static inline void
FillMessageHeadersFromSharingProperties (NGMutableHashMap *headers, NSDictionary *mailProperties)
{
/* Store the *important* properties related with a sharing object as
MIME eXtension headers. See [MS-OXSHARE] Section 2.2 for details
about the properties */
id value;
NSNumber *sharingFlavourNum = nil;
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingCapabilities)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-Capabilities"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingFlavor)];
if (value)
sharingFlavourNum = (NSNumber *)value;
else
{
value = [mailProperties objectForKey: MAPIPropertyKey (PidNameXSharingFlavor)];
if (value)
{
/* Transform the hex string to unsigned int */
NSScanner *scanner;
unsigned int sharingFlavour;
scanner = [NSScanner scannerWithString:value];
if ([scanner scanHexInt:&sharingFlavour])
sharingFlavourNum =[NSNumber numberWithUnsignedInt: sharingFlavour];
}
}
if (sharingFlavourNum)
{
if ([sharingFlavourNum unsignedIntegerValue] == 0x5100)
{
/* 0x5100 sharing flavour is not in standard but it seems to
be a denial of request + invitation message so we store
deny sharing flavour */
sharingFlavourNum = [NSNumber numberWithUnsignedInt: SHARING_DENY_REQUEST];
}
[headers setObject: sharingFlavourNum
forKey: @"X-MS-Sharing-Flavor"];
}
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorEntryId)];
if (value)
[headers setObject: [[value stringByEncodingBase64] stringByReplacingOccurrencesOfString: @"\n"
withString: @""]
forKey: @"X-MS-Sharing-InitiatorEntryId"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorName)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-InitiatorName"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorSmtp)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-InitiatorSmtp"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingLocalType)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-LocalType"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingProviderName)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-ProviderName"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingRemoteName)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-RemoteName"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingRemoteStoreUid)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-RemoteStoreUid"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingRemoteUid)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-RemoteUid"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingResponseTime)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-ResponseTime"];
value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingResponseType)];
if (value)
[headers setObject: value
forKey: @"X-MS-Sharing-ResponseType"];
}
static inline void
FillMessageHeadersFromProperties (NGMutableHashMap *headers,
NSDictionary *mailProperties, BOOL withBcc,
struct mapistore_connection_info *connInfo)
{
BOOL fromResolved = NO;
NSData *senderEntryId;
NSMutableString *subject;
NSString *from, *recId, *messageId, *subjectData;
NSString *from, *recId, *messageId, *subjectData, *recipientsStr, *msgClass;
NSArray *list;
NSCalendarDate *date;
NSDictionary *recipients;
@@ -571,10 +673,96 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
list = MakeRecipientsList ([recipients objectForKey: @"orig"]);
if ([list count])
[headers setObjects: list forKey: @"from"];
{
[headers setObjects: list forKey: @"from"];
fromResolved = YES;
}
}
if (!fromResolved)
{
NSLog (@"Message without an orig from, try to guess it from PidTagSenderEntryId");
senderEntryId = [mailProperties objectForKey: MAPIPropertyKey (PR_SENDER_ENTRYID)];
if (senderEntryId)
{
struct Binary_r bin32;
struct AddressBookEntryId *addrBookEntryId;
NSString *username;
NSMutableDictionary *fromRecipient;
fromRecipient = [NSMutableDictionary dictionaryWithCapacity: 2];
bin32.cb = [senderEntryId length];
bin32.lpb = (uint8_t *) [senderEntryId bytes];
addrBookEntryId = get_AddressBookEntryId (connInfo->sam_ctx, &bin32);
if (addrBookEntryId && [[NSString stringWithGUID: &addrBookEntryId->ProviderUID]
hasSuffix: @"08002b2fe182"])
{
/* TODO: better way to distinguish local and other ones */
username = MAPIStoreSamDBUserAttribute (connInfo->sam_ctx, @"legacyExchangeDN",
[NSString stringWithUTF8String: addrBookEntryId->X500DN], @"sAMAccountName");
if (username)
{
SOGoUser *fromUser;
fromUser = [SOGoUser userWithLogin: [username lowercaseString]];
[fromRecipient setObject: [fromUser cn] forKey: @"fullName"];
[fromRecipient setObject: [[fromUser allEmails] objectAtIndex: 0]
forKey: @"email"];
}
else
[fromRecipient setObject: [NSString stringWithUTF8String: addrBookEntryId->X500DN]
forKey: @"email"];
}
else
{
/* Try with One-Off EntryId */
struct OneOffEntryId *oneOffEntryId;
oneOffEntryId = get_OneOffEntryId (connInfo->sam_ctx, &bin32);
if (oneOffEntryId && [[NSString stringWithGUID: &oneOffEntryId->ProviderUID]
hasSuffix: @"00dd010f5402"])
{
[fromRecipient setObject: [NSString stringWithUTF8String: oneOffEntryId->DisplayName.lpszW]
forKey: @"fullName"];
[fromRecipient setObject: [NSString stringWithUTF8String: oneOffEntryId->EmailAddress.lpszW]
forKey: @"email"];
}
talloc_free (oneOffEntryId);
}
talloc_free (addrBookEntryId);
if ([[fromRecipient allKeys] count] > 0)
{
list = MakeRecipientsList ([NSArray arrayWithObjects: fromRecipient, nil]);
if ([list count])
[headers setObjects: list forKey: @"from"];
}
}
}
if (!recipients)
{
NSLog (@"Message without recipients."
@"Guessing recipients from PidTagOriginalDisplayTo and PidTagOriginalCc");
recipientsStr = [mailProperties objectForKey: MAPIPropertyKey (PidTagOriginalDisplayTo)];
if (recipientsStr)
{
list = [recipientsStr componentsSeparatedByString:@", "];
if ([list count])
[headers setObjects: list forKey: @"to"];
}
recipientsStr = [mailProperties objectForKey: MAPIPropertyKey (PidTagOriginalDisplayCc)];
if (recipientsStr)
{
list = [recipientsStr componentsSeparatedByString:@", "];
if ([list count])
[headers setObjects: list forKey: @"cc"];
}
}
else
NSLog (@"message without recipients");
subject = [NSMutableString stringWithCapacity: 128];
subjectData = [mailProperties objectForKey: MAPIPropertyKey (PR_SUBJECT_PREFIX_UNICODE)];
@@ -592,8 +780,6 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
date = [mailProperties objectForKey: MAPIPropertyKey (PR_CLIENT_SUBMIT_TIME)];
if (date)
{
date = [date addYear: 0 month: 0 day: 0
hour: 0 minute: 0 second: [[date timeZone] secondsFromGMT]];
[headers addObject: [date rfc822DateString] forKey: @"date"];
}
[headers addObject: @"1.0" forKey: @"MIME-Version"];
@@ -612,6 +798,13 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
{
[headers addObject: @"5 (Lowest)" forKey: @"X-Priority"];
}
msgClass = [mailProperties objectForKey: MAPIPropertyKey (PidTagMessageClass)];
if ([msgClass isEqualToString: @"IPM.Sharing"])
{
FillMessageHeadersFromSharingProperties (headers, mailProperties);
}
}
static NSArray *
@@ -672,21 +865,9 @@ MakeTextHtmlBody (NSDictionary *mailProperties, NSDictionary *attachmentParts,
{
/* charset */
codePage = [mailProperties objectForKey: MAPIPropertyKey (PR_INTERNET_CPID)];
switch ([codePage intValue])
{
case 20127:
charset = @"us-ascii";
break;
case 28605:
charset = @"iso-8859-15";
break;
case 65001:
charset = @"utf-8";
break;
case 28591:
default:
charset = @"iso-8859-1";
}
charset = [Codepages getNameFromCodepage: codePage];
if (!charset)
charset = @"utf-8";
htmlContentType = [NSString stringWithFormat: @"text/html; charset=%@",
charset];
@@ -834,7 +1015,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
messageBody = MakeMessageBody (properties, attachmentParts, &contentType);
if (messageBody)
{
[headers setObject: contentType forKey: @"content-type"];
[message setHeader: contentType forKey: @"content-type"];
[message setBody: messageBody];
}
@@ -873,12 +1054,12 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
id <SOGoAuthenticator> authenticator;
msgClass = [properties objectForKey: MAPIPropertyKey (PidTagMessageClass)];
if ([msgClass isEqualToString: @"IPM.Note"]) /* we skip invitation replies */
if ([msgClass isEqualToString: @"IPM.Note"] || [msgClass isEqualToString: @"IPM.Sharing"]) /* we skip invitation replies */
{
/* send mail */
messageData = [self _generateMailDataWithBcc: NO];
recipientEmails = [NSMutableArray arrayWithCapacity: 32];
recipients = [properties objectForKey: @"recipients"];
for (type = MAPI_ORIG; type <= MAPI_BCC; type++)
+6
View File
@@ -49,13 +49,19 @@
- (NSString *) urlFromID: (uint64_t) idKey;
- (uint64_t) idFromURL: (NSString *) url;
- (uint64_t) idFromURL: (NSString *) url
isSoftDeleted: (bool *) softDeleted;
- (BOOL) registerURL: (NSString *) urlString
withID: (uint64_t) idNbr;
- (void) registerURLs: (NSArray *) urlString
withIDs: (NSArray *) idNbrs;
- (void) unregisterURLWithID: (uint64_t) idNbr;
- (void) unregisterURLWithID: (uint64_t) idNbr
andFlags: (uint8_t) flags;
- (void) updateID: (uint64_t) idNbr
withURL: (NSString *) urlString;
- (BOOL) updateURL: (NSString *) urlString
withID: (uint64_t) idNbr;
@end
+57 -8
View File
@@ -114,6 +114,9 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
{
ASSIGN (username, newUsername);
indexing = newIndexing;
/* Workaround so all indexing context are valid and won't be freed. */
// TODO refactor indexing interface
talloc_reference(memCtx, indexing);
}
return self;
@@ -157,6 +160,21 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
return NSNotFound;
}
- (uint64_t) idFromURL: (NSString *) url
isSoftDeleted: (bool *) softDeleted
{
enum mapistore_error ret;
uint64_t idNbr;
ret = indexing->get_fmid(indexing, [username UTF8String], [url UTF8String],
false, &idNbr, softDeleted);
if (ret != MAPISTORE_SUCCESS)
return NSNotFound;
return idNbr;
}
- (void) _updateFolderWithURL: (NSString *) oldURL
withURL: (NSString *) urlString
{
@@ -209,12 +227,32 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
}
}
- (BOOL) updateURL: (NSString *) urlString
withID: (uint64_t) idNbr
{
BOOL rc = NO;
uint64_t oldIDNbr;
oldIDNbr = [self idFromURL: urlString];
if (oldIDNbr)
{
[self logWithFormat: @"Updating URL: %@ with id %.16"PRIx64" from old id %.16"PRIx64,
urlString, idNbr, oldIDNbr];
[self unregisterURLWithID: oldIDNbr];
[self registerURL: urlString
withID: idNbr];
rc = YES;
}
return rc;
}
- (BOOL) registerURL: (NSString *) urlString
withID: (uint64_t) idNbr
{
NSString *oldURL;
uint64_t oldIdNbr;
bool rc;
bool softDeleted;
oldURL = [self urlFromID: idNbr];
if (oldURL != NULL)
@@ -225,18 +263,20 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
return NO;
}
oldIdNbr = [self idFromURL: urlString];
oldIdNbr = [self idFromURL: urlString isSoftDeleted: &softDeleted];
if (oldIdNbr != NSNotFound)
{
[self errorWithFormat:
@"attempt to double register an entry with idNbr ('%@', %lld,"
@" 0x%.16"PRIx64", oldid=0x%.16"PRIx64")",
urlString, idNbr, idNbr, oldIdNbr];
if (softDeleted)
[self logWithFormat: @"Attempt to register a soft-deleted %@", urlString];
else
[self errorWithFormat:
@"attempt to double register an entry with idNbr ('%@', %lld,"
@" 0x%.16"PRIx64", oldid=0x%.16"PRIx64")",
urlString, idNbr, idNbr, oldIdNbr];
return NO;
}
else
{
rc = YES;
// [self logWithFormat: @"registered url '%@' with id %lld (0x%.16"PRIx64")",
// urlString, idNbr, idNbr];
@@ -245,7 +285,7 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
idNbr, [urlString UTF8String]);
}
return rc;
return YES;
}
- (void) registerURLs: (NSArray *) urlStrings
@@ -275,4 +315,13 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr)
idNbr, MAPISTORE_PERMANENT_DELETE);
}
- (void) unregisterURLWithID: (uint64_t) idNbr
andFlags: (uint8_t) flags
{
indexing->del_fmid(indexing, [username UTF8String],
idNbr,
(flags == MAPISTORE_SOFT_DELETE) ? MAPISTORE_SOFT_DELETE : MAPISTORE_PERMANENT_DELETE);
}
@end
+7 -47
View File
@@ -465,16 +465,15 @@ rtf2html (NSData *compressedRTF)
enum mapistore_error rc;
NSArray *containerTables;
NSUInteger count, max;
struct mapistore_object_notification_parameters *notif_parameters;
uint64_t folderId;
struct mapistore_context *mstoreCtx;
MAPIStoreContext *context;
SOGoUser *ownerUser;
BOOL userIsOwner;
MAPIStoreMessage *mainMessage;
//[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
containerTables = nil;
max = 0;
context = [self context];
ownerUser = [[self userContext] sogoUser];
userIsOwner = [[context activeUser] isEqual: ownerUser];
@@ -496,47 +495,6 @@ rtf2html (NSData *compressedRTF)
/* notifications */
if ([container isKindOfClass: MAPIStoreFolderK])
{
folderId = [(MAPIStoreFolder *) container objectId];
mstoreCtx = [[self context] connectionInfo]->mstore_ctx;
/* folder modified */
notif_parameters
= talloc_zero(memCtx, struct mapistore_object_notification_parameters);
notif_parameters->object_id = folderId;
if (isNew)
{
notif_parameters->tag_count = 3;
notif_parameters->tags = talloc_array (notif_parameters,
enum MAPITAGS, 3);
notif_parameters->tags[0] = PR_CONTENT_COUNT;
notif_parameters->tags[1] = PR_MESSAGE_SIZE;
notif_parameters->tags[2] = PR_NORMAL_MESSAGE_SIZE;
notif_parameters->new_message_count = true;
notif_parameters->message_count
= [[(MAPIStoreFolder *) container messageKeys] count] + 1;
}
mapistore_push_notification (mstoreCtx,
MAPISTORE_FOLDER,
MAPISTORE_OBJECT_MODIFIED,
notif_parameters);
talloc_free (notif_parameters);
/* message created */
if (isNew)
{
notif_parameters
= talloc_zero(memCtx,
struct mapistore_object_notification_parameters);
notif_parameters->object_id = [self objectId];
notif_parameters->folder_id = folderId;
notif_parameters->tag_count = 0xffff;
mapistore_push_notification (mstoreCtx,
MAPISTORE_MESSAGE, MAPISTORE_OBJECT_CREATED,
notif_parameters);
talloc_free (notif_parameters);
}
/* we ensure the table caches are loaded so that old and new state
can be compared */
containerTables = [self activeContainerMessageTables];
@@ -782,7 +740,7 @@ rtf2html (NSData *compressedRTF)
return [self getLongZero: data inMemCtx: memCtx];
}
- (int) getPidTagSensitivity: (void **) data // TODO -> subclass in calendar
- (int) getPidTagSensitivity: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getLongZero: data inMemCtx: memCtx];
@@ -795,7 +753,7 @@ rtf2html (NSData *compressedRTF)
TALLOC_CTX *localMemCtx;
char *prefix, *normalizedSubject;
localMemCtx = talloc_zero (NULL, TALLOC_CTX);
localMemCtx = talloc_zero (memCtx, TALLOC_CTX);
if ([self getProperty: (void **) &prefix
withTag: PidTagSubjectPrefix
inMemCtx: localMemCtx]
@@ -807,6 +765,8 @@ rtf2html (NSData *compressedRTF)
if (rc == MAPISTORE_SUCCESS)
*data = talloc_asprintf (memCtx, "%s%s", prefix, normalizedSubject);
talloc_free(localMemCtx);
return rc;
}
-51
View File
@@ -87,58 +87,7 @@
- (void) notifyChangesForChild: (MAPIStoreMessage *) child
{
NSUInteger currentChildRow, newChildRow;
NSArray *list;
NSString *childName;
struct mapistore_table_notification_parameters notif_parameters;
struct mapistore_context *mstoreCtx;
mstoreCtx = [[(MAPIStoreFolder *) container context]
connectionInfo]->mstore_ctx;
notif_parameters.table_type = tableType;
notif_parameters.handle = handleId;
notif_parameters.folder_id = [(MAPIStoreFolder *) container objectId];
notif_parameters.object_id = [child objectId];
notif_parameters.instance_id = 0; /* TODO: always 0 ? */
childName = [child nameInContainer];
list = [self restrictedChildKeys];
currentChildRow = [list indexOfObject: childName];
notif_parameters.row_id = currentChildRow;
[self cleanupCaches];
list = [self restrictedChildKeys];
newChildRow = [list indexOfObject: childName];
if (currentChildRow == NSNotFound)
{
if (newChildRow != NSNotFound)
{
notif_parameters.row_id = newChildRow;
mapistore_push_notification (mstoreCtx,
MAPISTORE_TABLE,
MAPISTORE_OBJECT_CREATED,
&notif_parameters);
}
}
else
{
if (newChildRow == NSNotFound)
mapistore_push_notification (mstoreCtx,
MAPISTORE_TABLE,
MAPISTORE_OBJECT_DELETED,
&notif_parameters);
else
{
/* the fact that the row order has changed has no impact here */
notif_parameters.row_id = newChildRow;
mapistore_push_notification (mstoreCtx,
MAPISTORE_TABLE,
MAPISTORE_OBJECT_MODIFIED,
&notif_parameters);
}
}
}
@end
+2 -1
View File
@@ -45,7 +45,8 @@
context = talloc_zero(memCtx, struct mapistore_contexts_list);
context->url = talloc_asprintf (context, "sogo://%s@notes/",
[userName UTF8String]);
[[userName stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"] UTF8String]);
// context->name = "Notes personnelles";
context->main_folder = true;
context->role = MAPISTORE_NOTES_ROLE;
+3 -15
View File
@@ -23,7 +23,6 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSObject+Logs.h>
#import <SOGo/SOGoObject.h>
#import <SOGo/SOGoUser.h>
@@ -245,17 +244,16 @@ static Class NSExceptionK, MAPIStoreFolderK;
struct SPropValue *cValue;
NSUInteger counter;
NSMutableDictionary *newProperties;
NSTimeZone *tz;
NSInteger tzOffset;
id value;
tz = nil;
newProperties = [NSMutableDictionary dictionaryWithCapacity: aRow->cValues];
for (counter = 0; counter < aRow->cValues; counter++)
{
cValue = aRow->lpProps + counter;
value = NSObjectFromSPropValue (cValue);
if (value == nil)
continue;
switch (cValue->ulPropTag & 0xffff)
{
case PT_STRING8:
@@ -264,16 +262,6 @@ static Class NSExceptionK, MAPIStoreFolderK;
@"attempting to set string property as PR_STRING8: %.8x",
cValue->ulPropTag];
break;
case PT_SYSTIME:
if (!tz)
{
tz = [[self userContext] timeZone];
tzOffset = -[tz secondsFromGMT];
}
value = [value addYear: 0 month: 0 day: 0
hour: 0 minute: 0 second: tzOffset];
[value setTimeZone: tz];
break;
}
[newProperties setObject: value
forKey: MAPIPropertyKey (cValue->ulPropTag)];
+6 -1
View File
@@ -25,6 +25,8 @@
#include <talloc.h>
#import <Foundation/NSTimeZone.h>
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalRecurrenceRule.h>
@@ -41,7 +43,10 @@
@interface iCalCalendar (MAPIStoreRecurrence)
- (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity
fromRecurrencePattern: (struct RecurrencePattern *) rp;
fromRecurrencePattern: (struct RecurrencePattern *) rp
withExceptions: (struct ExceptionInfo *) exInfos
andExceptionCount: (uint16_t) exInfoCount
inTimeZone: (NSTimeZone *) tz;
@end
+52 -29
View File
@@ -24,6 +24,7 @@
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSSet.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NSObject+Logs.h>
@@ -48,6 +49,10 @@
- (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity
fromRecurrencePattern: (struct RecurrencePattern *) rp
withExceptions: (struct ExceptionInfo *) exInfos
andExceptionCount: (uint16_t) exInfoCount
inTimeZone: (NSTimeZone *) tz
{
NSCalendarDate *startDate, *olEndDate, *untilDate, *exDate;
NSString *monthDay, *month;
@@ -214,34 +219,42 @@
/* exception dates:
- take all deleted instances
- remove all modified instances from the above set
- remove all modified instances available in ExceptionInfo from the above set
- add remaining instances, in chronological order
*/
exceptionDates = [NSMutableSet set];
for (count = 0; count < rp->DeletedInstanceCount; count++)
{
exDate
= [NSDate dateFromMinutesSince1601: rp->DeletedInstanceDates[count]];
exDate = [exDate hour: [startDate hourOfDay]
minute: [startDate minuteOfHour]
second: [startDate secondOfMinute]];
[exceptionDates addObject: exDate];
}
for (count = 0; count < rp->ModifiedInstanceCount; count++)
{
exDate
= [NSDate dateFromMinutesSince1601: rp->ModifiedInstanceDates[count]];
exDate = [exDate hour: [startDate hourOfDay]
minute: [startDate minuteOfHour]
second: [startDate secondOfMinute]];
[exceptionDates removeObject: exDate];
}
realExDates = [[exceptionDates allObjects]
sortedArrayUsingSelector: @selector (compare:)];
max = [realExDates count];
for (count = 0; count < max; count++)
[entity addToExceptionDates: [realExDates objectAtIndex: count]];
/* Heuristic to avoid these loops */
if (rp->DeletedInstanceCount != rp->ModifiedInstanceCount) {
exceptionDates = [NSMutableSet set];
for (count = 0; count < rp->DeletedInstanceCount; count++)
{
exDate
= [NSDate dateFromMinutesSince1601: rp->DeletedInstanceDates[count]];
exDate = [exDate hour: [startDate hourOfDay]
minute: [startDate minuteOfHour]
second: [startDate secondOfMinute]];
[exceptionDates addObject: exDate];
}
/* Read the exceptions to remove the instances that are modified and not deleted */
if (exInfos && exInfoCount > 0)
{
for (count = 0; count < exInfoCount; count++)
{
/* The OriginalStartDate is in local time */
exDate = [NSDate dateFromMinutesSince1601: exInfos[count].OriginalStartDate];
exDate = [exDate dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: - [tz secondsFromGMT]];
[exceptionDates removeObject: exDate];
}
}
realExDates = [[exceptionDates allObjects]
sortedArrayUsingSelector: @selector (compare:)];
max = [realExDates count];
for (count = 0; count < max; count++)
[entity addToExceptionDates: [realExDates objectAtIndex: count]];
}
}
@end
@@ -312,15 +325,25 @@
rp->RecurFrequency = RecurFrequency_Weekly;
rp->PatternType = PatternType_Week;
rp->Period = repeatInterval;
dayOfWeek = [startDate dayOfWeek];
mask = 0;
byDayMask = [self byDayMask];
for (count = 0; count < 7; count++)
if ([byDayMask occursOnDay: count])
mask |= 1 << count;
if (byDayMask)
{
for (count = 0; count < 7; count++)
if ([byDayMask occursOnDay: count])
mask |= 1 << count;
}
else
{
/* Set the recurrence pattern using start date */
mask |= 1 << dayOfWeek;
}
rp->PatternTypeSpecific.WeekRecurrencePattern = mask;
/* FirstDateTime */
dayOfWeek = [startDate dayOfWeek];
if (dayOfWeek)
beginOfWeek = [startDate dateByAddingYears: 0 months: 0
days: -dayOfWeek
+66 -46
View File
@@ -47,6 +47,7 @@
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
#include <libmapi/libmapi.h>
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
#include <execinfo.h>
@@ -58,8 +59,8 @@ static BOOL initialization_done = NO;
#define NS_CURRENT_THREAD_REGISTER() \
BOOL __nsrct_thread_registered = GSRegisterCurrentThread(); \
if (!initialization_done) { \
DEBUG(5, ("[SOGo: %s:%d] You should call sogo_backend_init() first. Current thread: %p, pid: %d\n", \
__FUNCTION__, __LINE__, GSCurrentThread(), getpid())); \
OC_DEBUG(5, "[SOGo] You should call sogo_backend_init() first. Current thread: %p, pid: %d\n", \
GSCurrentThread(), getpid()); \
}
#define NS_CURRENT_THREAD_TRY_UNREGISTER() \
if (__nsrct_thread_registered) { \
@@ -144,7 +145,7 @@ sogo_backend_init (void)
GSRegisterCurrentThread();
if (initialization_done) {
DEBUG(0, ("SOGo backend already initialized.\n"));
OC_DEBUG(5, "[SOGo] SOGo backend already initialized.\n");
return MAPISTORE_SUCCESS;
}
@@ -189,7 +190,7 @@ sogo_backend_init (void)
[pool release];
DEBUG(0, ("[SOGo: %s:%d] backend init SUCCESS. Current thread: %p, pid: %d\n", __FUNCTION__, __LINE__, GSCurrentThread(), getpid()));
OC_DEBUG(5, "[SOGo] backend init SUCCESS. Current thread: %p, pid: %d\n", GSCurrentThread(), getpid());
initialization_done = YES;
return MAPISTORE_SUCCESS;
@@ -213,7 +214,7 @@ sogo_backend_create_context(TALLOC_CTX *mem_ctx,
MAPIStoreContext *context;
int rc;
DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
NS_CURRENT_THREAD_REGISTER();
pool = [NSAutoreleasePool new];
@@ -250,7 +251,7 @@ sogo_backend_create_root_folder (const char *username,
NSString *mapistoreUri;
int rc;
DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
NS_CURRENT_THREAD_REGISTER();
pool = [NSAutoreleasePool new];
@@ -287,7 +288,7 @@ sogo_backend_list_contexts(const char *username, struct indexing_context *indexi
NSString *userName;
int rc;
DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
NS_CURRENT_THREAD_REGISTER();
pool = [NSAutoreleasePool new];
@@ -335,7 +336,7 @@ sogo_context_get_path(void *backend_object, TALLOC_CTX *mem_ctx,
MAPIStoreContext *context;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (backend_object)
{
@@ -369,7 +370,7 @@ sogo_context_get_root_folder(void *backend_object, TALLOC_CTX *mem_ctx,
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (backend_object)
{
@@ -412,7 +413,7 @@ sogo_folder_open_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid,
MAPIStoreFolder *folder, *childFolder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -456,7 +457,7 @@ sogo_folder_create_folder(void *folder_object, TALLOC_CTX *mem_ctx,
MAPIStoreFolder *folder, *childFolder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -499,7 +500,7 @@ sogo_folder_delete(void *folder_object)
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -531,7 +532,7 @@ sogo_folder_get_child_count(void *folder_object, enum mapistore_table_type table
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -567,7 +568,7 @@ sogo_folder_open_message(void *folder_object,
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -609,7 +610,7 @@ sogo_folder_create_message(void *folder_object,
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -645,7 +646,7 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags)
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -683,7 +684,7 @@ sogo_folder_move_copy_messages(void *folder_object,
struct MAPIStoreTallocWrapper *wrapper;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -727,7 +728,7 @@ sogo_folder_move_folder(void *folder_object, void *target_folder_object,
struct MAPIStoreTallocWrapper *wrapper;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -777,7 +778,7 @@ sogo_folder_copy_folder(void *folder_object, void *target_folder_object, TALLOC_
struct MAPIStoreTallocWrapper *wrapper;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -821,7 +822,7 @@ sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx,
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -860,7 +861,7 @@ sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx,
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -899,7 +900,7 @@ sogo_folder_modify_permissions(void *folder_object, uint8_t flags,
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -933,7 +934,7 @@ sogo_folder_preload_message_bodies(void *folder_object, enum mapistore_table_typ
MAPIStoreFolder *folder;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (folder_object)
{
@@ -968,7 +969,7 @@ sogo_message_get_message_data(void *message_object,
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@@ -1003,7 +1004,7 @@ sogo_message_create_attachment (void *message_object, TALLOC_CTX *mem_ctx, void
MAPIStoreAttachment *attachment;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@@ -1040,7 +1041,7 @@ sogo_message_open_attachment (void *message_object, TALLOC_CTX *mem_ctx,
MAPIStoreAttachment *attachment;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@@ -1076,7 +1077,7 @@ sogo_message_get_attachment_table (void *message_object, TALLOC_CTX *mem_ctx, vo
MAPIStoreAttachmentTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@@ -1115,7 +1116,8 @@ sogo_message_modify_recipients (void *message_object,
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@@ -1150,7 +1152,8 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@@ -1183,7 +1186,8 @@ sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx)
MAPIStoreMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@@ -1216,7 +1220,8 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags)
MAPIStoreMailVolatileMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (message_object)
{
@@ -1254,7 +1259,8 @@ sogo_message_attachment_open_embedded_message (void *attachment_object,
MAPIStoreEmbeddedMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (attachment_object)
{
@@ -1295,7 +1301,8 @@ sogo_message_attachment_create_embedded_message (void *attachment_object,
MAPIStoreEmbeddedMessage *message;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (attachment_object)
{
@@ -1331,7 +1338,8 @@ static enum mapistore_error sogo_table_get_available_properties(void *table_obje
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@@ -1363,7 +1371,8 @@ sogo_table_set_columns (void *table_object, uint16_t count, enum MAPITAGS *prope
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@@ -1396,7 +1405,8 @@ sogo_table_set_restrictions (void *table_object, struct mapi_SRestriction *restr
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@@ -1431,7 +1441,8 @@ sogo_table_set_sort_order (void *table_object, struct SSortOrderSet *sort_order,
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@@ -1468,7 +1479,8 @@ sogo_table_get_row (void *table_object, TALLOC_CTX *mem_ctx,
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@@ -1503,7 +1515,8 @@ sogo_table_get_row_count (void *table_object,
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@@ -1536,7 +1549,8 @@ sogo_table_handle_destructor (void *table_object, uint32_t handle_id)
MAPIStoreTable *table;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (table_object)
{
@@ -1570,7 +1584,8 @@ static enum mapistore_error sogo_properties_get_available_properties(void *objec
MAPIStoreObject *propObject;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (object)
{
@@ -1605,7 +1620,8 @@ sogo_properties_get_properties (void *object,
MAPIStoreObject *propObject;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (object)
{
@@ -1639,7 +1655,8 @@ sogo_properties_set_properties (void *object, struct SRow *aRow)
MAPIStoreObject *propObject;
int rc;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (object)
{
@@ -1674,7 +1691,7 @@ sogo_manager_generate_uri (TALLOC_CTX *mem_ctx,
NSAutoreleasePool *pool;
NSString *partialURLString, *username, *directory;
DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__));
OC_DEBUG(5, "[SOGo]");
if (uri == NULL) return MAPISTORE_ERR_INVALID_PARAMETER;
@@ -1693,7 +1710,10 @@ sogo_manager_generate_uri (TALLOC_CTX *mem_ctx,
username = [NSString stringWithUTF8String: (user ? user : "*")];
/* Do proper directory lookup here */
directory = [NSString stringWithUTF8String: (folder ? folder : "*")];
partialURLString = [NSString stringWithFormat: @"sogo://%@:*@%@", username, directory];
partialURLString = [NSString stringWithFormat: @"sogo://%@:*@%@",
[username stringByReplacingOccurrencesOfString: @"@"
withString: @"%40"],
directory];
}
if (![partialURLString hasSuffix: @"/"])
partialURLString = [partialURLString stringByAppendingString: @"/"];
@@ -1776,7 +1796,7 @@ int mapistore_init_backend(void)
/* Register ourselves with the MAPISTORE subsystem */
ret = mapistore_backend_register (&backend);
if (ret != MAPISTORE_SUCCESS)
DEBUG(0, ("Failed to register the '%s' mapistore backend!\n", backend.backend.name));
OC_DEBUG(0, "[SOGo] Failed to register the '%s' mapistore backend!\n", backend.backend.name);
}
return ret;
+5 -2
View File
@@ -96,8 +96,11 @@ MAPIStoreInternalEntryId (struct ldb_context *samCtx, NSString *username)
[entryId appendUInt8: 0]; // end of string
}
else
entryId = nil;
{
NSLog (@"Error trying to generate EntryId for `%@`", username);
entryId = nil;
}
return entryId;
}
+101
View File
@@ -0,0 +1,101 @@
/* MAPIStoreSharingMessage.h - this file is part of SOGo-OpenChange
*
* Copyright (C) 2015 Enrique J. Hernández
*
* Author: Enrique J. Hernández <ejhernandez@zentyal.com>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef MAPISTORESHARINGMESSAGE_H
#define MAPISTORESHARINGMESSAGE_H
#import "MAPIStoreMailMessage.h"
#import "MAPIStoreObjectProxy.h"
#define SHARING_SPECIAL_FOLDER 0x40290
@interface MAPIStoreSharingMessage : MAPIStoreObjectProxy
{
struct mapistore_connection_info *connInfo;
NSMutableDictionary *properties;
}
- (id) initWithMailHeaders: (NSDictionary *) mailHeaders
andConnectionInfo: (struct mapistore_connection_info *) newConnInfo
fromMessage: (MAPIStoreMailMessage *) msg;
/* getters */
- (int) getPidLidSharingCapabilities: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingCapabilities: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingConfigurationUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingConfigUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingFlavor: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingFlavor: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingInitiatorEntryId: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingInitiatorName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingInitiatorSmtp: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingLocalType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingLocalType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingProviderGuid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingProviderGuid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingProviderName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingProviderName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingProviderUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingProviderUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingRemoteName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingRemoteName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingRemoteStoreUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameXSharingRemoteStoreUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingRemoteType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidTypeXSharingRemoteType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingResponseTime: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidLidSharingResponseType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
- (int) getPidNameContentClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;
/* Save */
- (void) saveWithMessage: (MAPIStoreMailMessage *) msg
andSOGoObject: (SOGoMailObject *) sogoObject;
@end
#endif /* MAPISTORECALENDARWRAPPER_H */
+463
View File
@@ -0,0 +1,463 @@
/* MAPIStoreSharingMessage.m - this file is part of SOGo-OpenChange
*
* Copyright (C) 2015 Enrique J. Hernández
*
* Author: Enrique J. Hernández <ejhernandez@zentyal.com>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <talloc.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Mailer/SOGoMailObject.h>
#import <NGExtensions/NGBase64Coding.h>
#import "NSData+MAPIStore.h"
#import "NSDate+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import "NSValue+MAPIStore.h"
#import "MAPIStoreMailFolder.h"
#import "MAPIStoreSharingMessage.h"
#import "MAPIStoreTypes.h"
#include <gen_ndr/property.h>
#include <mapistore/mapistore_errors.h>
#include <mapistore/mapistore_nameid.h>
@implementation MAPIStoreSharingMessage
- (id) init
{
if ((self = [super init]))
{
connInfo = NULL;
properties = nil;
}
return self;
}
- (id) initWithMailHeaders: (NSDictionary *) mailHeaders
andConnectionInfo: (struct mapistore_connection_info *) newConnInfo
fromMessage: (MAPIStoreMailMessage *) msg
{
NSEnumerator *enumerator;
NSString *key;
if ((self = [self init]))
{
connInfo = newConnInfo;
enumerator = [mailHeaders keyEnumerator];
properties = [NSMutableDictionary new];
while ((key = [enumerator nextObject]))
{
if ([key hasPrefix: @"x-ms-sharing-"])
[properties setObject: [mailHeaders objectForKey: key]
forKey: key];
}
/* Set request properties from container folder */
NSDictionary *requestProps = [(MAPIStoreMailFolder *)[msg container]
extraPropertiesForMessage: [msg nameInContainer]];
if (requestProps)
[properties addEntriesFromDictionary: requestProps];
}
return self;
}
- (void) dealloc
{
[properties release];
[super dealloc];
}
- (enum mapistore_error) _getStringProperty: (NSString *) propertyName
inData: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: propertyName];
if (value)
{
*data = [value asUnicodeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidLidSharingCapabilities: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: @"x-ms-sharing-capabilities"];
if (value)
{
*data = MAPILongValue (memCtx, [value intValue]);
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidNameXSharingCapabilities: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: @"x-ms-sharing-capabilities"];
if (value)
{
*data = [[NSString stringWithFormat:@"%X", [value intValue]]
asUnicodeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidLidSharingConfigurationUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"" asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidNameXSharingConfigUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingConfigurationUrl: data inMemCtx: memCtx];
}
- (int) getPidLidSharingFlavor: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
/* See [MS-OXSHARE] Section 2.2.2.5 for details */
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value, auxValue;
value = [properties objectForKey: @"x-ms-sharing-flavor"];
if (value)
{
*data = MAPILongValue (memCtx, [value intValue]);
rc = MAPISTORE_SUCCESS;
}
else
{
/* Guess its value required by old clients based on other properties */
value = [properties objectForKey: @"x-ms-sharing-capabilities"];
if (value)
{
if ([value intValue] == SHARING_SPECIAL_FOLDER)
{
value = [properties objectForKey: @"x-ms-sharing-responsetime"];
auxValue = [properties objectForKey: @"x-ms-sharing-remoteuid"];
if (value) /* A sharing request */
{
if (auxValue)
*data = MAPILongValue (memCtx, SHARING_INVITATION_REQUEST_FOLDER);
else
*data = MAPILongValue (memCtx, SHARING_REQUEST_SPECIAL_FOLDER);
}
else
{
if (auxValue) /* It SHOULD be an invitation or response */
*data = MAPILongValue (memCtx, SHARING_INVITATION_SPECIAL_FOLDER);
else /* No remote info, then denial */
*data = MAPILongValue (memCtx, SHARING_DENY_REQUEST);
}
}
else
{
*data = MAPILongValue (memCtx, SHARING_INVITATION_FOLDER);
}
rc = MAPISTORE_SUCCESS;
}
}
return rc;
}
- (int) getPidNameXSharingFlavor: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: @"x-ms-sharing-flavor"];
if (value)
{
*data = [[NSString stringWithFormat:@"%X", [value intValue]]
asUnicodeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidLidSharingInitiatorEntryId: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
NSData *entryId;
value = [properties objectForKey: @"x-ms-sharing-initiatorentryid"];
if (value)
{
entryId = [value dataByDecodingBase64];
if (entryId)
{
*data = [entryId asBinaryInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
}
return rc;
}
- (int) getPidLidSharingInitiatorName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-initiatorname"
inData: data
inMemCtx: memCtx];
}
- (int) getPidLidSharingInitiatorSmtp: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-initiatorsmtp"
inData: data
inMemCtx: memCtx];
}
- (int) getPidLidSharingLocalType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-localtype"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingLocalType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingLocalType: data inMemCtx: memCtx];
}
- (int) getPidLidSharingProviderGuid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
const unsigned char providerGuidBytes[] = {0xAE, 0xF0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
NSData *providerGuid = [NSData dataWithBytes: providerGuidBytes length: 16];
*data = [providerGuid asBinaryInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidNameXSharingProviderGuid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"AEF0060000000000C000000000000046" asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
- (int) getPidLidSharingProviderName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-providername"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingProviderName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingProviderName: data inMemCtx: memCtx];
}
- (int) getPidLidSharingProviderUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-providerurl"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingProviderUrl: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingProviderUrl: data inMemCtx: memCtx];
}
- (int) getPidLidSharingRemoteName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-remotename"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingRemoteName: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingRemoteName: data inMemCtx: memCtx];
}
- (int) getPidLidSharingRemoteStoreUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-remotestoreuid"
inData: data
inMemCtx: memCtx];
}
- (int) getPidNameXSharingRemoteStoreUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingRemoteStoreUid: data inMemCtx: memCtx];
}
- (int) getPidLidSharingRemoteType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-remotetype"
inData: data
inMemCtx: memCtx];
}
- (int) getPidTypeXSharingRemoteType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingRemoteType: data inMemCtx: memCtx];
}
- (int) getPidLidSharingRemoteUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self _getStringProperty: @"x-ms-sharing-remoteuid"
inData: data
inMemCtx: memCtx];
}
- (int) getPidUidXSharingRemoteUid: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
return [self getPidLidSharingRemoteUid: data inMemCtx: memCtx];
}
- (int) getPidLidSharingResponseTime: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: MAPIPropertyKey (PidLidSharingResponseTime)];
if (!value)
{
value = [properties objectForKey: @"x-ms-sharing-responsetime"];
if (value)
{
/* Here the value is a GSCBufferString */
NSString * responseTime = [NSString stringWithUTF8String: [value UTF8String]];
value = [NSDate dateWithString: responseTime];
}
}
if (value)
{
*data = [value asFileTimeInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidLidSharingResponseType: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND;
id value;
value = [properties objectForKey: MAPIPropertyKey (PidLidSharingResponseType)];
if (!value)
value = [properties objectForKey: @"x-ms-sharing-responsetype"];
if (value)
{
*data = MAPILongValue (memCtx, [value intValue]);
rc = MAPISTORE_SUCCESS;
}
return rc;
}
- (int) getPidNameContentClass: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
*data = talloc_strdup (memCtx, "Sharing");
return MAPISTORE_SUCCESS;
}
- (void) saveWithMessage: (MAPIStoreMailMessage *) msg
andSOGoObject: (SOGoMailObject *) sogoObject
{
/* Store PidLidSharingResponseType and PidLidSharingResponseTime if
required in versions message from the container as I don't see
other straightforward place to put that information */
id response;
NSDictionary *propsToStore;
response = [[msg properties] objectForKey: MAPIPropertyKey (PidLidSharingResponseType)];
if (response)
{
/* FIXME: Is there any better way to increase the modseq? */
[sogoObject addFlags: @"\\Draft"];
[sogoObject removeFlags: @"\\Draft"];
/* Store this modification in container folder along the property values */
propsToStore = [NSDictionary dictionaryWithObjects:
[NSArray arrayWithObjects: response,
[[msg properties] objectForKey: MAPIPropertyKey (PidLidSharingResponseTime)],
nil]
forKeys:
[NSArray arrayWithObjects: MAPIPropertyKey (PidLidSharingResponseType),
MAPIPropertyKey (PidLidSharingResponseTime), nil]];
[(MAPIStoreMailFolder *)[msg container] setExtraProperties: propsToStore
forMessage: [msg nameInContainer]];
}
}
@end
+20 -2
View File
@@ -367,13 +367,15 @@
NSString *status, *priority, *tzName;
NSCalendarDate *now;
NSInteger tzOffset;
NSTimeZone *userTZ;
double doubleValue;
vToDo = [sogoObject component: YES secure: NO];
vCalendar = [vToDo parent];
[vCalendar setProdID: @"-//Inverse inc.//OpenChange+SOGo//EN"];
tzName = [[[self userContext] timeZone] name];
userTZ = [[self userContext] timeZone];
tzName = [userTZ name];
tz = [iCalTimeZone timeZoneForName: tzName];
[vCalendar addTimeZone: tz];
@@ -428,6 +430,13 @@
{
date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"dtstart"];
[date setTimeZone: tz];
/* The property is set to user's local time zone.
See: [MS-OXOTASK] 2.2.2.2.4
TODO: Ignore when the PT_SYSTIME is 0x5AE980E0*/
tzOffset = [userTZ secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];
[date setDateTime: value];
}
@@ -437,6 +446,13 @@
{
date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"due"];
[date setTimeZone: tz];
/* The property is set to user's local time zone.
See: [MS-OXOTASK] 2.2.2.2.5
TODO: Ignore when the PT_SYSTIME is 0x5AE980E0*/
tzOffset = [userTZ secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];
[date setDateTime: value];
}
@@ -445,7 +461,9 @@
if (value)
{
date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"completed"];
tzOffset = [[value timeZone] secondsFromGMTForDate: value];
/* The property is set to midnight in local time zone converted to UTC:
See: [MS-OXOTASK] 2.2.2.2.9 */
tzOffset = [userTZ secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: -tzOffset];
+3
View File
@@ -157,6 +157,9 @@ static Class MAPIStoreTasksMessageK = Nil;
forKey: MAPIPropertyKey (PidLidTaskDueDate)];
[knownProperties setObject: @"c_creationdate"
forKey: MAPIPropertyKey (PidLidTaskOrdinal)];
/* Use by oxcfxics to sort the latest first */
[knownProperties setObject: @"c_lastmodified"
forKey: MAPIPropertyKey (PidTagMessageDeliveryTime)];
}
return [knownProperties objectForKey: MAPIPropertyKey (property)];
+3 -4
View File
@@ -119,6 +119,7 @@ NSObjectFromMAPISPropValue (const struct mapi_SPropValue *value)
break;
case PT_SYSTIME:
result = [NSCalendarDate dateFromFileTime: &(value->value.ft)];
[result setTimeZone: utcTZ];
break;
case PT_BINARY:
case PT_SVREID:
@@ -154,8 +155,7 @@ NSObjectFromMAPISPropValue (const struct mapi_SPropValue *value)
// #define PT_I8 0x14
// #define PT_SRESTRICT 0xFD
// #define PT_ACTIONS 0xFE
result = [NSNull null];
abort();
result = nil;
NSLog (@"%s: object type not handled: %d (0x%.4x)",
__PRETTY_FUNCTION__, valueType, valueType);
}
@@ -250,8 +250,7 @@ NSObjectFromSPropValue (const struct SPropValue *value)
// #define PT_I8 0x14
// #define PT_SRESTRICT 0xFD
// #define PT_ACTIONS 0xFE
result = [NSNull null];
abort();
result = nil;
NSLog (@"%s: object type not handled: %d (0x%.4x)",
__PRETTY_FUNCTION__, valueType, valueType);
}
+3 -3
View File
@@ -311,9 +311,9 @@ static NSMapTable *contextsTable = nil;
parts in this url. We strip the '-' character in case we have
this in the domain part - like foo@bar-zot.com */
ocFSTableName = [NSString stringWithFormat: @"sogo_cache_folder_%@",
[[[user loginInDomain] asCSSIdentifier]
stringByReplacingOccurrencesOfString: @"-"
withString: @"_"]];
[[[user login] asCSSIdentifier]
stringByReplacingOccurrencesOfString: @"-"
withString: @"_"]];
[parts replaceObjectAtIndex: 4 withObject: ocFSTableName];
folderTableURL
= [NSURL URLWithString: [parts componentsJoinedByString: @"/"]];
+118 -39
View File
@@ -26,6 +26,7 @@
// Useful macros
//
#define ADVANCE _bytes++; _current_pos++;
#define ADVANCE_N(N) _bytes += (N); _current_pos += (N);
#define REWIND _bytes--; _current_pos--;
@@ -412,16 +413,46 @@ const unsigned short ansicpg874[256] = {
- (const char *) parseControlWord: (unsigned int *) len
{
const char *start, *end;
start = ADVANCE;
while (isalnum(*_bytes) || *_bytes == '-')
/*
A control word is defined by:
\<ASCII Letter Sequence><Delimiter>
*/
while (isalpha(*_bytes))
{
ADVANCE;
}
/*
The <Delimiter> can be one of the following:
- A space. This serves only to delimit a control word and is
ignored in subsequent processing.
- A numeric digit or an ASCII minus sign (-), which indicates
that a numeric parameter is associated with the control word.
Only this case requires to include it in the control word.
- Any character other than a letter or a digit
*/
if (*_bytes == '-' || isdigit(*_bytes))
{
ADVANCE;
while (isdigit(*_bytes)) // TODO: Allow up to 10 digits
{
ADVANCE;
}
}
/* In this case, the delimiting character terminates the control
word and is not part of the control word. */
end = _bytes;
*len = end-start-1;
return start+1;
}
@@ -508,6 +539,7 @@ const unsigned short ansicpg874[256] = {
fontTable = [[[RTFFontTable alloc] init] autorelease];
fontName = nil;
fontInfo = nil;
count = 0;
do
@@ -543,7 +575,7 @@ const unsigned short ansicpg874[256] = {
// Skip our control word
if (strncmp((const char*)cw, "fonttbl", len) == 0)
continue;
// We must at least parse <fontnum><fontfamily><fcharset>
s = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1
length: len-1
@@ -558,12 +590,18 @@ const unsigned short ansicpg874[256] = {
// We now parse <fontfamily><fcharset>
cw = [self parseControlWord: &len];
if (len == 0) // Possibly parsing a space
cw = [self parseControlWord: &len];
fontInfo->family = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1
length: len-1
encoding: NSASCIIStringEncoding
freeWhenDone: NO];
cw = [self parseControlWord: &len];
if (len == 0) // Possibly parsing a space
cw = [self parseControlWord: &len];
fontInfo->charset = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1
length: len-1
encoding: NSASCIIStringEncoding
@@ -622,13 +660,44 @@ const unsigned short ansicpg874[256] = {
} while (count != 0);
}
- (void) parseIgnoringEverything
{
unsigned int count = 1;
// Ignore everything. But we cannot parse it blindly because it could have
// binary data with '}' and '{' bytes, so disasters can happen and they will
do
{
if (*_bytes == '\\')
{
unsigned int binary_size, len = 0, cw_len;
const char *cw = [self parseControlWord: &len];
cw_len = strlen("bin");
if (strncmp(cw, "bin", cw_len) == 0 && len > cw_len)
{
NSString *s;
s = [[NSString alloc] initWithBytesNoCopy: (void *) cw + cw_len
length: len - cw_len
encoding: NSASCIIStringEncoding
freeWhenDone: NO];
[s autorelease];
binary_size = [s intValue];
ADVANCE_N(binary_size);
}
}
if (*_bytes == '{') count++;
if (*_bytes == '}') count--;
ADVANCE;
}
while (count > 0);
}
//
//
//
- (void) parsePicture
{
// Do the same as -parseStyleSheet for now, that is, ignore everything.
[self parseStyleSheet];
[self parseIgnoringEverything];
}
//
@@ -648,6 +717,7 @@ const unsigned short ansicpg874[256] = {
fontTable = nil;
colorTable = nil;
charset = NULL;
formattingOptions = nil;
_html = [[NSMutableData alloc] init];
[_html appendBytes: "<html><meta charset='utf-8'><body>" length: 34];
@@ -694,19 +764,7 @@ const unsigned short ansicpg874[256] = {
}
else if (*(_bytes+1) == '*')
{
int cc = 1;
do
{
if (*_bytes == '{')
cc++;
if (*_bytes == '}')
cc--;
ADVANCE;
}
while (cc != 0);
[self parseIgnoringEverything];
continue;
}
@@ -726,16 +784,16 @@ const unsigned short ansicpg874[256] = {
{
// We rewind our buffer so we start at the beginning of {\fonttbl...
_bytes = cw-2;
_current_pos -= 10;
_current_pos -= 9; // Length: {\fonttbl
fontTable = [self parseFontTable];
// We go back 1 byte in order to end our section properly ('}' character
// We go back 1 byte in order to end our section properly ('}' character)
REWIND;
}
else if (strncmp(cw, "stylesheet", 10) == 0)
{
_bytes = cw-2;
_current_pos -= 13;
_current_pos -= 12; // Length: {\stylesheet
[self parseStyleSheet];
REWIND;
}
@@ -746,7 +804,7 @@ const unsigned short ansicpg874[256] = {
else if (strncmp(cw, "pict", 4) == 0)
{
_bytes = cw-2;
_current_pos -= 7;
_current_pos -= 6; // Length: {\pict
[self parsePicture];
REWIND;
}
@@ -766,19 +824,19 @@ const unsigned short ansicpg874[256] = {
int color_index;
char *v;
if (!formattingOptions) continue;
color_index = [[s substringFromIndex: 2] intValue];
if (!formattingOptions)
continue;
if (formattingOptions->color_index >= 0) // && color_index != formattingOptions->color_index)
colorDef = [colorTable colorDefAtIndex: color_index];
if (!colorDef) continue;
if (formattingOptions->color_index >= 0)
{
[_html appendBytes: "</font>" length: 7];
}
formattingOptions->color_index = color_index;
colorDef = [colorTable colorDefAtIndex: color_index];
formattingOptions->color_index = color_index;
v = malloc(23*sizeof(char));
memset(v, 0, 23);
sprintf(v, "<font color=\"#%02x%02x%02x\">", colorDef->red, colorDef->green, colorDef->blue);
@@ -814,20 +872,41 @@ const unsigned short ansicpg874[256] = {
if (!formattingOptions)
continue;
if (formattingOptions->font_index >= 0 &&
font_index != formattingOptions->font_index)
{
[_html appendBytes: "</font>" length: 7];
}
formattingOptions->font_index = font_index;
fontInfo = [fontTable fontInfoAtIndex: font_index];
char *v = malloc(128*sizeof(char));
memset(v, 0, 128);
sprintf(v, "<font face=\"%s\">", [fontInfo->name UTF8String]);
char *v = NULL;
if (fontInfo && fontInfo->name)
{
if ([fontInfo->name length] < 128)
{
int tag_size = 15 + [fontInfo->name length];
v = calloc(tag_size, sizeof(char));
snprintf(v, tag_size, "<font face=\"%s\">", [fontInfo->name UTF8String]);
}
else
{
NSLog(@"RTFHandler: Font %u has %d chars length, parse error? "
"Ignored", font_index, [fontInfo->name length]);
v = calloc(7, sizeof(char));
sprintf(v, "<font>");
}
}
else
{
// RTF badformed? We don't know about that font (font_index).
// Anyhow, we still open the html tag because in the future
// we will close it (e.g. when new font is used).
v = calloc(7, sizeof(char));
sprintf(v, "<font>");
}
[_html appendBytes: v length: strlen(v)];
free(v);
}
+3 -3
View File
@@ -39,7 +39,7 @@
#import <SOGo/BSONCodec.h>
#import "NSObject+PropertyList.h"
Class MAPIStoreUserContextK, SOGoMAPIDBObjectK;
Class MAPIStoreUserContextK, SOGoCacheGCSObjectK;
static void
DumpBSONData(NSData *data)
@@ -60,7 +60,7 @@ DbDumpObject (NSString *username, NSString *path)
ctx = [MAPIStoreUserContextK userContextWithUsername: username
andTDBIndexing: NULL];
dbobject = [SOGoMAPIDBObjectK new];
dbobject = [SOGoCacheGCSObjectK new];
[dbobject setTableUrl: [ctx folderTableURL]];
record = [dbobject lookupRecord: path newerThanVersion: -1];
if (record)
@@ -107,7 +107,7 @@ int main (int argc, char *argv[], char *envp[])
[loader loadProducts: [NSArray arrayWithObject: BACKEND_BUNDLE_NAME]];
MAPIStoreUserContextK = NSClassFromString (@"MAPIStoreUserContext");
SOGoMAPIDBObjectK = NSClassFromString (@"SOGoMAPIDBObject");
SOGoCacheGCSObjectK = NSClassFromString (@"SOGoCacheGCSObject");
arguments = [[NSProcessInfo processInfo] arguments];
if ([arguments count] > 2) {
+162 -137
View File
@@ -74,6 +74,7 @@
@implementation iCalEvent (MAPIStoreProperties)
- (void) _setupEventRecurrence: (NSData *) mapiRecurrenceData
inTimeZone: (NSTimeZone *) tz
inMemCtx: (TALLOC_CTX *) memCtx
{
struct Binary_r *blob;
@@ -81,9 +82,18 @@
blob = [mapiRecurrenceData asBinaryInMemCtx: memCtx];
pattern = get_AppointmentRecurrencePattern (memCtx, blob);
[(iCalCalendar *) parent
setupRecurrenceWithMasterEntity: self
fromRecurrencePattern: &pattern->RecurrencePattern];
if (pattern == NULL) {
[self logWithFormat: @"Error parsing recurrence pattern. No changes in event recurrence will be done"];
return;
}
[(iCalCalendar *) parent setupRecurrenceWithMasterEntity: self
fromRecurrencePattern: &pattern->RecurrencePattern
withExceptions: pattern->ExceptionInfo
andExceptionCount: pattern->ExceptionCount
inTimeZone: tz
];
//talloc_free (blob);
}
@@ -131,6 +141,107 @@
}
}
- (int) _updateFromAttendeeMAPIProperties: (NSArray *) recipients
withRole: (NSString *) role
outParam: (BOOL *) organizerIsSet
{
NSDictionary *dict;
NSString *attEmail;
iCalPerson *person;
iCalPersonPartStat newPartStat;
NSNumber *flags, *trackStatus;
int i, effective;
effective = 0;
for (i = 0; i < [recipients count]; i++)
{
dict = [recipients objectAtIndex: i];
person = [iCalPerson new];
[person setCn: [dict objectForKey: @"fullName"]];
attEmail = [dict objectForKey: @"email"];
[person setEmail: attEmail];
flags = [dict objectForKey: MAPIPropertyKey (PR_RECIPIENT_FLAGS)];
if (!flags)
{
[self logWithFormat:
@"no recipient flags specified: skipping recipient"];
continue;
}
if (([flags unsignedIntValue] & 0x0002)) /* recipOrganizer */
{
[self setOrganizer: person];
*organizerIsSet = YES;
[self logWithFormat: @"organizer set via recipient flags"];
}
else
{
BOOL isOrganizer = NO;
// /* Work-around: it happens that Outlook still passes the
// organizer as a recipient, maybe because of a feature
// documented in a pre-mesozoic PDF still buried in a
// cavern... In that case we remove it, and we keep the
// number of effective recipients in "effective". If the
// total is 0, we remove the "ORGANIZER" too. */
// if ([attEmail isEqualToString: orgEmail])
// {
// [self logWithFormat:
// @"avoiding setting organizer as recipient"];
// continue;
// }
trackStatus = [dict objectForKey: MAPIPropertyKey (PidTagRecipientTrackStatus)];
if (trackStatus)
{
/* FIXME: we should provide a data converter between OL
partstats and SOGo */
switch ([trackStatus unsignedIntValue])
{
case 0x01: /* respOrganized */
isOrganizer = YES;
break;
case 0x02: /* respTentative */
newPartStat = iCalPersonPartStatTentative;
break;
case 0x03: /* respAccepted */
newPartStat = iCalPersonPartStatAccepted;
break;
case 0x04: /* respDeclined */
newPartStat = iCalPersonPartStatDeclined;
break;
default:
newPartStat = iCalPersonPartStatNeedsAction;
}
if (isOrganizer)
{
[self setOrganizer: person];
*organizerIsSet = YES;
[self logWithFormat: @"organizer set via track status"];
}
else
{
[person setParticipationStatus: newPartStat];
[person setRsvp: @"TRUE"];
[person setRole: role];
[self addToAttendees: person];
effective++;
}
}
else
[self errorWithFormat: @"skipped recipient due"
@" to missing track status"];
}
[person release];
}
return effective;
}
- (void) updateFromMAPIProperties: (NSDictionary *) properties
inUserContext: (MAPIStoreUserContext *) userContext
withActiveUser: (SOGoUser *) activeUser
@@ -140,7 +251,7 @@
iCalDateTime *start, *end;
iCalTimeZone *tz;
NSTimeZone *userTimeZone;
NSString *priority;
NSString *priority, *class = nil;
NSUInteger responseStatus = 0;
NSInteger tzOffset;
SOGoUser *ownerUser;
@@ -207,16 +318,7 @@
value
= [properties objectForKey: MAPIPropertyKey (PidLidExceptionReplaceTime)];
if (value)
{
if (!isAllDay)
{
tzOffset = [userTimeZone secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
}
[self setRecurrenceId: value];
}
[self setRecurrenceId: value];
// start
value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentStartWhole)];
@@ -241,13 +343,7 @@
[start setTimeZone: nil];
}
else
{
tzOffset = [userTimeZone secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[start setDateTime: value];
}
}
/* end */
@@ -273,13 +369,7 @@
[end setTimeZone: nil];
}
else
{
tzOffset = [[value timeZone] secondsFromGMTForDate: value];
value = [value dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 0
seconds: tzOffset];
[end setDateTime: value];
}
}
/* priority */
@@ -302,6 +392,36 @@
priority = @"0"; // None
[self setPriority: priority];
/* class */
/* See [MS-OXCICAL] Section 2.1.3.11.20.4 */
value = [properties objectForKey: MAPIPropertyKey(PR_SENSITIVITY)];
if (value)
{
switch ([value intValue])
{
case 1:
class = @"X-PERSONAL";
break;
case 2:
class = @"PRIVATE";
break;
case 3:
class = @"CONFIDENTIAL";
break;
default: /* 0 as well */
class = @"PUBLIC";
}
}
if (class)
[self setAccessClass: class];
/* Categories */
/* See [MS-OXCICAL] Section 2.1.3.1.1.20.3 */
value = [properties objectForKey: MAPIPropertyKey (PidNameKeywords)];
if (value)
[self setCategories: value];
/* show time as free/busy/tentative/out of office. Possible values are:
0x00000000 - olFree
0x00000001 - olTentative
@@ -347,7 +467,7 @@
value = [properties
objectForKey: MAPIPropertyKey (PidLidAppointmentRecur)];
if (value)
[self _setupEventRecurrence: value inMemCtx: memCtx];
[self _setupEventRecurrence: value inTimeZone: userTimeZone inMemCtx: memCtx];
/* alarm */
[self _setupEventAlarmFromProperties: properties];
@@ -356,106 +476,28 @@
value = [properties objectForKey: @"recipients"];
if (value)
{
NSArray *recipients;
NSDictionary *dict;
NSString *orgEmail, *sentBy, *attEmail;
NSString *orgEmail, *sentBy;
iCalPerson *person;
iCalPersonPartStat newPartStat;
NSNumber *flags, *trackStatus;
int i, effective;
int effective;
BOOL organizerIsSet = NO;
[self setOrganizer: nil];
[self removeAllAttendees];
recipients = [value objectForKey: @"to"];
effective = 0;
for (i = 0; i < [recipients count]; i++)
{
dict = [recipients objectAtIndex: i];
person = [iCalPerson new];
[person setCn: [dict objectForKey: @"fullName"]];
attEmail = [dict objectForKey: @"email"];
[person setEmail: attEmail];
flags = [dict objectForKey: MAPIPropertyKey (PR_RECIPIENT_FLAGS)];
if (!flags)
{
[self logWithFormat:
@"no recipient flags specified: skipping recipient"];
continue;
}
/* In [MS-OXOCAL] Section 2.2.4.10.7 says the recipient type is 0x01 as Required
and 0x02 as Optional and other documents such [MS-OXCMSG] 2.2.3.1.2 indicates
that MAPI_TO is 0x01 and MAPI_CC is 0x02, that's why in SOGo is in 'to' and 'cc'
respectively. */
effective = [self _updateFromAttendeeMAPIProperties: [value objectForKey: @"to"]
withRole: @"REQ-PARTICIPANT"
outParam: &organizerIsSet];
effective += [self _updateFromAttendeeMAPIProperties: [value objectForKey: @"cc"]
withRole: @"OPT-PARTICIPANT"
outParam: &organizerIsSet];
if (([flags unsignedIntValue] & 0x0002)) /* recipOrganizer */
{
[self setOrganizer: person];
organizerIsSet = YES;
[self logWithFormat: @"organizer set via recipient flags"];
}
else
{
BOOL isOrganizer = NO;
// /* Work-around: it happens that Outlook still passes the
// organizer as a recipient, maybe because of a feature
// documented in a pre-mesozoic PDF still buried in a
// cavern... In that case we remove it, and we keep the
// number of effective recipients in "effective". If the
// total is 0, we remove the "ORGANIZER" too. */
// if ([attEmail isEqualToString: orgEmail])
// {
// [self logWithFormat:
// @"avoiding setting organizer as recipient"];
// continue;
// }
trackStatus = [dict objectForKey: MAPIPropertyKey (PidTagRecipientTrackStatus)];
if (trackStatus)
{
/* FIXME: we should provide a data converter between OL
partstats and SOGo */
switch ([trackStatus unsignedIntValue])
{
case 0x01: /* respOrganized */
isOrganizer = YES;
break;
case 0x02: /* respTentative */
newPartStat = iCalPersonPartStatTentative;
break;
case 0x03: /* respAccepted */
newPartStat = iCalPersonPartStatAccepted;
break;
case 0x04: /* respDeclined */
newPartStat = iCalPersonPartStatDeclined;
break;
default:
newPartStat = iCalPersonPartStatNeedsAction;
}
if (isOrganizer)
{
[self setOrganizer: person];
organizerIsSet = YES;
[self logWithFormat: @"organizer set via track status"];
}
else
{
[person setParticipationStatus: newPartStat];
[person setRsvp: @"TRUE"];
[person setRole: @"REQ-PARTICIPANT"];
[self addToAttendees: person];
effective++;
}
}
else
[self errorWithFormat: @"skipped recipient due"
@" to missing track status"];
}
[person release];
}
if (effective == 0) /* See work-around above */
if (effective == 0) /* See work-around inside _updateFromAttendeeMAPIProperties */
[self setOrganizer: nil];
else
{
@@ -481,7 +523,7 @@
= [properties objectForKey: MAPIPropertyKey (PidLidResponseStatus)];
if (value)
responseStatus = [value unsignedLongValue];
/* FIXME: we should provide a data converter between OL partstats and
SOGo */
switch (responseStatus)
@@ -503,23 +545,6 @@
value = [properties objectForKey: MAPIPropertyKey (PidLidAttendeeCriticalChange)];
if (value && ![value isNever])
[self setTimeStampAsDate: value];
// if (newPartStat // != iCalPersonPartStatUndefined
// )
// {
// // iCalPerson *participant;
// // participant = [self userAsAttendee: ownerUser];
// // [participant setParticipationStatus: newPartStat];
// // [sogoObject saveComponent: self];
// [sogoObject changeParticipationStatus: newPartStat
// withDelegate: nil];
// // [[self context] tearDownRequest];
// }
// // }1005
// // else
// // {
}
}
else
@@ -534,7 +559,7 @@
[person setCn: [dict objectForKey: @"fullName"]];
orgEmail = [dict objectForKey: @"email"];
[person setEmail: orgEmail];
if (![activeUser isEqual: ownerUser])
{
dict = [activeUser primaryIdentity];
+9 -1
View File
@@ -51,6 +51,7 @@
NSArray *byMonth;
iCalByDayMask *mask;
NSCalendarDate *dateValue;
int16_t wDay;
rrule = [self recurrenceRule];
byMonth = [rrule byMonth];
@@ -59,7 +60,14 @@
tzData->wMonth = [[byMonth objectAtIndex: 0] intValue];
mask = [rrule byDayMask];
tzData->wDayOfWeek = [mask firstDay];
tzData->wDay = [mask firstOccurrence];
wDay = [mask firstOccurrence];
if (wDay < 0)
/* [MS-OXOCAL] the wDay field is set to indicate the
occurrence of the day of the week within the month (1 to
5, where 5 indicates the final occurrence during the
month if that day of the week does not occur 5 times). */
wDay += 6;
tzData->wDay = (uint16_t) wDay;
dateValue = [self startDate];
tzData->wHour = [dateValue hourOfDay];
+1
View File
@@ -4,5 +4,6 @@ import sys
import samba.param
a = samba.param.LoadParm()
a.set('debug level', '0')
a.load_default()
print a.get(sys.argv[1])
+1 -1
View File
@@ -240,7 +240,7 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60;
handle = currentHandle;
else if (debugPools)
[self logWithFormat: @"DBPOOL: cannot use handle (%@ vs %@) ",
[_url absoluteString], [handle->url absoluteString]];
[_url absoluteString], [currentHandle->url absoluteString]];
return handle;
}
+2 -1
View File
@@ -20,6 +20,7 @@
*/
#import <Foundation/NSDictionary.h>
#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSSet.h>
#import <Foundation/NSString.h>
@@ -147,7 +148,7 @@
if ([keys count] == 0)
return folderQualifier;
bindings = [_folder valuesForKeys:keys];
bindings = [_folder dictionaryWithValuesForKeys:keys];
return [folderQualifier qualifierWithBindings:bindings
requiresAllVariables:NO];
}
+6 -1
View File
@@ -131,7 +131,7 @@
},
{
columnName = c_partstates;
sqlType = "VARCHAR2(255)";
sqlType = "CLOB";
allowsNull = YES;
},
{
@@ -154,5 +154,10 @@
sqlType = "INTEGER";
allowsNull = YES;
},
{
columnName = c_description;
sqlType = "CLOB";
allowsNull = YES;
}
);
}
+6 -1
View File
@@ -131,7 +131,7 @@
},
{
columnName = c_partstates;
sqlType = "VARCHAR(255)";
sqlType = "TEXT";
allowsNull = YES;
},
{
@@ -153,6 +153,11 @@
columnName = c_nextalarm;
sqlType = "INT";
allowsNull = YES;
},
{
columnName = c_description;
sqlType = "TEXT";
allowsNull = YES;
}
);
}
+6 -4
View File
@@ -59,8 +59,10 @@ static NGCardsSaxHandler *sax = nil;
[parser setErrorHandler:sax];
}
else
NSLog(@"ERROR(%s): did not find a parser for text/x-vcard!",
__PRETTY_FUNCTION__);
{
//NSLog(@"ERROR(%s): did not find a parser for text/x-vcard!",
// __PRETTY_FUNCTION__);
}
}
return parser;
@@ -170,8 +172,8 @@ static NGCardsSaxHandler *sax = nil;
{
if (![aChild isKindOfClass: mappedClass])
{
NSLog (@"warning: new child to entity '%@': '%@' converted to '%@'",
tag, childTag, NSStringFromClass(mappedClass));
//NSLog (@"warning: new child to entity '%@': '%@' converted to '%@'",
// tag, childTag, NSStringFromClass(mappedClass));
newChild = [aChild elementWithClass: mappedClass];
}
}
+1 -1
View File
@@ -54,7 +54,7 @@
- (BOOL)appendLine:(NSString *)_line {
if (self->isFinished) {
NSLog(@"WARNING[%s]: already finished!", __PRETTY_FUNCTION__);
//NSLog(@"WARNING[%s]: already finished!", __PRETTY_FUNCTION__);
return NO;
}
// limit length to 75 chars
-2
View File
@@ -55,8 +55,6 @@ static NSArray *privilegedTagNames = nil;
- (void) dealloc
{
if (content)
free (content);
[self reset];
[cards release];
[currentGroup release];
+2 -2
View File
@@ -77,8 +77,8 @@ static NSString *gmtcalfmt = @"%Y%m%dT%H%M%SZ";
return [self icalStringInGMT];
else {
/* not in GMT */
NSLog(@"WARNING(%s): arbitary timezones not supported yet: %@",
__PRETTY_FUNCTION__, _tz);
//NSLog(@"WARNING(%s): arbitary timezones not supported yet: %@",
// __PRETTY_FUNCTION__, _tz);
return [self icalStringInGMT];
}
}
+3 -1
View File
@@ -276,7 +276,9 @@
}
}
else
NSLog(@"Cannot parse iCal duration value: '%@'", self);
{
//NSLog(@"Cannot parse iCal duration value: '%@'", self);
}
if (isNegative)
ti = -ti;
+2 -2
View File
@@ -59,8 +59,8 @@ static NSTimeZone *defTZ = nil;
[self takeValue:_value forXKey:_key];
}
else {
NSLog(@"0x%08x[%@]: ignoring attempt to set unbound key '%@'",
self, NSStringFromClass([self class]), _key);
//NSLog(@"0x%08x[%@]: ignoring attempt to set unbound key '%@'",
// self, NSStringFromClass([self class]), _key);
}
}
+37 -3
View File
@@ -156,13 +156,15 @@
[tzStart setTimeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
tmpDate = [NSCalendarDate dateWithYear: [refDate yearOfCommonEra]
month: [[[rrule byMonth] objectAtIndex: 0] intValue]
day: 1 hour: [tzStart hourOfDay]
day: 1
hour: [tzStart hourOfDay]
minute: [tzStart minuteOfHour] second: 0
timeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
tmpDate = [tmpDate addYear: 0 month: ((pos > 0) ? 0 : 1)
day: 0 hour: 0 minute: 0
second: 0];
/* If the day of the time change is "-XSU", we need to determine whether the
first day of next month is in the same week. In practice, as most time
changes occurs on sundays, it will be false only when that first day is a
@@ -171,10 +173,42 @@
if (dateDayOfWeek > dayOfWeek && pos < 0)
pos++;
/* We check if the days of the week are identical. This is important because if they
are, "pos" actually includes the first day of tmpDate which means we must decrement
pos by 1. This happens for example in the eastern timezone (America/Montreal)
in 2015. We have:
BEGIN:VTIMEZONE
TZID:America/Montreal
X-LIC-LOCATION:America/Montreal
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE
The time changes occure on a Sunday, but in March, the 1st is a Sunday itself and in November
the 1st is also a Sunday. If we don't decrement "pos" by one, tmpDate (which is set to March or November 1st
because of "day: 1" will have 14 more days added for March and 7 more days added for November - which will
effectively shift the time change by a whole week.
*/
if (dayOfWeek == dateDayOfWeek)
pos--;
offset = (dayOfWeek - dateDayOfWeek) + (pos * 7);
tmpDate = [tmpDate addYear: 0 month: 0 day: offset
hour: 0 minute: 0 second: 0];
return tmpDate;
}
@@ -1075,6 +1075,12 @@ static NSCharacterSet *whitespaceCharSet = nil;
// FIXME: Data is not always utf-8.....
source = [[[NSString alloc] initWithData: _data encoding: encoding]
autorelease];
// We fallback to ISO-8859-1 string encoding
if (!source)
source = [[[NSString alloc] initWithData: _data encoding: NSISOLatin1StringEncoding]
autorelease];
if (!source)
{
e = (id)[SaxParseException exceptionWithName: @"SaxIOException"
+14
View File
@@ -0,0 +1,14 @@
[Unit]
Description=SOGo is a groupware server
After=network.target
[Service]
Environment="PREFORK=3"
EnvironmentFile=-/etc/sysconfig/sogo
Type=forking
ExecStart=/usr/sbin/sogod -WOWorkersCount ${PREFORK} -WOPidFile /var/run/sogo/sogo.pid -WOLogFile /var/log/sogo/sogo.log
PIDFile=/var/run/sogo/sogo.pid
User=sogo
[Install]
WantedBy=multi-user.target
+59
View File
@@ -0,0 +1,59 @@
#!/bin/bash
set -e
# This script only works with MySQL
# updates c_partstates to mediumtext
# adds c_description to Calendar quick tables
# http://www.sogo.nu/bugs/view.php?id=3175
# the field length was actually changed in v2.2.18
defaultusername=$USER
defaulthostname=127.0.0.1
defaultdatabase=$USER
indextable=$(sogo-tool dump-defaults -f /etc/sogo/sogo.conf | awk -F\" '/ OCSFolderInfoURL =/ {print $2}' | awk -F/ '{print $NF}')
if [ -z "$indextable" ]; then
echo "Couldn't fetch OCSFolderInfoURL value, aborting" >&2
exit 1
fi
read -p "Username ($defaultusername): " username
read -p "Hostname ($defaulthostname): " hostname
read -p "Database ($defaultdatabase): " database
if [ -z "$username" ]
then
username=$defaultusername
fi
if [ -z "$hostname" ]
then
hostname=$defaulthostname
fi
if [ -z "$database" ]
then
database=$defaultdatabase
fi
sqlscript=""
function adjustSchema() {
oldIFS="$IFS"
IFS=" "
part1="`echo -e \"ALTER TABLE $table MODIFY c_partstates mediumtext;\\n\"`";
part2="`echo -e \"ALTER TABLE $table ADD COLUMN c_description mediumtext;\\n\"`";
sqlscript="$sqlscript$part1$part2"
IFS="$oldIFS"
}
echo "This script will ask for the sql password twice" >&2
echo "Converting c_partstates from VARCHAR(255) to mediumtext in calendar quick tables" >&2
tables=`mysql -p -s -u $username -h $hostname $database -e "select SUBSTRING_INDEX(c_quick_location, '/', -1) from $indextable where c_path3 = 'Calendar';"`
for table in $tables;
do
adjustSchema
done
echo "$sqlscript" | mysql -p -s -u $username -h $hostname $database
+56
View File
@@ -0,0 +1,56 @@
#!/bin/bash
set -e
# This script only works with PostgreSQL
# updates c_partstates to text
# adds c_description to Calendar quick tables
# http://www.sogo.nu/bugs/view.php?id=3175
# the field length was actually changed in v2.2.18
defaultusername=$USER
defaulthostname=localhost
defaultdatabase=$USER
#indextable=sogo_folder_info
indextable=$(sogo-tool dump-defaults -f /etc/sogo/sogo.conf | awk -F\" '/ OCSFolderInfoURL =/ {print $2}' | awk -F/ '{print $NF}')
if [ -z "$indextable" ]; then
echo "Couldn't fetch OCSFolderInfoURL value, aborting" >&2
exit 1
fi
read -p "Username ($defaultusername): " username
read -p "Hostname ($defaulthostname): " hostname
read -p "Database ($defaultdatabase): " database
if [ -z "$username" ]
then
username=$defaultusername
fi
if [ -z "$hostname" ]
then
hostname=$defaulthostname
fi
if [ -z "$database" ]
then
database=$defaultdatabase
fi
sqlscript=""
function adjustSchema() {
oldIFS="$IFS"
IFS=" "
part1="`echo -e \"ALTER TABLE $table ALTER COLUMN c_partstates TYPE TEXT;\\n\"`";
part2="`echo -e \"ALTER TABLE $table ADD COLUMN c_description TEXT;\\n\"`";
sqlscript="$sqlscript$part1$part2"
IFS="$oldIFS"
}
echo "Converting c_cycleinfo from VARCHAR(255) to TEXT in calendar quick tables" >&2
tables=`psql -t -U $username -h $hostname $database -c "select split_part(c_quick_location, '/', 5) from $indextable where c_path3 = 'Calendar';"`
for table in $tables;
do
adjustSchema
done
echo "$sqlscript" | psql -q -e -U $username -h $hostname $database
@@ -0,0 +1,67 @@
"Inviting the following persons is prohibited:" = "Ondorengo pertsonak gonbidatzea debekatuta dago:";
"Personal Calendar" = "Egutegi pertsonala";
vevent_class0 = "(Ekitaldi publikoa)";
vevent_class1 = "(Ekitaldi pribatua)";
vevent_class2 = "(Isilpeko ekitaldia)";
vtodo_class0 = "(Zeregin publikoa)";
vtodo_class1 = "(Zeregin pribatua)";
vtodo_class2 = "(Isilpeko egitekoa)";
/* Receipts */
"The event \"%{Summary}\" was created" = "\"%{Summary}\" ekitaldia sortu da";
"The event \"%{Summary}\" was deleted" = "\"%{Summary}\" ekitaldia ezabatu da";
"The event \"%{Summary}\" was updated" = "\"%{Summary}\" ekitaldia eguneratu da";
"The following attendees(s) were notified:" = "Ondorengo partaidea(k) jakinarazi d(ir)a:";
"The following attendees(s) were added:" = "Ondorengo partaidea(k) gehitu d(ir)a:";
"The following attendees(s) were removed:" = "Ondorengo partaidea(k) ezabatu d(ir)a:";
/* IMIP messages */
"calendar_label" = "Egutegia";
"startDate_label" = "Hasi:";
"endDate_label" = "Amaitu:";
"due_label" = "Epemuga:";
"location_label" = "Kokapena:";
"summary_label" = "Laburpena:";
"comment_label" = "Iruzkina:";
/* Invitation */
"Event Invitation: \"%{Summary}\"" = "Ekitaldirako gonbidapena: \"%{Summary}\"";
"(sent by %{SentBy}) " = "(%{SentBy}-k bidalia) ";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText}-k gonbidatu zaitu %{Summary}.-ra\n\nHasiera: %{StartDate}\nAmaiera: %{EndDate}\nDeskribapena: %{Description}";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText}-k gonbidatu zaitu %{Summary}-ra \n\nHasiera: %{StartDate}-an, %{StartTime}-tan\nEnd: %{EndDate}-an, %{EndTime}-tan\nDeskribapena: %{Description}";
/* Deletion */
"Event Cancelled: \"%{Summary}\"" = "Ekitaldia bertan behera utzi da: \"%{Summary}\"";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
= "%{Organizer} %{SentByText} ekitaldi hau bertan behera utzi du: %{Summary}.\n\nHasiera: %{StartDate}\nAmaiera: %{EndDate}\nDEskribapena: %{Description}";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
= "%{Organizer} %{SentByText}-k honako ekitaldia bertan behera utzi du: %{Summary}.\n\nHasiera: %{StartDate}-an, %{StartTime}-tan\nAmaiera: %{EndDate}-an %{EndTime}-tan\nDeskribapena: %{Description}";
/* Update */
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
= "%{OldStartDate} eguneko \"%{Summary}\" hitzordua aldatu da";
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
= "%{OldStartDate} eguneko eta %{OldStartTime} orduko \"%{Summary}\" hitzordua aldatu da";
"The following parameters have changed in the \"%{Summary}\" meeting:"
= " \"%{Summary}\" bilerako ondorengo parametroak aldatu dira:";
"Please accept or decline those changes."
= "Mesedez, onartu edo ezetsi ondorengo aldaketak.";
/* Reply */
"Accepted invitation: \"%{Summary}\"" = "Gonbidapena onartua: \"%{Summary}\"";
"Declined invitation: \"%{Summary}\"" = "Ezetzitako gonbidapena: \"%{Summary}\"";
"Delegated invitation: \"%{Summary}\"" = "Delegatutako gonbidapena: \"%{Summary}\"";
"Not yet decided on invitation: \"%{Summary}\"" = "\"%{Summary}\" gonbidapenari buruz erabaki gabe";
"%{Attendee} %{SentByText}has accepted your event invitation."
= "%{Attendee} %{SentByText} -k zure gonbidapena onartu du.";
"%{Attendee} %{SentByText}has declined your event invitation."
= "%{Attendee} %{SentByText}-k zure gonbidapenari uko egin dio.";
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
= "%{Attendee} %{SentByText}-k zure gonbidapena %{Delegate}-ri delegatu dio.";
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
= "%{Attendee} %{SentByText}-k ez du oraindik zure gonbidapenari buruz erabakirik hartu.";
/* Resources */
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "Ezin da honako baliabidea atzitu: \"%{Cn} %{SystemEmail}\"";
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "\"%{Cn} %{SystemEmail}\" baliabidearentzako gehienezko erreserba kopurura (%{NumberOfSimultaneousBookings}) iritsi gara. Gatazka sortu duen ekitaldia \"%{EventTitle}\" da, eta %{StartDate}-n hasten da.";
@@ -56,7 +56,7 @@ vtodo_class2 = "(Tarefa Confidencial)";
"%{Attendee} %{SentByText}has accepted your event invitation."
= "%{Attendee} %{SentByText}foi aceitado seu convite ao evento.";
"%{Attendee} %{SentByText}has declined your event invitation."
= "%{Attendee} %{SentByText}foi declinado seu convite ao evento.";
= "%{Attendee} %{SentByText}recusou seu convite para o evento.";
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
= "%{Attendee} %{SentByText} delegou o convite para %{Delegate}.";
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
+1 -1
View File
@@ -54,7 +54,7 @@ Appointments_RESOURCE_FILES += \
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
Appointments_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
Appointments_LOCALIZED_RESOURCE_FILES = Localizable.strings
@@ -70,11 +70,27 @@
to: (NSCalendarDate *) newEndDate
{
ASSIGN(address, newAddress);
ASSIGN(startDate, newStartDate);
ASSIGN(endDate, newEndDate);
startDate = [NSCalendarDate dateWithYear: [newStartDate yearOfCommonEra]
month: [newStartDate monthOfYear]
day: [newStartDate dayOfMonth]
hour: [newStartDate hourOfDay]
minute: [newStartDate minuteOfHour]
second: [newStartDate secondOfMinute]
timeZone: [newStartDate timeZone]];
endDate = [NSCalendarDate dateWithYear: [newEndDate yearOfCommonEra]
month: [newEndDate monthOfYear]
day: [newEndDate dayOfMonth]
hour: [newEndDate hourOfDay]
minute: [newEndDate minuteOfHour]
second: [newEndDate secondOfMinute]
timeZone: [newEndDate timeZone]];
[startDate setTimeZone: timeZone];
[endDate setTimeZone: timeZone];
[startDate retain];
[endDate retain];
}
- (NSString *) serverVersion
+28 -17
View File
@@ -492,6 +492,9 @@ static Class iCalEventK = nil;
//
// If the user is NOT the owner of the calendar, by default we exclude the freebusy information.
//
// We must include the freebusy information of other users if we are actually looking at their freebusy information
// but we aren't necessarily subscribed to their calendars.
//
- (BOOL) includeInFreeBusy
{
NSNumber *excludeFromFreeBusy;
@@ -499,17 +502,32 @@ static Class iCalEventK = nil;
BOOL is_owner;
userLogin = [[context activeUser] login];
is_owner = [userLogin isEqualToString: [self ownerInContext: context]];
is_owner = [userLogin isEqualToString: self->owner];
// Check if the owner (not the active user) has excluded the calendar from her/his free busy data.
excludeFromFreeBusy
= [self folderPropertyValueInCategory: @"FreeBusyExclusions"
forUser: [SOGoUser userWithLogin: userLogin]];
forUser: [context activeUser]];
if (!excludeFromFreeBusy && !is_owner)
return NO;
return ![excludeFromFreeBusy boolValue];
if ([self isSubscription])
{
// If the user has not yet set an include/not include fb information let's EXCLUDE it.
if (!excludeFromFreeBusy)
return NO;
else
return ![excludeFromFreeBusy boolValue];
}
else if (is_owner)
{
// We are the owner but we haven't included/excluded freebusy info, let's INCLUDE it.
if (!excludeFromFreeBusy)
return YES;
else
return ![excludeFromFreeBusy boolValue];
}
// It's not a subscribtion and we aren't the owner. Let's INCLUDE the freebusy info.
return YES;
}
- (void) setIncludeInFreeBusy: (BOOL) newInclude
@@ -782,7 +800,7 @@ static Class iCalEventK = nil;
/**
* Set the timezone of the event start and end dates to the user's timezone.
* @param theRecord a dictionnary with the attributes of the event.
* @param theRecord a dictionary with the attributes of the event.
* @return a copy of theRecord with adjusted dates.
*/
- (NSMutableDictionary *) _fixupRecord: (NSDictionary *) theRecord
@@ -908,11 +926,6 @@ static Class iCalEventK = nil;
dateSecs = [NSNumber numberWithInt: [date timeIntervalSince1970]];
[record setObject: dateSecs forKey: @"c_enddate"];
// The first instance date is added to the dictionary so it can
// be used by UIxCalListingActions to compute the DST offset.
date = [theFirstCycle startDate];
[record setObject: date forKey: @"cycleStartDate"];
return record;
}
@@ -1085,9 +1098,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
[newRecord setObject: dateSecs forKey: @"c_recurrence_id"];
[newRecord setObject: [NSNumber numberWithInt: 1] forKey: @"c_iscycle"];
// The first instance date is added to the dictionary so it can
// be used by UIxCalListingActions to compute the DST offset.
[newRecord setObject: [fir startDate] forKey: @"cycleStartDate"];
// We identified the record as an exception.
[newRecord setObject: [NSNumber numberWithInt: 1] forKey: @"isException"];
@@ -2803,7 +2814,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
@"c_category", @"c_classification", @"c_isallday",
@"c_isopaque", @"c_participants", @"c_partmails",
@"c_partstates", @"c_sequence", @"c_priority",
@"c_cycleinfo", @"c_iscycle", @"c_nextalarm", nil];
@"c_cycleinfo", @"c_iscycle", @"c_nextalarm", @"c_description", nil];
return [self fetchFields: infos from: _startDate to: _endDate title: title
component: _component
@@ -1,7 +1,7 @@
/* SOGoAppointmentFolders.m - this file is part of SOGo
*
* Copyright (C) 2007-2014 Inverse inc.
* Copyright (C) 2007-2015 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 -22
View File
@@ -400,9 +400,9 @@
{
currentUID = [currentAttendee uid];
if (currentUID)
[self _addOrUpdateEvent: newEvent
forUID: currentUID
owner: owner];
[self _addOrUpdateEvent: newEvent
forUID: currentUID
owner: owner];
}
[self sendEMailUsingTemplateNamed: @"Update"
@@ -421,11 +421,14 @@
SOGoUserSettings *us;
NSMutableArray *unavailableAttendees;
NSEnumerator *enumerator;
NSString *currentUID, *ownerUID, *whiteListString;
NSString *currentUID, *ownerUID;
NSMutableString *reason;
NSDictionary *values;
NSMutableDictionary *value, *moduleSettings, *whiteList;
NSMutableDictionary *value, *moduleSettings;
id whiteList;
int i, count;
i = count = 0;
// Build list of the attendees uids without ressources
@@ -443,12 +446,15 @@
us = [user userSettings];
moduleSettings = [us objectForKey:@"Calendar"];
// Check if the user prevented his account from beeing invited to events
// Check if the user prevented their account from beeing invited to events
if (![user isResource] && [[moduleSettings objectForKey:@"PreventInvitations"] boolValue])
{
// Check if the user have a whiteList
whiteListString = [moduleSettings objectForKey:@"PreventInvitationsWhitelist"];
whiteList = [whiteListString objectFromJSONString];
whiteList = [moduleSettings objectForKey:@"PreventInvitationsWhitelist"];
// For backward <= 2.2.17 compatibility
if ([whiteList isKindOfClass: [NSString class]])
whiteList = [whiteList objectFromJSONString];
// If the filter have a hit, do not add the currentUID to the unavailableAttendees array
if (![whiteList objectForKey:ownerUID])
@@ -637,10 +643,10 @@
if ([fbInfo count])
{
// If we always force the auto-accept if numberOfSimultaneousBookings == 0 (ie., no limit
// 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 ||
if ([user numberOfSimultaneousBookings] <= 0 ||
[user numberOfSimultaneousBookings] > [fbInfo count])
{
if (currentAttendee)
@@ -734,7 +740,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
// the modification was actually NOT made on the master event
if ([theEvent recurrenceId])
return;
events = [[theEvent parent] events];
for (i = 0; i < [events count]; i++)
@@ -743,12 +749,12 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
if ([e recurrenceId])
for (j = 0; j < [theAttendees count]; j++)
if (shouldAdd)
[e addToAttendees: [theAttendees objectAtIndex: j]];
else
[e removeFromAttendees: [theAttendees objectAtIndex: j]];
[e addToAttendees: [theAttendees objectAtIndex: j]];
else
[e removeFromAttendees: [theAttendees objectAtIndex: j]];
}
}
//
//
//
@@ -803,14 +809,17 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
// We insert the attendees in all exception occurences, if
// the attendees were added to the master event.
[self _addOrDeleteAttendees: addedAttendees
inRecurrenceExceptionsForEvent: newEvent
add: YES];
inRecurrenceExceptionsForEvent: newEvent
add: YES];
if ([changes sequenceShouldBeIncreased])
{
[newEvent increaseSequence];
// Update attendees calendars and send them an update
// notification by email
// notification by email. We ignore the newly added
// attendees as we don't want to send them invitation
// update emails
[self _handleSequenceUpdateInEvent: newEvent
ignoringAttendees: addedAttendees
fromOldEvent: oldEvent];
@@ -1093,7 +1102,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
else
{
// We must REMOVE any SENT-BY here. This is important since if A accepted
// the event for B and then, B changes by himself his participation status,
// the event for B and then, B changes by theirself their participation status,
// we don't want to keep the previous SENT-BY attribute there.
[(NSMutableDictionary *)[otherAttendee attributes] removeObjectForKey: @"SENT-BY"];
}
@@ -1191,7 +1200,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
else
{
// We must REMOVE any SENT-BY here. This is important since if A accepted
// the event for B and then, B changes by himself his participation status,
// the event for B and then, B changes by theirself their participation status,
// we don't want to keep the previous SENT-BY attribute there.
[(NSMutableDictionary *)[attendee attributes] removeObjectForKey: @"SENT-BY"];
}
@@ -1208,7 +1217,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
delegatedUID = [otherDelegate uid];
if (delegatedUID)
// Delegate attendee is a local user; remove event from his calendar
// Delegate attendee is a local user; remove event from their calendar
[self _removeEventFromUID: delegatedUID
owner: [theOwnerUser login]
withRecurrenceId: [event recurrenceId]];
@@ -1240,7 +1249,7 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
[event addToAttendees: delegate];
if (delegatedUID)
// Delegate attendee is a local user; add event to his calendar
// Delegate attendee is a local user; add event to their calendar
[self _addOrUpdateEvent: event
forUID: delegatedUID
owner: [theOwnerUser login]];
@@ -644,8 +644,8 @@
// As much as we can, we try to use c_name == c_uid in order
// to avoid tricky scenarios with some CalDAV clients. For example,
// if Alice invites Bob (both use SOGo) and Bob accepts the invitation
// using Lightning before having refreshed his calendar, he'll end up
// with a duplicate of the event in his database tables.
// using Lightning before having refreshed their calendar, they'll end up
// with a duplicate of the event in their database tables.
if (isNew)
{
newUid = nameInContainer;
+5 -11
View File
@@ -62,17 +62,14 @@
SOGoUserManager *um;
NSString *domain;
NSDictionary *contactInfos;
NSArray *contacts;
um = [SOGoUserManager sharedUserManager];
contactInfos = [um contactInfosForUserWithUIDorEmail: uid];
if (contactInfos == nil)
{
// Search among global addressbooks
domain = [[context activeUser] domain];
[um fetchContactsMatching: uid inDomain: domain];
contacts = [um fetchContactsMatching: uid inDomain: domain];
if ([contacts count] == 1)
contactInfos = [contacts lastObject];
contactInfos = [um fetchContactWithUID: uid inDomain: domain];
}
/* iCal.app compatibility:
@@ -279,7 +276,6 @@
if ([uid length])
{
SOGoUserManager *um;
NSArray *contacts;
NSString *domain, *email;
NSDictionary *contact;
MSExchangeFreeBusy *exchangeFreeBusy;
@@ -287,10 +283,9 @@
um = [SOGoUserManager sharedUserManager];
domain = [[context activeUser] domain];
contacts = [um fetchContactsMatching: uid inDomain: domain];
if ([contacts count] == 1)
contact = [um fetchContactWithUID: uid inDomain: domain];
if (contact)
{
contact = [contacts lastObject];
email = [contact valueForKey: @"c_email"];
source = [contact objectForKey: @"source"];
if ([email length]
@@ -386,8 +381,7 @@
([currentStartDate compare: startDate] == NSOrderedAscending)? startDate : currentStartDate, @"startDate",
currentEndDate, @"endDate", nil]];
if (!firstRange
&& currentEndDate != endDate
if (currentEndDate != endDate
&& ([currentEndDate dayOfWeek] == 6 || [currentEndDate dayOfWeek] == 0))
{
// Fill weekend days
@@ -1,6 +1,6 @@
/* SOGoWebAppointmentFolder.m - this file is part of SOGo
*
* Copyright (C) 2009-2014 Inverse inc.
* Copyright (C) 2009-2015 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
@@ -137,6 +137,7 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
curl_easy_setopt (curl, CURLOPT_URL, [location UTF8String]);
curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt (curl, CURLOPT_TIMEOUT, 60L);
authInfos = [self _loadAuthData];
if (authInfos)
+1 -1
View File
@@ -93,7 +93,7 @@
element = [elements objectAtIndex: 0];
else
{
NSLog(@"ERROR: given calendar contains no elements: %@", self);
//NSLog(@"ERROR: given calendar contains no elements: %@", self);
element = nil;
}
+6
View File
@@ -248,6 +248,12 @@
else
[row setObject: [NSNull null] forKey: @"c_category"];
/* handle description */
if ([self comment])
[row setObject: [self comment] forKey: @"c_description"];
else
[row setObject: [NSNull null] forKey: @"c_description"];
return row;
}
+6
View File
@@ -177,6 +177,12 @@
[row setObject: [categories componentsJoinedByString: @","]
forKey: @"c_category"];
/* handle description */
if ([self comment])
[row setObject: [self comment] forKey: @"c_description"];
else
[row setObject: [NSNull null] forKey: @"c_description"];
return row;
}
@@ -0,0 +1,2 @@
"Personal Address Book" = "Helbide liburu pertsonala";
"Collected Address Book" = "Bildutako helbide liburua";
@@ -1,2 +1,2 @@
"Personal Address Book" = "Livro de Endereços Pessoais";
"Personal Address Book" = "Livro de Endereço Pessoal";
"Collected Address Book" = "Catálogos Coletados";
+1 -1
View File
@@ -27,7 +27,7 @@ Contacts_OBJC_FILES = \
Contacts_RESOURCE_FILES += \
product.plist \
Contacts_LANGUAGES = Arabic BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
Contacts_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian Slovak SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
Contacts_LOCALIZED_RESOURCE_FILES = Localizable.strings
Loaded 100 of 294 files, more files were not shown because too many files have changed in this diff. Show more