Compare commits

...
330 Commits
Author SHA1 Message Date
Francis Lachapelle b5e77ad86c Bump version to 2.1.1a 2013-11-22 15:16:20 -05:00
Francis Lachapelle 5bc0a0a932 Update NEWS file 2013-11-22 15:11:13 -05:00
Francis Lachapelle 582af53af0 Cleanup wox templates 2013-11-22 15:10:39 -05:00
Francis Lachapelle 13f01b512b Move mail tags strings to UI/Common 2013-11-22 15:10:31 -05:00
Ludovic Marcotte cdb25b141d Init local variable to avoid potential crasher. 2013-11-22 15:10:16 -05:00
Francis Lachapelle a9868b1c93 Fix the Sieve filters editor with new mail flags 2013-11-22 15:09:49 -05:00
Jean Raby 2cf66e037d Merge to 2.1.1 2013-11-19 14:00:22 -05:00
Jean Raby 6587f4f193 Update ChangeLog 2013-11-19 13:59:20 -05:00
Francis Lachapelle c8a4ea5548 Update translations 2013-11-19 13:57:18 -05:00
Jean Raby 148fd4936c Update Version to 2.1.1 and update news 2013-11-19 13:43:45 -05:00
Jean Raby a7fef39448 Update to 2.1.1 2013-11-19 13:43:22 -05:00
Francis Lachapelle 5a3d0d27e0 Fix bug following mail tags management CSS changes 2013-11-19 13:39:48 -05:00
Ludovic Marcotte eb9111b5fa Updated news for the recent bug fix 2013-11-19 11:40:33 -05:00
Ludovic Marcotte eb7d1f08bc Fix for bug #2482 2013-11-19 11:39:45 -05:00
Ludovic Marcotte 854fed529c Added SOGoMailAuxiliaryUserAccountsEnabled 2013-11-19 09:52:53 -05:00
Jean Raby 3c29e0724d update news file 2013-11-15 16:12:15 -05:00
Jean Raby cebaed9059 Merge branch 'master' of https://github.com/inverse-inc/sogo 2013-11-15 16:09:52 -05:00
Jean Raby aae26602b0 Use raw (utf7) name when checking folder type 2013-11-15 16:04:09 -05:00
Jean Raby 05233d9c53 Use modified utf7 for special folder names 2013-11-15 16:02:59 -05:00
Francis Lachapelle e862194b32 Convert color picker to an inline widget
The colors are now limited to the colors offered in Thunderbird.
2013-11-15 15:50:46 -05:00
Jean Raby 884fbfdb73 Bump copyright and fix whitespace (tab kill) 2013-11-15 13:17:37 -05:00
Ludovic Marcotte c05cf00db7 Update standard tag colors to match TB and improve tags id generation. 2013-11-14 09:00:19 -05:00
Ludovic Marcotte 198db855f6 Specify color in which TB can grok it. 2013-11-13 15:55:25 -05:00
Ludovic Marcotte 1c439c866e Added DAV support for mails labels. 2013-11-13 15:44:57 -05:00
Francis Lachapelle 616ee7c6e4 GUI changes for mail labels management 2013-11-13 14:46:08 -05:00
Ludovic Marcotte 37d3234b60 Added support for dynamic mail labels/tags management.
The CSS in the UIxPreferences remains to be done.
2013-11-11 10:49:58 -05:00
Francis Lachapelle 449d838dc2 Merge to 2.1.0 2013-11-07 14:43:19 -05:00
Francis Lachapelle 6a9bcfda68 Update ChangeLog 2013-11-07 14:42:48 -05:00
Francis Lachapelle d0b09ebe35 Update translations 2013-11-07 14:14:39 -05:00
Francis Lachapelle 0361b7dfdb Documentation - bump version to 2.1.0 2013-11-07 11:09:41 -05:00
Francis Lachapelle 38b350382a Update NEWS file 2013-11-07 10:13:30 -05:00
Francis Lachapelle 73141a645e Update translations 2013-11-06 21:36:09 -05:00
Francis Lachapelle f07526423f Fix display of ICal event in message 2013-11-06 15:25:36 -05:00
Francis Lachapelle ba35a4b003 Update CKEditor to version 4.2.2 2013-11-06 11:29:15 -05:00
Ludovic Marcotte 47c4ad5807 Make sure the var is initilized to nil. 2013-10-29 20:58:26 -04:00
Ludovic Marcotte 0f3e31ebf1 Added more tags to skip 2013-10-23 16:37:03 -04:00
Ludovic Marcotte 87261f3280 Fix for bug #2468. 2013-10-23 16:04:37 -04:00
Ludovic Marcotte bd2759ecdf Fix for bug #2433 2013-10-22 11:44:26 -04:00
Ludovic Marcotte be1bcf3c9b Fix for bug #2461 2013-10-22 11:25:24 -04:00
Ludovic Marcotte 053b090aff Fix for bug #2235 2013-10-21 15:37:01 -04:00
Ludovic Marcotte 189f2218a8 Fix for bug #2459 2013-10-21 15:26:43 -04:00
Ludovic Marcotte 656869a4a2 Fix for bug #1328 2013-10-18 13:16:30 -04:00
Ludovic Marcotte 16f62e2393 Fix for bug #2434 2013-10-18 10:30:43 -04:00
Jean Raby 9289615996 Added https vhost example for apple carddav 2013-10-17 11:45:07 -04:00
Jean Raby fdea04c08c Added some verbose logging for expire-autoreply 2013-10-15 10:49:21 -04:00
Jean Raby edca3638ec Fixup backup_dir to use sogo's home directory 2013-10-11 13:41:44 -04:00
Ludovic Marcotte 05990e9a14 Fix for bug 2007 2013-09-30 10:50:27 -04:00
Jean Raby 3cce9b2012 Fix file permissions 2013-09-30 09:39:29 -04:00
Ludovic Marcotte 7dc65af300 Fix for bug #2386 2013-09-27 15:54:11 -04:00
Ludovic Marcotte 84e999229b Fix for bug #2270 2013-09-27 15:36:46 -04:00
Francis Lachapelle 3dbfb0ed2d Add Underline option to HTML editor 2013-09-27 14:43:05 -04:00
Francis Lachapelle d1f3417c3a Update CKEditor to version 4.2.1
And added the table-related modules.
2013-09-27 14:25:22 -04:00
Ludovic Marcotte 7c7031333e Fix for bug #2221 2013-09-27 10:00:39 -04:00
Jean Raby 1e48481426 Updated description/default value for WOPort 2013-09-26 08:51:42 -04:00
Jean Raby 8ae1624604 Added --noexpiry for administrator 2013-09-26 08:49:17 -04:00
Ludovic Marcotte 7166f5a597 Fix for bug #2399 2013-09-25 16:02:13 -04:00
Ludovic Marcotte 55052ea36f Fix for bug #2240 2013-09-25 14:40:48 -04:00
Ludovic Marcotte 99d38417cc Fix for bug #2354 2013-09-25 13:51:42 -04:00
Ludovic Marcotte 29eed182a7 Updated the OpenChange code related to UTF-7 changes for IMAP folders 2013-09-25 10:41:07 -04:00
Ludovic Marcotte 744610dbe1 Fixed tests regarding new WebDAV sync responses 2013-09-25 08:46:34 -04:00
Ludovic Marcotte d2b739d261 Fix for bug #2318 2013-09-24 16:01:23 -04:00
Ludovic Marcotte 2ba8254ecc Fix for bug #1275 2013-09-24 09:29:46 -04:00
Jean Raby 28e600a4e6 Set default listening address to 127.0.0.1:20000
No reason to listen on 0.0.0.0 by default
2013-09-20 15:37:34 -04:00
Ludovic Marcotte ab6e4841ba Merge branch 'master' of https://github.com/inverse-inc/sogo
Conflicts:
	NEWS
2013-09-19 16:14:41 -04:00
Ludovic Marcotte 91f1ab6a60 Fix for bug #2217 2013-09-19 16:14:08 -04:00
Jean Raby 32a534919d update NEWS. ldap fixes 2013-09-19 11:11:29 -04:00
Ludovic Marcotte 5b77c2b724 Stability fix when we're untable to determine the message class type 2013-09-19 10:49:42 -04:00
Ludovic Marcotte 70086e5ee6 Fix for bug #1935 2013-09-19 09:56:28 -04:00
Ludovic Marcotte 7ddc1b9e2d Avoid type-issues generating wrong GlobCnt - leading to OpenChange crashes during the sync process. 2013-09-18 14:03:07 -04:00
Francis Lachapelle 6d93db96e4 Update NEWS file 2013-09-17 11:17:40 -04:00
Jean Raby 27445d3b85 update news 2013-09-17 09:27:46 -04:00
Jean Raby 60d6abe542 Use HTTP/1.0 to avoid chunked replies
Fixes^WWorkaround #2408
2013-09-17 09:07:53 -04:00
Ludovic Marcotte baacf8516d Updated NEWS file regarding previous commit 2013-09-16 11:21:23 -04:00
Ludovic Marcotte 46a48faf23 Merge branch 'master' of https://github.com/inverse-inc/sogo 2013-09-16 11:00:40 -04:00
Ludovic Marcotte 193720cfbb Fix for s/mime verification issues with some openssl versions 2013-09-16 10:59:45 -04:00
Jean Raby f40580d632 Merge branch 'master' of https://github.com/inverse-inc/sogo 2013-09-13 11:25:08 -04:00
Jean Raby ca4d89fb08 update with latest fixes 2013-09-13 11:24:16 -04:00
Jean Raby 906985c1f3 Call MSExchangeHostname on SOGoDNSource only
Fixes #2418
2013-09-13 11:19:44 -04:00
Jean Raby de8bf64c70 Local pool when appending contacts to response
Avoids using too much memory when doing a contact lookup with many matches
2013-09-13 11:16:28 -04:00
Jean Raby 0c38a9e555 whitespace tabkill 2013-09-13 11:13:02 -04:00
Francis Lachapelle 3c6c90d434 Reload webmail when changing "remote images" pref 2013-09-13 09:33:28 -04:00
Francis Lachapelle 72a4b075d6 Mail popup: respect "remote inline images" prefs
Fixes #2417
2013-09-12 17:08:02 -04:00
Francis Lachapelle 24c0fb1cc4 Fix change listener on calendar list select input
Fixes #2353
2013-09-12 16:33:44 -04:00
Jean Raby 7241e3e30e Added rewrite rule for apple autoconfiguration url
Rewrite rules are no inherited by virtualhosts when they are declared in conf.d
This means that you'll have to explicitly include SOGo.conf from 000-default
on debian/ubuntu for this redirection to work properly.
2013-09-12 10:14:47 -04:00
Jean Raby 1d705dc00b Next version: 2.1.0 2013-09-10 13:58:04 -04:00
Jean Raby df42ab2a46 Run 3 sogod process by default instead on only 1 2013-09-09 10:07:07 -04:00
Ludovic Marcotte 53f9d0d7f5 Merge branch 'master' of https://github.com/inverse-inc/sogo 2013-09-06 13:49:25 -04:00
Jean Raby f59c77a950 Update news 2013-09-06 13:49:04 -04:00
Ludovic Marcotte cd4abe4b5b Fix for bug 2398 2013-09-06 13:48:44 -04:00
Francis Lachapelle 69b0f9fcbf Mail notifications: Escape HTML in wox templates
We don't escape the values in the classes but in the templates.
2013-09-03 12:05:13 -04:00
Jean Raby dceead3997 Fixup sogo spool cleanup cronjob
Add -user sogo to be on the safe side.
Change call to /bin/rmdir by -delete to avoid error messages.
Find would call rmdir and then do an openat() on the deleted directory,
which would obviously fail.

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

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

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

SOGoDAVAuthenticator is not updated since it doesn't really use the imap code.
2013-06-18 16:36:11 -04:00
Ludovic Marcotte 47a3f1a19d toggle to send or not notifications 2013-06-18 14:14:42 -04:00
Ludovic Marcotte f25344182d Rewrote escapedForCards so it's 10 times faster. 2013-06-14 14:58:16 -04:00
Jean Raby f24e3a0a31 whitespace fixes. tabkill 2013-06-12 02:36:50 -04:00
Ludovic Marcotte afb7bc309c Added message submissions rate-limiting support 2013-06-11 11:21:58 -04:00
Ludovic Marcotte cfee5aa3f4 Added new failed login rate-limiting options 2013-06-11 09:41:17 -04:00
Francis Lachapelle 2a51f6f385 Update CKEditor to version 4.1.2
Also added the blockquote plugin.
2013-06-10 21:07:52 -04:00
Jean Raby 4cffea43eb French translation of Sync Issues 2013-06-07 15:16:12 -04:00
Jean Raby cafce5753d update description of MultipleBookingsFieldName 2013-06-06 16:04:47 -04:00
Francis Lachapelle 5d6a5f5d5e Update CKEditor to version 4.1.1 2013-06-06 13:21:26 -04:00
Francis Lachapelle 8e5a26dfb1 Remove unicode separators from JSON
Fixes #2309
2013-06-05 15:55:52 -04:00
Ludovic Marcotte 4cb0facd72 Fixed bug #2206 2013-06-04 08:51:38 -04:00
Francis Lachapelle 854bce28fb Fix condition in UIxMailPartHTMLViewer 2013-06-03 12:07:18 -04:00
Francis Lachapelle 49e964c529 Fix decoding charset parameter
To avoid a libxml bug/limitation, we were already stripping the charset
parameter, but we were not considering the single quote as valid
delimiter.
2013-06-03 11:47:48 -04:00
Jean Raby 3281cea2a2 Add bindFields to the sample configuration file 2013-05-31 15:54:22 -04:00
Jean Raby 82253e91d2 don't use -M when creating the sogo user on debian
-M was not available in lenny. It is not actually needed since useradd
won't create the homedir when adding a system user (-r)
2013-05-24 15:00:05 -04:00
Jean Raby 1d1ed9a031 Update ldap filter description, example and syntax 2013-05-15 14:51:15 -04:00
Francis Lachapelle 2bd8a2935f Change default value of SOGoMailSpoolPath
Set the spool path to /var/spool/sogo and modified the installation
guide to point to the tmpwatch cronjob when changing SOGoMailSpoolPath.
2013-05-09 08:12:27 -04:00
Francis Lachapelle 8a25e38827 Add indent group to ckeditor toolbar 2013-05-02 09:07:17 -04:00
Ludovic Marcotte 4ec19d46fa Removed left-over code that would cause the logic from bug #2035 to not work. 2013-04-25 14:46:00 -04:00
Jean Raby d46a39e252 TOC links 2013-04-22 13:22:16 -04:00
Jean Raby 23e10d30be Added ldap attribute mapping table 2013-04-22 12:31:18 -04:00
Jean Raby f049e2430a Added ldap attribute mapping table 2013-04-22 12:25:22 -04:00
Jean Raby a53c66e8a4 Install openchange_user_cleanup in usr/sbin/
Instead of usr/share/doc/sogo/
2013-04-18 14:35:56 -04:00
Jean Raby 4fb3492ea8 openchange_cleanup.py -> openchange_user_cleanup 2013-04-18 14:28:55 -04:00
Jean Raby 353f40ac3e try to cleanup under INBOX too (altnamespace = no) 2013-04-18 14:15:35 -04:00
Jean Raby 96c831f726 Use separator sent by the imap server, not '/' 2013-04-18 14:11:36 -04:00
Jean Raby 59b3219f2d Merge to 2.05a 2013-04-16 15:20:19 -04:00
Jean Raby d7fdfc6cb2 Update NEWS + bump version 2013-04-16 15:16:54 -04:00
Jean Raby d02f58b3cd Update ChangeLog 2013-04-16 15:12:29 -04:00
Ludovic Marcotte 62fee93d86 Fix for bug #2287 2013-04-16 14:33:57 -04:00
Jean Raby 139c14d9e1 save: memCtx
Same fix as for MAPIStoreContactMessage
2013-04-16 12:06:17 -04:00
Francis Lachapelle 8ee15c6f77 Update Installation Guide
Improved the description of the parameters IMAPHostFieldName and
SieveHostFieldName.
2013-04-16 08:34:10 -04:00
Jean Raby 5d17414018 [MAPIStoreContactsMessage save] needs memCtx
From extrafu
2013-04-15 14:13:07 -04:00
Francis Lachapelle 3cd91846a6 Fix CSS color refresh of calendars 2013-04-11 16:32:17 -04:00
Francis Lachapelle e9eb8bdc86 Merge to 2.0.5 2013-04-11 12:56:34 -04:00
Francis Lachapelle 3739cb1536 Update ChangeLog 2013-04-11 12:55:11 -04:00
Francis Lachapelle 30f10ee8f0 Update translations 2013-04-11 11:30:23 -04:00
Jean Raby dfb8788270 don't build SAML support on debian yet 2013-04-11 10:37:34 -04:00
Jean Raby 3810833e1b remove unrtf leftovers 2013-04-11 10:22:28 -04:00
Francis Lachapelle 29e05c7c81 Bump version to 2.0.5 2013-04-11 10:20:10 -04:00
Jean Raby 0a08285fac Add note regarding precedence of .GNUstepDefaults 2013-04-11 10:09:02 -04:00
Jean Raby 01f20a42ad packaging fixups 2013-04-11 09:18:43 -04:00
Francis Lachapelle 3a61a2566b Updated installation guide: version 2.0.5 2013-04-10 18:24:03 -04:00
Jean Raby d2dda86529 ... dir fixup again 2013-04-10 16:30:16 -04:00
Jean Raby cc125d2192 directory fixup 2013-04-10 16:27:03 -04:00
Jean Raby 4da1e41d93 deb: install a sample sogo.conf in /etc/sogo
While there, replace mkdir + cp combo with 'install'
2013-04-10 16:20:47 -04:00
Jean Raby e24eb10c4f rpm: install a sample sogo.conf in /etc/sogo 2013-04-10 16:20:16 -04:00
Jean Raby dd9e51fd16 sogo.conf - new example configuration file 2013-04-10 16:16:30 -04:00
Jean Raby 9932d1413b update NEWS 2013-04-10 12:29:48 -04:00
Jean Raby ff13c49540 updated NEWS 2013-04-10 12:16:26 -04:00
Jean Raby 1e33b4bf26 Add notes regarding UIDField: value must be unique 2013-04-10 12:05:44 -04:00
Francis Lachapelle e23a7df125 Update NEWS file 2013-04-10 11:33:41 -04:00
Ludovic Marcotte 4ca476db9e Updated NEWS file 2013-04-10 11:30:40 -04:00
Ludovic Marcotte 33840c71cd Changed noop by unselect/select. 2013-04-10 10:48:25 -04:00
Ludovic Marcotte 1b983ef691 Fixed a potential timing issue with Dovecot when getting the modseq 2013-04-10 09:56:23 -04:00
Ludovic Marcotte eec8c07d4f Avoid appending the domain if already present. 2013-04-09 11:35:53 -04:00
Ludovic Marcotte 84ba93fc0a Now set ForceAuthn to false by default 2013-04-08 13:58:55 -04:00
Francis Lachapelle 37a6f82659 Initial Arabic translation 2013-04-08 11:05:45 -04:00
Ludovic Marcotte b4aaa68d85 Also consider the "mail" attribute in order to get the user's login 2013-04-05 10:26:17 -04:00
Ludovic Marcotte 5487f34b9e Disable hint verification for now. 2013-04-05 08:57:47 -04:00
Jean Raby e07734fa5f Filter sql source entries based on the user domain
When using dynamic domains with SQL sources (DomainFieldName),
let WebUI and dav lookups return entries from current domain
and other domains visible from the originating domain.

Fixes #2269

SQLSource.m: _visibleDomainsQualifierFromDomain:
  returns a EOQualifier OR'ing all visible domains from specified domain
  (including specified domain)

SQLSource.m: allEntryIDsVisibleFromDomain
  Replacement for allEntryIDs.
  Instead of returning all entries from the sql source,
  only return the entries visible from the specified domain.

SoObjects/SOGo/SQLSource.m: allEntryIDs
  Changed to call allEntryIDsVisibleFromDomain with an empty domain.

SQLSource.m fetchContactsMatching:inDomain:
  Use _visibleDomainsQualifierFromDomain to filter entries

LDAPSource.m: allEntryIDsVisibleFromDomain
  Simply call allEntryIDs, discarding the domain.
  LDAP does need to do the extra domain filtering

SOGoContactSourceFolder.m: toOneRelationshipKeys
   Call new method: allEntryIDsVisibleFromDomain
2013-03-29 10:38:52 -04:00
Ludovic Marcotte 6a8e6cd762 Fixed the GNUmakfile and const's for charset tables. 2013-03-28 08:32:00 -04:00
Ludovic Marcotte 663351029a Replaced unrtf by our own RTF to HTML converter.
Faster, thread safe, a hell lot cleaner.
2013-03-26 19:32:08 -04:00
Jean Raby c26e5fa7fe semi-colon 2013-03-26 14:01:04 -04:00
Jean Raby 74c01dc448 gen-charset-table.py: script to import ms charmaps
For example: http://msdn.microsoft.com/en-us/goglobal/cc305147
2013-03-26 13:42:22 -04:00
Ludovic Marcotte a009c71034 Fixed table initialization. 2013-03-25 15:58:36 -04:00
Jean Raby b4ebc90dd0 replace subprocess.check_output with Popen magic
check_output isn't available in py 2.6...
2013-03-25 14:12:12 -04:00
Jean Raby 95dc134ca6 Revamped openchange_cleanup.py
This is now usable again.

  - Don't delete password files in mapistoreCleanup()
  - reworked the ldb cleanup and enabled it
  - sql cleanup should now be able to figure out the db info from the config
    regardless of the format used (xml, plist, sogo.conf or GNUstepDefaults)
    (We really need a python plist parser.. the current solution is not elegant)
  - Inform user of missing python packages
2013-03-22 15:13:39 -04:00
Jean Raby 9c4b7d8481 Add notes regarding html mails and mod_reqtimeout 2013-03-21 15:39:02 -04:00
Jean Raby 9fb9f2cae6 Enable saml2 support on squeeze (temporary fix) 2013-03-20 11:51:37 -04:00
Francis Lachapelle 15f9b7d22e Fix comments in UIxContactFolderActions.* 2013-03-15 11:23:27 -04:00
Francis Lachapelle 5f179ed6b0 Activate the menu option "Mark Folder Read"
Fixes #1473
2013-03-15 11:06:26 -04:00
Ludovic Marcotte 93f9a7273e Now handle mem context when saving messages and removed useless debugging. 2013-03-13 15:04:11 -04:00
Jean Raby 15e082896c Update sogo-tool expire-autoreply syntax in cron 2013-03-12 09:08:19 -04:00
Jean Raby 63ff9751d7 Add ics_compare and use it in _testRespondTo()
This new class uses vobject.ics_diff() to compare 2 VCALENDAR components.
We should use this instead of textually comparing events for equality
in future tests.
2013-03-11 11:37:59 -04:00
Francis Lachapelle d12c651d59 New system default SOGoEncryptionKey
To be used to encrypt the passwords of remote Web calendars when
SOGoTrustProxyAuthentication is enabled.
2013-03-11 09:34:36 -04:00
Jean Raby 41a6c02aa3 Rework web services section
State that HTTPS is mandatory for autodiscovery services.
Add example named config for SRV record.
2013-03-08 16:20:27 -05:00
Jean Raby a026e75c0e Removed note about linefeed in password files
This is handled by the code now
2013-03-08 15:57:10 -05:00
Ludovic Marcotte 46815042c9 Fixed bug when modifying/deleting exceptions of recurring events. 2013-03-07 09:29:56 -05:00
Jean Raby c79af52b67 Fix BSONCodec.m includes
include objc.h instead of runtime.h so that it works on older gcc objc runtime
2013-03-06 11:03:19 -05:00
Jean Raby e882dedac9 Update News 2013-03-05 11:01:51 -05:00
Jean Raby 13277bbdb9 c_content TEXT to LONGTEXT for OpenChange tables
Add an script to update existing tables.
Note that if a row already have 65535 char in it,
the data is most likely broken.
2013-03-05 10:47:09 -05:00
Francis Lachapelle 7e8a83aefb Fix Slovak templates for mail reply/forward 2013-03-05 10:22:20 -05:00
Jean Raby f1846191d5 Use an autorelease pool in member expansion
Otherwise, we would hold one ldap connection for each member of a group.
And close them all later. With large groups, we could hit the open file limit
(or the open file limit of the ldap server).

Fixes #2256
2013-03-01 16:24:16 -05:00
Jean Raby a7c3f33447 Whitespace 2013-03-01 01:26:15 -05:00
Ludovic Marcotte a8d67edb44 Merge branch 'master' of https://github.com/inverse-inc/sogo 2013-02-20 12:11:17 -05:00
Ludovic Marcotte 89766b2e7e Temporary fix for unsigned long long values. 2013-02-20 12:10:34 -05:00
Jean Raby 7d65d808f6 Strip newline characters from user password files
Makes it easier to create those files with a regular editor.
2013-02-20 10:50:58 -05:00
Ludovic Marcotte fa5e99d58d Much better fix over previous commit. 2013-02-19 15:54:52 -05:00
Ludovic Marcotte 67c2d508ea Added rationale around previous commit. 2013-02-19 15:42:05 -05:00
Ludovic Marcotte 19923d10db Also handle date-strings as date objects.
Dates are stored as string in BSON - might change in the future.
2013-02-19 15:30:29 -05:00
Ludovic Marcotte e57b6835e6 Fix for objective-c runtimes. 2013-02-18 16:50:54 -05:00
Ludovic Marcotte bcab7e7dc9 C99 style fixes. 2013-02-18 16:42:59 -05:00
Ludovic Marcotte 2572eedd89 Added BSON encoder/decoder for Outlook cache files. 2013-02-18 16:28:06 -05:00
Francis Lachapelle efb45bfba6 Fix issue with exceptions in repeating events
Fixed the display of an exception when its recurrence id is outside the
current view.
2013-02-15 15:17:08 -05:00
Ludovic Marcotte 4f38b5cf3f Alse use hex-formatted keys for deleted mails. 2013-02-14 15:59:19 -05:00
Ludovic Marcotte 71b9772546 Ensure we hit the cache with hex-formatted keys. 2013-02-14 15:22:48 -05:00
Francis Lachapelle c13c389ae5 Update Danish translation 2013-02-12 08:42:47 -05:00
Jean Raby caf6f0ec6c Add example apache configuration for apple AB 2013-02-11 10:41:50 -05:00
Jean Raby 4952ff7914 Use SOGoSystemDefaults in all tools
sogo-ealarms-notify and sogo-slapd-sockd will now be able to use sogo.conf
Fixes #2226
2013-02-08 16:22:14 -05:00
Francis Lachapelle 8981dcd645 Fix segfault in SOGoSieveManager.m 2013-02-08 09:42:31 -05:00
Jean Raby 470a53a548 Add example configuration for fail2ban
From Arnd Brandes. (#2229)
2013-02-07 13:00:27 -05:00
Francis Lachapelle 7b65b7400e Update Finnish translation 2013-02-07 09:00:16 -05:00
Francis Lachapelle 90c61abdb6 Update Polish translation 2013-02-06 15:16:09 -05:00
Jean Raby f8387b90ff Log x-webobjects-remote-host in login process
Most of the time, the remote-host will contain data from the x-forwarded-for header.
Which could have more than one ip in it if the request went through multiple proxies.
eg. x-forwarded-for: real.client.ip, load.balancer.ip
2013-02-06 09:23:47 -05:00
Francis Lachapelle feb02c54b9 Add missing localizable string 2013-02-05 16:13:18 -05:00
Ludovic Marcotte 49a2299414 Avoid going out of bounds for special URL chars ending mail contents. 2013-02-05 16:11:37 -05:00
Jean Raby 43044bf88f Plug sieve connection leak
Fixes #2228
Fix from 'bofhus'
2013-02-05 15:09:55 -05:00
Jean Raby 0532d331a3 whitespace (tabkill) 2013-02-05 15:09:20 -05:00
Jean Raby 70fc05091f Remove x-webobjects-remote-host from apache conf
SOPE now handles this on its own by setting x-webobjects-remote-host
to the content of the x-forward or x-forwarded-for headers if it wasn't defined
2013-02-05 14:27:16 -05:00
Jean Raby 469e5c647e Updated NEWS 2013-02-05 11:52:26 -05:00
Jean Raby 4bfb43a4ad Merge 'tests/authcache' - don't use cache on login 2013-02-05 11:40:47 -05:00
Francis Lachapelle 5e0c7ae4f2 Merge to 2.0.4b 2013-02-04 14:24:46 -05:00
Francis Lachapelle 3daa7e55b7 Update ChangeLog 2013-02-04 14:24:03 -05:00
Francis Lachapelle 6913502810 Bump version to 2.0.4b 2013-02-04 14:22:37 -05:00
Jean Raby 24971070f6 Updated NEWS 2013-02-04 14:03:28 -05:00
Jean Raby 3d90e3a539 Bump userkey length from 64 to 160 bytes
Allows for much longer username@domain:password strings.
Fixes #2212

To bump it further, the database schema will have to be updated
to allow a longer c_value (currently 255 chars)
2013-02-04 13:55:53 -05:00
Francis Lachapelle b5fdaa78cd Add missing strings to mail module
The two columns names of the contacts pane were missing. They have
been copied from the contact module.
2013-02-04 08:58:37 -05:00
Francis Lachapelle f94adb5473 Update NEWS file 2013-02-03 20:42:20 -05:00
Francis Lachapelle e34ba5689c Fix saving prefs with disabled mail module 2013-02-03 20:40:06 -05:00
Jean Raby 7b5da8a2c9 don't use cache for login page 2013-02-01 19:58:25 -05:00
Jean Raby 451c82c815 Don't use user/password cache from the login page
The idea is to always use memcached for credentials to avoid hitting
the authentication backend on every click but to check with the auth backend
for every login requests.

This should fix #2169

While there, fix whitespace (killtab)
2013-02-01 18:35:10 -05:00
Jean Raby 488a76c5e3 Merge branch 'test/userdefaults' 2013-02-01 16:31:56 -05:00
Jean Raby a4bd966cc0 Revisit option handling
Really fix #2166
The previous fix (46b53b3) was wrong since SOPE was able to override
the 'final' config with its defaults.

This now uses a new approach using a volatile domain and a reordering
of the search list :
  *   NSArgumentDomain (command line arguments)
  *   sogodRuntimeDomain (config from all config files)
  *   GSPrimaryDomain
  *   NSGlobalDomain
  *   GSConfigDomain
  *   (languages)
  *   NSRegistrationDomain (SOPE loads its defaults in this one)
2013-02-01 16:26:01 -05:00
Francis Lachapelle ecc36c9025 Fix classification menu in component editor 2013-02-01 14:47:37 -05:00
Francis Lachapelle 716daf027d Fix link to ACL editor for any authenticated user 2013-02-01 14:46:05 -05:00
Jean Raby 0b7c32510b news file update for 2.0.4b 2013-02-01 10:40:59 -05:00
jraby 547dfa0d90 Merge pull request #9 from inverse-inc/fix/2066_options-precedence
Fix/2066 options precedence
2013-01-31 18:42:09 -08:00
Jean Raby 225a28258f Read credential files using dataWithContentsOfFile
Again, to cope with older gnusteps which don't have
stringWithContentsOfFile:encoding:error:
2013-01-31 16:44:14 -05:00
Jean Raby e01b190e57 Fixup handling NSArgumentDomain arguments
would fix #2216
2013-01-31 15:42:48 -05:00
Francis Lachapelle cd7d410262 Fix tooltips in contacts list 2013-01-31 13:55:57 -05:00
Francis Lachapelle 4bcf90c693 Fix "Send Anyway" string wrt localizable strings 2013-01-31 09:44:29 -05:00
Francis Lachapelle 0408415c61 Remove control characters before returning JSON 2013-01-30 15:47:20 -05:00
Francis Lachapelle c1c0c1ab44 Merge to 2.0.4a 2013-01-30 08:54:00 -05:00
Francis Lachapelle 3ea94940c2 Update ChangeLog 2013-01-30 08:52:32 -05:00
Francis Lachapelle 321675ba99 Bump version to 2.0.4a 2013-01-30 08:51:10 -05:00
Francis Lachapelle 9eb1418e36 Update French translation 2013-01-30 08:49:16 -05:00
Francis Lachapelle d8804c699d Format birthday on contact card 2013-01-30 08:43:02 -05:00
Francis Lachapelle 4e9db74e29 Update NEWS file 2013-01-29 15:04:57 -05:00
Francis Lachapelle 7150ebde6b Update updates.php 2013-01-29 15:03:37 -05:00
Francis Lachapelle 6fbd975e00 Update NEWS file 2013-01-29 15:02:51 -05:00
Francis Lachapelle e0a1a47953 Code cleanup in UIxAppointmentEditor.m 2013-01-29 14:53:57 -05:00
Francis Lachapelle da757a19c6 Fix handling of decoding contacts UID
A problem occurs when the contact UID contains a special character that
was HTML encoded (ex: space, &, ").
2013-01-28 22:05:54 -05:00
Jean Raby ea13fd14c9 Use older NSPropertyListSerialization methods
dataWithPropertyList and propertyListWithData didn't exist in gnustep 1.20
which is shipped with debian-squeeze.
2013-01-29 10:31:16 -05:00
Francis Lachapelle 902a5d8f70 Fix saving all-day event in appointment editor 2013-01-28 18:43:45 -05:00
Francis Lachapelle be0090be06 Fix until date in component editor 2013-01-28 16:44:14 -05:00
Francis Lachapelle 2d455bf0ca Fix possible infinite loop in repeataable object 2013-01-28 09:51:42 -05:00
Francis Lachapelle 1d8e72646c Update Czech translation 2013-01-28 08:43:58 -05:00
Ludovic Marcotte c066136a06 Reverted code that was causing issues with groups (#2090) 2013-01-28 08:34:40 -05:00
Jean Raby 46b53b31fd Fix order of precedence for options
Fixes #2066 and #2166
Enforce the following order of precedence for options, first match wins:
  1. Command line arguments
  2. .GNUstepDefaults
  3. /etc/sogo/{debconf,sogo}.conf
  4. SOGoDefaults.plist
2013-01-24 22:43:38 -05:00
Jean Raby 6093c4dd2e Axe handling of sogo 0.9 gnustep domain migration 2013-01-24 20:37:30 -05:00
Jean Raby 61ded01171 whitespace - tabkill 2013-01-24 20:35:03 -05:00
505 changed files with 16144 additions and 17146 deletions

No files matched your search

+2
View File
@@ -9,3 +9,5 @@ tags
*.swp
SoObjects/SOGo/SOGo.framework/
SoObjects/SOGo/derived_src/
Tests/*/config.py
*.pyc
+11 -1
View File
@@ -1,9 +1,10 @@
[main]
host = https://www.transifex.net
host = https://www.transifex.com
[sogo.ui-mailerui]
source_file = UI/MailerUI/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/MailerUI/Arabic.lproj/Localizable.strings
trans.ca = UI/MailerUI/Catalan.lproj/Localizable.strings
trans.cs = UI/MailerUI/Czech.lproj/Localizable.strings
trans.cy = UI/MailerUI/Welsh.lproj/Localizable.strings
@@ -29,6 +30,7 @@ trans.uk = UI/MailerUI/Ukrainian.lproj/Localizable.strings
[sogo.ui-preferencesui]
source_file = UI/PreferencesUI/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/PreferencesUI/Arabic.lproj/Localizable.strings
trans.ca = UI/PreferencesUI/Catalan.lproj/Localizable.strings
trans.cs = UI/PreferencesUI/Czech.lproj/Localizable.strings
trans.cy = UI/PreferencesUI/Welsh.lproj/Localizable.strings
@@ -54,6 +56,7 @@ trans.uk = UI/PreferencesUI/Ukrainian.lproj/Localizable.strings
[sogo.ui-scheduler]
source_file = UI/Scheduler/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/Scheduler/Arabic.lproj/Localizable.strings
trans.ca = UI/Scheduler/Catalan.lproj/Localizable.strings
trans.cs = UI/Scheduler/Czech.lproj/Localizable.strings
trans.cy = UI/Scheduler/Welsh.lproj/Localizable.strings
@@ -79,6 +82,7 @@ trans.uk = UI/Scheduler/Ukrainian.lproj/Localizable.strings
[sogo.ui-contacts]
source_file = UI/Contacts/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/Contacts/Arabic.lproj/Localizable.strings
trans.ca = UI/Contacts/Catalan.lproj/Localizable.strings
trans.cs = UI/Contacts/Czech.lproj/Localizable.strings
trans.cy = UI/Contacts/Welsh.lproj/Localizable.strings
@@ -104,6 +108,7 @@ trans.uk = UI/Contacts/Ukrainian.lproj/Localizable.strings
[sogo.ui-mainui]
source_file = UI/MainUI/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/MainUI/Arabic.lproj/Localizable.strings
trans.ca = UI/MainUI/Catalan.lproj/Localizable.strings
trans.cs = UI/MainUI/Czech.lproj/Localizable.strings
trans.cy = UI/MainUI/Welsh.lproj/Localizable.strings
@@ -129,6 +134,7 @@ trans.uk = UI/MainUI/Ukrainian.lproj/Localizable.strings
[sogo.ui-common]
source_file = UI/Common/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/Common/Arabic.lproj/Localizable.strings
trans.ca = UI/Common/Catalan.lproj/Localizable.strings
trans.cs = UI/Common/Czech.lproj/Localizable.strings
trans.cy = UI/Common/Welsh.lproj/Localizable.strings
@@ -154,6 +160,7 @@ trans.uk = UI/Common/Ukrainian.lproj/Localizable.strings
[sogo.ui-administrationui]
source_file = UI/AdministrationUI/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/AdministrationUI/Arabic.lproj/Localizable.strings
trans.ca = UI/AdministrationUI/Catalan.lproj/Localizable.strings
trans.cs = UI/AdministrationUI/Czech.lproj/Localizable.strings
trans.cy = UI/AdministrationUI/Welsh.lproj/Localizable.strings
@@ -179,6 +186,7 @@ trans.uk = UI/AdministrationUI/Ukrainian.lproj/Localizable.strings
[sogo.soobjects-appointments]
source_file = SoObjects/Appointments/English.lproj/Localizable.strings
source_lang = en
trans.ar = SoObjects/Appointments/Arabic.lproj/Localizable.strings
trans.ca = SoObjects/Appointments/Catalan.lproj/Localizable.strings
trans.cs = SoObjects/Appointments/Czech.lproj/Localizable.strings
trans.cy = SoObjects/Appointments/Welsh.lproj/Localizable.strings
@@ -204,6 +212,7 @@ trans.uk = SoObjects/Appointments/Ukrainian.lproj/Localizable.strings
[sogo.soobjects-contacts]
source_file = SoObjects/Contacts/English.lproj/Localizable.strings
source_lang = en
trans.ar = SoObjects/Contacts/Arabic.lproj/Localizable.strings
trans.ca = SoObjects/Contacts/Catalan.lproj/Localizable.strings
trans.cs = SoObjects/Contacts/Czech.lproj/Localizable.strings
trans.cy = SoObjects/Contacts/Welsh.lproj/Localizable.strings
@@ -229,6 +238,7 @@ trans.uk = SoObjects/Contacts/Ukrainian.lproj/Localizable.strings
[sogo.ui-mailpartviewers]
source_file = UI/MailPartViewers/English.lproj/Localizable.strings
source_lang = en
trans.ar = UI/MailPartViewers/Arabic.lproj/Localizable.strings
trans.ca = UI/MailPartViewers/Catalan.lproj/Localizable.strings
trans.cs = UI/MailPartViewers/Czech.lproj/Localizable.strings
trans.cy = UI/MailPartViewers/Welsh.lproj/Localizable.strings
+74
View File
@@ -0,0 +1,74 @@
#
#
# Keep only one of those vhost definition, comment out the other one
#
#
# for https
# don't forget to add a Listen parameter for port 8843:
# Listen 8843
<VirtualHost *:8843>
ServerName YOUR.SERVER.NAME
SSLEngine on
SSLProtocol -ALL +SSLv3 +TLSv1
SSLHonorCipherOrder On
SSLCipherSuite HIGH:MEDIUM:!ADH:!aNULL:!eNULL:!NULL
SSLCertificateFile /path/to/your/cert/cert.pem
SSLCertificateChainFile /path/to/your/cert/cert-chain-file.pem
SSLCertificateKeyFile /path/to/your/key/file.key
RewriteEngine Off
ProxyRequests Off
SetEnv proxy-nokeepalive 1
ProxyPreserveHost On
ProxyPassInterpolateEnv On
ProxyPass /principals http://127.0.0.1:20000/SOGo/dav/ interpolate
ProxyPass /SOGo http://127.0.0.1:20000/SOGo interpolate
ProxyPass / http://127.0.0.1:20000/SOGo/dav/ interpolate
<Location />
Order allow,deny
Allow from all
</Location>
<Proxy http://127.0.0.1:20000>
RequestHeader set "x-webobjects-server-port" "8843"
RequestHeader set "x-webobjects-server-name" "CHANGETHIS:8843"
RequestHeader set "x-webobjects-server-url" "http://CHANGETHIS:8843"
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
AddDefaultCharset UTF-8
</Proxy>
ErrorLog /var/log/apache2/ab-error.log
CustomLog /var/log/apache2/ab-access.log combined
</VirtualHost>
# plain http
# Same here, don't forget to add a Listen parameter for port 8800:
# Listen 8800
<VirtualHost *:8800>
RewriteEngine Off
ProxyRequests Off
SetEnv proxy-nokeepalive 1
ProxyPreserveHost On
ProxyPassInterpolateEnv On
ProxyPass /principals http://127.0.0.1:20000/SOGo/dav/ interpolate
ProxyPass /SOGo http://127.0.0.1:20000/SOGo interpolate
ProxyPass / http://127.0.0.1:20000/SOGo/dav/ interpolate
<Location />
Order allow,deny
Allow from all
</Location>
<Proxy http://127.0.0.1:20000>
RequestHeader set "x-webobjects-server-port" "8800"
RequestHeader set "x-webobjects-server-name" "changethis:8800"
RequestHeader set "x-webobjects-server-url" "http://changethis:8800"
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
AddDefaultCharset UTF-8
</Proxy>
ErrorLog /var/log/apache2/ab-error.log
CustomLog /var/log/apache2/ab-access.log combined
</VirtualHost>
+6 -6
View File
@@ -59,7 +59,6 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
# RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e"
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
RequestHeader set "x-webobjects-remote-host" %{REMOTE_HOST}e env=REMOTE_HOST
AddDefaultCharset UTF-8
@@ -67,8 +66,9 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
Allow from all
</Proxy>
## We use mod_rewrite to pass remote address to the SOGo proxy.
# The remote address will appear in SOGo's log files and in the X-Forward
# header of emails.
RewriteEngine On
RewriteRule ^/SOGo/(.*)$ /SOGo/$1 [env=REMOTE_HOST:%{REMOTE_ADDR},PT]
# For apple autoconfiguration
<IfModule rewrite_module>
RewriteEngine On
RewriteRule ^/.well-known/caldav/?$ /SOGo/dav [R=301]
</IfModule>
+3456
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
Binary file not shown.
+205 -1
View File
@@ -1,4 +1,207 @@
2.0.4 (2013-01-DD)
2.1.1a (2013-11-22)
-------------------
Bug fixes
- fixed Sieve filters editor (#2504)
- moved missing translation to UI/Common (#2499)
- fixed potential crasher in OpenChange
2.1.1 (2013-11-19)
------------------
New features
- creation and modification of mail labels
Enhancements
- the color picker is no longer a popup window
Bug fixes
- fixed utf8 character handling in special folder names
Special folder names can now be set as UTF8 or modified UTF7 in sogo.conf
- fixed reply-to header not being set for auxiliary IMAP accounts
- fixed handling of broken/invalid email addresses
2.1.0 (2013-11-07)
------------------
Enhancements
- improved order of user rights in calendar module (#1431)
- increased height of alarm editor when email alarms are enabled
- added SMTP AUTH support for sogo-ealarms-notify
- added support for LDAP password change against AD/Samba4
- added Apache configuration for Apple autoconfiguration (#2248)
- the init scripts now start 3 sogod processes by default instead of 1
- SOGo now also sends a plain/text parts when sending HTML mails (#2217)
- SOGo now listens on 127.0.0.1:20000 by default (instead of *:20000)
- SOGo new uses the latest WebDAV sync response type (#1275)
- updated CKEditor to version 4.2.2 and added the tables-related modules (#2410)
- improved display of vEvents in messages
Bug fixes
- fixed handling of an incomplete attachment filename (#2385)
- fixed Finnish mail reply/forward templates (#2401)
- fixed position of red line of current time (#2373)
- fixed crontab error (#2372)
- avoid using too many LDAP connections while looping through LDAP results
- don't encode HTML entities in mail subject of notification (#2402)
- fixed crash of Samba when sending an invitation (#2398)
- fixed selection of destination calendar when saving a task or an event (#2353)
- fixed "display remote images" preference for message in a popup (#2417)
- avoid crash when handling malformed or non-ASCII HTTP credentials (#2358)
- fixed crash in DAV free-busy lookups when using SQL addressbooks (#2418)
- disabled verbose logging of SMTP sessions by default
- fixed high CPU usage when there are no available child processes and added logging when such a condition occurs
- fixed memory consumption issues when doing dav lookups with huge result set
- fixed S/MIME verification issues with certain OpenSSL versions
- worked around an issue with chunked encoding of CAS replies (#2408)
- fixed OpenChange corruption issue regarding predecessors change list (#2405)
- avoid unnecessary UTF-7 conversions (#2318)
- improved RTF parser to fix vCards (#2354)
- fixed definition of the COMPLETED attribute of vTODO (#2240)
- fixed DAV:resource-id property when sharing calendars (#2399)
- fixed reload of multiple external web calendars (#2221)
- fixed display of PDF files sent from Thunderbird (#2270)
- fixed TLS support for IMAP (#2386)
- fixed creation of web calendar when added using sogo-tool (#2007)
- avoid crash when parsing HTML tags of a message (#2434)
- fixed handling of LDAP groups with no email address (#1328)
- fixed encoding of messages with non-ASCII characters (#2459)
- fixed compilation with clang 3.2 (#2235)
- truncated long fields of quick records to avoid an SQL error (#2461)
- fixed IMAP ACLs (#2433)
- removed inline JavaScript when viewing HTML messages (#2468)
2.0.7 (2013-07-19)
------------------
New features
- print gridlines of calendar in 15-minute intervals
- allow the events/tasks lists to be collapsable
Enhancements
- bubble box of events no longer overlaps the current event
- now pass the x-originating-ip using the IMAP ID extension (#2366)
- updated BrazilianPortuguese, Czech, Dutch, German, Polish and Russian translations
Bug fixes
- properly handle RFC2231 everywhere
- fixed minor XSS issues
- fixed jquery-ui not bluring the active element when clicking on a draggable
2.0.6b (2013-06-27)
------------------
Bug fixes
- properly escape the foldername to avoid XSS issues
- fixed loading of MSExchangeFreeBusySOAPResponseMap
2.0.6a (2013-06-25)
------------------
Bug fixes
- documentation fixes
- added missing file for CAS single logout
2.0.6 (2013-06-21)
------------------
Enhancements
- updated CKEditor to version 4.1.1 (#2333)
- new failed login attemps rate-limiting options. See the new
SOGoMaximumFailedLoginCount, SOGoMaximumFailedLoginInterval and
SOGoFailedLoginBlockInterval defaults
- new message submissions rate-limiting options. See the new
SOGoMaximumMessageSubmissionCount, SOGoMaximumRecipientCount,
SOGoMaximumSubmissionInterval and SOGoMessageSubmissionBlockInterval defaults
- now possible to send or not event notifications on a per-event basis
- now possible to see who created an event/task in a delegated calendar
- multi-domain support in OpenChange (implemented using a trick)
Bug fixes
- fixed decoding of the charset parameter when using single quotes (#2306)
- fixed potential crash when sending MDN from Sent folder (#2209)
- fixed handling of unicode separators (#2309)
- fixed public access when SOGoTrustProxyAuthentication is used (#2237)
- fixed access right issues with import feature (#2294)
- fixed IMAP ACL issue when SOGoForceExternalLoginWithEmail is used (#2313)
- fixed handling of CAS logoutRequest (#2346)
- fixed many major OpenChange stability issues
2.0.5a (2013-04-17)
------------------
Bug fixes
- fixed an issue when parsing user CN with leading or trailing spaces (#2287)
- fixed a crash that occured when saving contacts or tasks via Outlook
2.0.5 (2013-04-11)
------------------
New features
- new system default SOGoEncryptionKey to be used to encrypt the passwords of
remote Web calendars when SOGoTrustProxyAuthentication is enabled
- activated the menu option "Mark Folder Read" in the Webmail (#1473)
Enhancements
- added logging of the X-Forwarded-For HTTP header (#2229)
- now use BSON instead of GNUstep's binary format for serializing
Outlook related cache files
- updated Danish, Finnish, Polish and Slovak translations
- added Arabic translation - thanks to Anass Ahmed
Bug fixes
- don't use the cache for password lookups from login page (#2169)
- fixed issue with exceptions in repeating events
- avoid data truncation issue in OpenChange with mysql backend
run sql-update-2.0.4b_to_2.0.5-mysql.sh to update existing tables
- avoid random crashes in OpenChange due to RTF conversion
- fixed issue when modifying/deleting exceptions of recurring events
- fixed major cache miss issue leading to slow Outlook resynchronizations
- fixed major memory corruption issue when Outlook was saving "messages"
- fixed filtering of sql contact entries when using dynamic domains (#2269)
- sogo.conf can now be used by all tools (#2226)
- SOPE: fixed handling of sieve capabilities after starttls (#2132)
- OpenChange: fixed 'stuck email' problem when sending a mail
- OpenChange NTLMAuthHandler: avoid tightloop when samba isn't available.
- OpenChange NTLMAuthHandler: avoid crash while parsing cookies
- OpenChange ocsmanager: a LOT of fixes, see git log
2.0.4b (2013-02-04)
------------------
Bug fixes
- Fixed order of precedence for options (#2166)
The following order is enforced - first match wins
1. Command line arguments
2. .GNUstepDefaults
3. /etc/sogo/{debconf,sogo}.conf
4. SOGoDefaults.plist
- fixed handling of LDAP DN containing special characters (#2152, #2207)
- fixed handling of credential files for older GNUsteps (#2216)
- fixed display of messages with control characters (#2079, #2177)
- fixed tooltips in contacts list (#2211)
- fixed classification menu in component editor (#2223)
- fixed link to ACL editor for 'any authenticated user' (#2222, #2224)
- fixed saving preferences when mail module is disabled
- fixed handling for long credential strings (#2212)
2.0.4a (2013-01-30)
------------------
Enhancements
- updated Czech translation
- birthday is now properly formatted in addressbook module
Bug fixes
- fixed handling of groups with spaces in their UID
- fixed possible infinite loop in repeatable object
- fixed until date in component editor
- fixed saving all-day event in appointment editor
- fixed handling of decoding contacts UID
- fixed support of GNUstep 1.20 / Debian Squeeze
2.0.4 (2013-01-25)
------------------
New features
@@ -18,6 +221,7 @@ Enhancements
- updated translations
- recurrence-id of all-day events is now set as a proper date with no time
- 'show completed tasks' is now persistent
- fixed memory usage consumption for remote ICS subscriptions
Bug fixes
- fixed usage of browser's language for the login page
+50
View File
@@ -0,0 +1,50 @@
//
// BSONCodec.h
// BSON Codec for Objective-C.
//
// Created by Martin Kou on 8/17/10.
// MIT License, see LICENSE file for details.
//
#import <Foundation/Foundation.h>
#import <stdint.h>
@protocol BSONCoding
- (uint8_t) BSONTypeID;
- (NSData *) BSONEncode;
- (NSData *) BSONRepresentation;
+ (id) BSONFragment: (NSData *) data at: (const void **) base ofType: (uint8_t) typeID;
@end
@protocol BSONObjectCoding
- (id) initWithBSONDictionary: (NSDictionary *) data;
- (NSDictionary *) BSONDictionary;
@end
@interface NSObject (BSONObjectCoding)
- (NSData *) BSONEncode;
- (NSData *) BSONRepresentation;
@end
@interface NSDictionary (BSON) <BSONCoding>
@end
@interface NSData (BSON) <BSONCoding>
- (NSDictionary *) BSONValue;
@end
@interface NSNumber (BSON) <BSONCoding>
@end
@interface NSString (BSON) <BSONCoding>
@end
@interface NSArray (BSON) <BSONCoding>
@end
@interface NSNull (BSON) <BSONCoding>
@end
@interface NSCalendarDate (BSON) <BSONCoding>
@end
+589
View File
@@ -0,0 +1,589 @@
//
// BSONCodec.m
// BSON Codec for Objective-C.
//
// Created by Martin Kou on 8/17/10.
// MIT License, see LICENSE file for details.
//
#import "BSONCodec.h"
#import <ctype.h>
#import <string.h>
#import <objc/objc.h>
#define BSONTYPE(tag,className) [className class], [NSNumber numberWithChar: (tag)]
#ifndef objc_msgSend
#define objc_msgSend(obj, sel, ...) \
objc_msg_lookup(obj, sel)(obj, sel, ## __VA_ARGS__)
#endif
static NSDictionary *BSONTypes()
{
static NSDictionary *retval = nil;
if (retval == nil)
{
retval = [[NSDictionary dictionaryWithObjectsAndKeys:
BSONTYPE(0x01, NSNumber),
BSONTYPE(0x02, NSString),
BSONTYPE(0x03, NSDictionary),
BSONTYPE(0x04, NSArray),
BSONTYPE(0x05, NSData),
BSONTYPE(0x08, NSNumber),
BSONTYPE(0x0A, NSNull),
BSONTYPE(0x10, NSNumber),
BSONTYPE(0x11, NSCalendarDate),
BSONTYPE(0x12, NSNumber),
nil] retain];
}
return retval;
}
#define SWAP16(x) \
((uint16_t)((((uint16_t)(x) & 0xff00) >> 8) | \
(((uint16_t)(x) & 0x00ff) << 8)))
#define SWAP32(x) \
((uint32_t)((((uint32_t)(x) & 0xff000000) >> 24) | \
(((uint32_t)(x) & 0x00ff0000) >> 8) | \
(((uint32_t)(x) & 0x0000ff00) << 8) | \
(((uint32_t)(x) & 0x000000ff) << 24)))
#define SWAP64(x) \
((uint64_t)((((uint64_t)(x) & 0xff00000000000000ULL) >> 56) | \
(((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \
(((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \
(((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \
(((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \
(((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \
(((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \
(((uint64_t)(x) & 0x00000000000000ffULL) << 56)))
#if BYTE_ORDER == LITTLE_ENDIAN
#define BSONTOHOST16(x) (x)
#define BSONTOHOST32(x) (x)
#define BSONTOHOST64(x) (x)
#define HOSTTOBSON16(x) (x)
#define HOSTTOBSON32(x) (x)
#define HOSTTOBSON64(x) (x)
#elif BYTE_ORDER == BIG_ENDIAN
#define BSONTOHOST16(x) SWAP16(x)
#define BSONTOHOST32(x) SWAP32(x)
#define BSONTOHOST64(x) SWAP64(x)
#define HOSTTOBSON16(x) SWAP16(x)
#define HOSTTOBSON32(x) SWAP16(x)
#define HOSTTOBSON64(x) SWAP16(x)
#endif
#define CLASS_NAME_MARKER @"$$__CLASS_NAME__$$"
@implementation NSObject (BSONObjectCoding)
- (NSData *) BSONEncode
{
if (![self conformsToProtocol: @protocol(BSONObjectCoding)])
[NSException raise: NSInvalidArgumentException format: @"BSON encoding is only valid on objects conforming to the BSONObjectEncoding protocol."];
id <BSONObjectCoding> myself = (id <BSONObjectCoding>) self;
NSMutableDictionary *values = [[myself BSONDictionary] mutableCopy];
#if (defined(__GNU_LIBOBJC__) && (__GNU_LIBOBJC__ >= 20100911)) || defined(APPLE_RUNTIME) || defined(__GNUSTEP_RUNTIME__)
const char* className = class_getName([self class]);
#else
const char* className = [self class]->name;
#endif
[values setObject: [NSData dataWithBytes: (void *)className length: strlen(className)] forKey: CLASS_NAME_MARKER];
NSData *retval = [values BSONEncode];
[values release];
return retval;
}
- (NSData *) BSONRepresentation
{
return [self BSONEncode];
}
@end
@implementation NSDictionary (BSON)
- (uint8_t) BSONTypeID
{
return 0x03;
}
- (NSData *) BSONEncode
{
// Initialize the components structure.
NSMutableArray *components = [[NSMutableArray alloc] init];
NSMutableData *lengthData = [[NSMutableData alloc] initWithLength: 4];
[components addObject: lengthData];
[lengthData release];
NSMutableData *contentsData = [[NSMutableData alloc] init];
[components addObject: contentsData];
[contentsData release];
[components addObject: [NSData dataWithBytes: "\x00" length: 1]];
// Ensure ordered keys. not in BSON spec, but ensures all BSONRepresentations
// of the same dict will be the same.
NSMutableArray *keys = [[NSMutableArray alloc] init];
[keys addObjectsFromArray: [self allKeys]];
//[keys sortUsingSelector: @selector(caseInsensitiveCompare:)];
// Encode data.- (NSData *) BSONEncode;
uint8_t elementType = 0;
int i;
for (i = 0; i < [keys count]; i++)
{
NSString *key = [keys objectAtIndex: i];
NSObject *value = [self objectForKey: key];
if ([value respondsToSelector: @selector(BSONTypeID)])
elementType = [(id <BSONCoding>) value BSONTypeID];
else
elementType = 3;
[contentsData appendBytes: &elementType length: 1];
[contentsData appendData: [key dataUsingEncoding: NSUTF8StringEncoding]];
[contentsData appendBytes: "\x00" length: 1];
[contentsData appendData: [value BSONEncode]];
}
[keys release];
// Write length.
uint32_t *length = (uint32_t *)[lengthData mutableBytes];
*length = HOSTTOBSON32([contentsData length]) + 4 + 1;
// Assemble the output data.
NSMutableData *retval = [NSMutableData data];
for (i = 0; i < [components count]; i++)
[retval appendData: [components objectAtIndex: i]];
[components release];
return retval;
}
- (NSData *) BSONRepresentation
{
return [self BSONEncode];
}
+ (id) BSONFragment: (NSData *) data at: (const void **) base ofType: (uint8_t) t
{
const void *current = [data bytes];
if ((id)base != nil)
current = *base;
else
base = &current;
uint32_t length = BSONTOHOST32(*((uint32_t *)current));
const void *endPoint = current + length;
current += 4;
NSMutableDictionary *retval = [NSMutableDictionary dictionary];
while (current < endPoint - 1)
{
uint8_t typeID = *((uint8_t *)current);
current++;
char *utf8Key = (char *) current;
while (*((char *)current) != 0 && current < endPoint - 1)
current++;
current++;
NSString *key = [NSString stringWithUTF8String: utf8Key];
*base = current;
Class typeClass = [BSONTypes() objectForKey: [NSNumber numberWithChar: typeID]];
id value = objc_msgSend(typeClass, @selector(BSONFragment:at:ofType:), data, base, typeID);
current = *base;
[retval setObject: value forKey: key];
}
*base = current + 1;
// If the dictionary has a class name marker, then it is to be converted to an object.
if ([retval objectForKey: CLASS_NAME_MARKER] != nil)
{
NSData *classNameData = [retval objectForKey: CLASS_NAME_MARKER];
char *className = malloc([classNameData length] + 1);
memcpy(className, [classNameData bytes], [classNameData length]);
className[[classNameData length]] = 0;
Class targetClass = objc_getClass(className);
if (targetClass == nil)
[NSException raise: NSInvalidArgumentException format: @"Class %s found in incoming data is undefined.", className];
id obj = [[targetClass alloc] initWithBSONDictionary: retval];
return obj;
}
return retval;
}
@end
@implementation NSData (BSON)
- (uint8_t) BSONTypeID
{
return 0x05;
}
- (NSData *) BSONEncode
{
uint32_t length = HOSTTOBSON32([self length]);
NSMutableData *retval = [NSMutableData data];
[retval appendBytes: &length length: 4];
[retval appendBytes: "\x00" length: 1];
[retval appendData: self];
return retval;
}
- (NSData *) BSONRepresentation
{
return [self BSONEncode];
}
+ (id) BSONFragment: (NSData *) data at: (const void **) base ofType: (uint8_t) t
{
const void *current = [data bytes];
if ((id)base != nil)
current = *base;
else
base = &current;
uint32_t length = BSONTOHOST32(*((uint32_t *)current));
current += 4 + 1;
NSData *retval = [NSData dataWithBytes: current length: length];
current += length;
*base = current;
return retval;
}
- (NSDictionary *) BSONValue
{
return [NSDictionary BSONFragment: self at: NULL ofType: 0x03];
}
@end
@implementation NSNumber (BSON)
- (uint8_t) BSONTypeID
{
const char encoding = tolower(*([self objCType]));
switch (encoding) {
case 'f':
case 'd': return 0x01;
case 'b': return 0x08;
case 'c':
case 's': return 0x10;
case 'i':
// Ok, if you're running Objective-C on 16-bit platforms...
// Then YOU have issues.
// So, yeah, we won't handle that case.
if (sizeof(int) == 4)
return 0x10;
else if (sizeof(int) == 8)
return 0x12;
case 'l':
if (sizeof(long) == 4)
return 0x10;
else if (sizeof(long) == 8)
return 0x12;
case 'q': return 0x12;
default:
[NSException raise: NSInvalidArgumentException format: @"%@::%s - invalid encoding type '%c'", [self class], _cmd, encoding];
}
return 0;
}
- (NSData *) BSONEncode
{
const char encoding = *([self objCType]);
if (encoding == 'd' || encoding == 'D')
{
double value = [self doubleValue];
return [NSData dataWithBytes: &value length: 8];
}
if (encoding == 'f' || encoding == 'F')
{
double value = [self floatValue];
return [NSData dataWithBytes: &value length: 8];
}
if (encoding == 'b' || encoding == 'B')
{
char value = [self boolValue];
return [NSData dataWithBytes: &value length: 1];
}
if (encoding == 'c' || encoding == 'C')
{
int32_t value = [self charValue];
value = HOSTTOBSON32(value);
return [NSData dataWithBytes: &value length: 4];
}
if (encoding == 's' || encoding == 'S')
{
int32_t value = [self shortValue];
value = HOSTTOBSON32(value);
return [NSData dataWithBytes: &value length: 4];
}
if (encoding == 'i' || encoding == 'I')
{
int value = [self intValue];
if (sizeof(int) == 4)
value = HOSTTOBSON32(value);
else if (sizeof(int) == 8)
value = HOSTTOBSON64(value);
return [NSData dataWithBytes: &value length: sizeof(int)];
}
if (encoding == 'l' || encoding == 'L')
{
long value = [self longValue];
if (sizeof(long) == 4)
value = HOSTTOBSON32(value);
else if (sizeof(long) == 8)
value = HOSTTOBSON64(value);
return [NSData dataWithBytes: &value length: sizeof(long)];
}
if (encoding == 'q')
{
long long value = HOSTTOBSON64([self longLongValue]);
return [NSData dataWithBytes: &value length: 8];
}
if (encoding == 'Q')
{
long long value = HOSTTOBSON64([self unsignedLongLongValue]);
return [NSData dataWithBytes: &value length: 8];
}
[NSException raise: NSInvalidArgumentException format: @"%@::%s - invalid encoding type '%c'", [self class], _cmd, encoding];
return nil;
}
- (NSData *) BSONRepresentation
{
return [self BSONEncode];
}
+ (id) BSONFragment: (NSData *) data at: (const void **) base ofType: (uint8_t) t
{
if (t == 0x01)
{
// #5: LLVM GCC requires double pointers to have a certain alignment in ARM CPUs.
// So we can't just read the double off directly from the data - need to copy it.
double value;
memcpy(&value, *base, sizeof(double));
*base += 8;
return [NSNumber numberWithDouble: value];
}
if (t == 0x08)
{
char value = ((char *) *base)[0];
*base += 1;
return [NSNumber numberWithBool: value];
}
if (t == 0x10)
{
int32_t value = BSONTOHOST32(((int32_t *) *base)[0]);
*base += 4;
if (sizeof(int) == 4)
return [NSNumber numberWithInt: value];
return [NSNumber numberWithLong: value];
}
if (t == 0x12)
{
int64_t value = BSONTOHOST64(((int64_t *) *base)[0]);
*base += 8;
return [NSNumber numberWithUnsignedLongLong: value];
}
return nil;
}
@end
@implementation NSString (BSON)
- (uint8_t) BSONTypeID
{
return 0x02;
}
- (NSData *) BSONEncode
{
NSData *utf8Data = [self dataUsingEncoding: NSUTF8StringEncoding];
uint32_t length = HOSTTOBSON32([utf8Data length] + 1);
NSMutableData *retval = [NSMutableData data];
[retval appendBytes: &length length: 4];
[retval appendData: utf8Data];
[retval appendBytes: "\x00" length: 1];
return retval;
}
- (NSData *) BSONRepresentation
{
return [self BSONEncode];
}
+ (id) BSONFragment: (NSData *) data at: (const void **) base ofType: (uint8_t) typeID
{
uint32_t length = BSONTOHOST32(((const uint32_t *) *base)[0]);
*base += 4;
const char *utf8Str = (const char *) *base;
*base += length;
return [NSString stringWithUTF8String: utf8Str];
}
@end
@implementation NSArray (BSON)
- (uint8_t) BSONTypeID
{
return 0x04;
}
- (NSData *) BSONEncode
{
// Initialize the components structure.
NSMutableArray *components = [[NSMutableArray alloc] init];
NSMutableData *lengthData = [[NSMutableData alloc] initWithLength: 4];
[components addObject: lengthData];
[lengthData release];
NSMutableData *contentsData = [[NSMutableData alloc] init];
[components addObject: contentsData];
[contentsData release];
[components addObject: [NSData dataWithBytes: "\x00" length: 1]];
// Encode data.
uint8_t elementType = 0;
int i, count = [self count];
for (i = 0 ; i < count ; i++)
{
NSObject *value = [self objectAtIndex: i];
if ([value respondsToSelector: @selector(BSONTypeID)])
elementType = [(id <BSONCoding>) value BSONTypeID];
else
elementType = 3;
[contentsData appendBytes: &elementType length: 1];
[contentsData appendData: [[NSString stringWithFormat: @"%d", i] dataUsingEncoding: NSUTF8StringEncoding]];
[contentsData appendBytes: "\x00" length: 1];
[contentsData appendData: [value BSONEncode]];
}
// Write length.
uint32_t *length = (uint32_t *)[lengthData mutableBytes];
*length = HOSTTOBSON32([contentsData length]) + 4 + 1;
// Assemble the output data.
NSMutableData *retval = [NSMutableData data];
for (i = 0; i < [components count]; i++)
[retval appendData: [components objectAtIndex: i]];
[components release];
return retval;
}
- (NSData *) BSONRepresentation
{
return [self BSONEncode];
}
+ (id) BSONFragment: (NSData *) data at: (const void **) base ofType: (uint8_t) typeID
{
NSDictionary *tmp = [NSDictionary BSONFragment: data at: base ofType: 0x03];
NSMutableArray *retval = [NSMutableArray arrayWithCapacity: [tmp count]];
int i;
for (i = 0; i < [tmp count]; i++)
[retval addObject: [tmp objectForKey: [NSString stringWithFormat: @"%d", i]]];
return retval;
}
@end
@implementation NSNull (BSON)
- (uint8_t) BSONTypeID
{
return 0x0a;
}
- (NSData *) BSONEncode
{
return [NSData data];
}
- (NSData *) BSONRepresentation
{
return [self BSONEncode];
}
+ (id) BSONFragment: (NSData *) data at: (const void **) base ofType: (uint8_t) typeID
{
return [NSNull null];
}
@end
@implementation NSCalendarDate (BSON)
- (uint8_t) BSONTypeID
{
return 0x11;
}
- (NSData *) BSONEncode
{
NSString *v;
v = [self descriptionWithCalendarFormat: @"%Y-%m-%d %H:%M:%S %Z"
locale: nil];
return [v BSONEncode];
}
- (NSData *) BSONRepresentation
{
return [self BSONEncode];
}
+ (id) BSONFragment: (NSData *) data at: (const void **) base ofType: (uint8_t) typeID
{
NSString *v;
v = [NSString BSONFragment: data at: base ofType: 0x02];
return [NSCalendarDate dateWithString: v
calendarFormat: @"%Y-%m-%d %H:%M:%S %Z"];
}
@end
+5 -5
View File
@@ -46,12 +46,12 @@
NSDictionary *properties;
BOOL rc;
[self logWithFormat: @"evaluating object '%@'", object];
//[self logWithFormat: @"evaluating object '%@'", object];
properties = [object properties];
rc = [self _evaluateSOGoMAPIDBObject: properties];
[self logWithFormat: @" evaluation result: %d", rc];
//[self logWithFormat: @" evaluation result: %d", rc];
return rc;
}
@@ -150,9 +150,9 @@ typedef BOOL (*EOComparator) (id, SEL, id);
rc = ((isZero && (intValue & mask) == 0)
|| (!isZero && (intValue & mask) != 0));
[self logWithFormat: @"evaluation of bitmask qualifier:"
@" (%.8x & %.8x) %s 0: %d",
intValue, mask, (isZero ? "==" : "!="), rc];
//[self logWithFormat: @"evaluation of bitmask qualifier:"
// @" (%.8x & %.8x) %s 0: %d",
// intValue, mask, (isZero ? "==" : "!="), rc];
return rc;
}
+1 -1
View File
@@ -79,7 +79,7 @@
@" c_lastmodified INT NOT NULL,"
@" c_version INT NOT NULL DEFAULT 0,"
@" c_deleted TINYINT NOT NULL DEFAULT 0,"
@" c_content TEXT)");
@" c_content LONGTEXT)");
return [NSString stringWithFormat: sqlFolderFormat, tableName];
}
+5 -30
View File
@@ -7,8 +7,6 @@ include ../Version
BACKEND_VERSION = 1.0.0
UNRTF_VERSION = 0.21.2
### bootstrap library
MAPISTORESOGO = MAPIStoreSOGo
LIBRARY_NAME = $(MAPISTORESOGO)
@@ -24,8 +22,6 @@ BUNDLE_NAME = $(SOGOBACKEND)
BUNDLE_EXTENSION = .MAPIStore
BUNDLE_INSTALL_DIR = $(SOGO_LIBDIR)
UNRTF_DIR = unrtf-$(UNRTF_VERSION)
PYTHON = /usr/bin/python
PYTHON_IS_GOOD = $(shell $(PYTHON) -c 'from sys import version_info; a=version_info; print a[0] == 2 and a[1] >= 6')
ifeq (${PYTHON_IS_GOOD},False)
@@ -37,8 +33,6 @@ all::
SAMBA_PRIVATE_DIR = $(shell $(PYTHON) ./samba-get-config.py "private dir")
$(SOGOBACKEND)_SUBPROJECTS += $(UNRTF_DIR)/src
$(SOGOBACKEND)_PRINCIPAL_CLASS = MAPIApplication
$(SOGOBACKEND)_OBJC_FILES += \
@@ -133,32 +127,14 @@ $(SOGOBACKEND)_OBJC_FILES += \
\
EOQualifier+MAPI.m \
\
EOBitmaskQualifier.m
EOBitmaskQualifier.m \
\
BSONCodec.m \
RTFHandler.m
$(SOGOBACKEND)_RESOURCE_FILES += \
product.plist \
$(UNRTF_DIR)/charmaps/SYMBOL.charmap \
$(UNRTF_DIR)/outputs/html.conf
### unrtf
all:: $(UNRTF_DIR)/config.h $(UNRTF_DIR)/src/GNUmakefile
$(UNRTF_DIR): $(UNRTF_DIR).tar.gz $(UNRTF_DIR).diff
@echo " Extracting and patching $(UNRTF_DIR)..."
@rm -rf $(UNRTF_DIR)
@$(TAR) -xvzf $< > /dev/null
@(cd $(UNRTF_DIR) && patch -p1 < ../$(UNRTF_DIR).diff) > /dev/null
@touch $(UNRTF_DIR)
$(UNRTF_DIR)-stamp: $(UNRTF_DIR)
@touch $@
$(UNRTF_DIR)/config.h: $(UNRTF_DIR)-stamp unrtf_config_h
@cp unrtf_config_h $(UNRTF_DIR)/config.h
$(UNRTF_DIR)/src/GNUmakefile: $(UNRTF_DIR)-stamp GNUmakefile.unrtf
@cp GNUmakefile.unrtf $@
product.plist
### pl reader
PLREADER_TOOL = plreader
@@ -210,7 +186,6 @@ ADDITIONAL_INCLUDE_DIRS += \
-DSAMBA_PRIVATE_DIR=@"\"$(SAMBA_PRIVATE_DIR)\"" \
$(LIBMAPI_CFLAGS) \
$(LIBMAPISTORE_CFLAGS) \
-I$(UNRTF_DIR)/src \
-I../SoObjects -I../SOPE \
-DBACKEND_BUNDLE_NAME="@\"$(BUNDLE_NAME)$(BUNDLE_EXTENSION)\"" \
-DSOGO_BUNDLES_DIR="@\"$(BUNDLE_INSTALL_DIR)\""
-34
View File
@@ -1,34 +0,0 @@
# -*-makefile-*-
# GNUstep makefile
include $(GNUSTEP_MAKEFILES)/common.make
UNRTF = unrtf
SUBPROJECT_NAME = $(UNRTF)
$(UNRTF)_C_FILES = \
attr.c \
convert.c \
error.c \
hash.c \
malloc.c \
my_iconv.c \
output.c \
parse.c \
unicode.c \
user.c \
util.c \
word.c
$(UNRTF)_CFLAGS = -DHAVE_CONFIG_H=1 -I. -I../
# Option include to set any additional variables
-include GNUmakefile.preamble
# Include in the rules for making libraries
include $(GNUSTEP_MAKEFILES)/subproject.make
# Option include to define any additional rules
-include GNUmakefile.postamble
@@ -161,7 +161,7 @@
return [self getNo: data inMemCtx: memCtx];
}
- (void) save
- (void) save: (TALLOC_CTX *) memCtx
{
// (gdb) po embeddedMessage->properties
// 2442592320 = "2012-07-11 22:30:00 +0000";
@@ -208,7 +208,8 @@
[[container event] updateFromMAPIProperties: properties
inUserContext: [self userContext]
withActiveUser: activeUser];
withActiveUser: activeUser
inMemCtx: memCtx];
}
@end
+1 -1
View File
@@ -63,7 +63,7 @@
SOGoAppointmentObject *newEntry;
NSString *name;
[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
//[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
name = [NSString stringWithFormat: @"%@.ics",
[SOGoObject globallyUniqueObjectId]];
+7 -6
View File
@@ -200,6 +200,7 @@ static Class NSArrayK;
- (void) dealloc
{
//NSLog(@"MAPIStoreCalendarMessage: -dealloc (%p)", self);
[calendar release];
[super dealloc];
}
@@ -417,7 +418,7 @@ static Class NSArrayK;
return [self getYes: data inMemCtx: memCtx];
}
- (NSString *) _uidFromGlobalObjectId
- (NSString *) _uidFromGlobalObjectId: (TALLOC_CTX *) memCtx
{
NSData *objectId;
NSString *uid = nil;
@@ -431,7 +432,7 @@ static Class NSArrayK;
if (objectId)
{
length = [objectId length];
bytesDup = talloc_array (NULL, char, length + 1);
bytesDup = talloc_array (memCtx, char, length + 1);
memcpy (bytesDup, [objectId bytes], length);
bytesDup[length] = 0;
uidStart = bytesDup + length - 1;
@@ -596,7 +597,7 @@ static Class NSArrayK;
}
}
- (void) save
- (void) save: (TALLOC_CTX *) memCtx
{
// iCalCalendar *vCalendar;
// NSCalendarDate *now;
@@ -608,7 +609,7 @@ static Class NSArrayK;
if (isNew)
{
uid = [self _uidFromGlobalObjectId];
uid = [self _uidFromGlobalObjectId: memCtx];
if (uid)
{
/* Hack required because of what's explained in oxocal 3.1.4.7.1:
@@ -650,12 +651,12 @@ static Class NSArrayK;
activeUser = [[self context] activeUser];
[masterEvent updateFromMAPIProperties: properties
inUserContext: [self userContext]
withActiveUser: activeUser];
withActiveUser: activeUser
inMemCtx: memCtx];
[self _updateAttachedEvents];
[[self userContext] activateWithUser: activeUser];
[sogoObject updateContentWithCalendar: calendar
fromRequest: nil];
[self updateVersions];
}
+1 -1
View File
@@ -911,7 +911,7 @@ fromProperties: (NSDictionary *) attachmentProps
//
//
//
- (void) save
- (void) save:(TALLOC_CTX *) memCtx
{
NSArray *elements, *units;
CardElement *element;
+3 -3
View File
@@ -224,7 +224,7 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
NSURL *baseURL;
int rc = MAPISTORE_ERR_NOT_FOUND;
NSLog (@"METHOD '%s' (%d) -- uri: '%s'", __FUNCTION__, __LINE__, newUri);
//NSLog (@"METHOD '%s' (%d) -- uri: '%s'", __FUNCTION__, __LINE__, newUri);
context = nil;
@@ -532,8 +532,8 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri)
mappingId = [mapping idFromURL: childURL];
if (mappingId == NSNotFound)
{
[self warnWithFormat: @"no id exist yet for '%@', requesting one...",
childURL];
//[self warnWithFormat: @"no id exist yet for '%@', requesting one...",
// childURL];
openchangedb_get_new_folderID (connInfo->oc_ctx, &mappingId);
[mapping registerURL: childURL withID: mappingId];
contextId = 0;
+2 -2
View File
@@ -236,7 +236,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
messageKeys = [self messageKeys];
date = [NSCalendarDate date];
[self logWithFormat: @"current date: %@", date];
//[self logWithFormat: @"current date: %@", date];
max = [messageKeys count];
for (count = 0; count < max; count++)
@@ -245,7 +245,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
fileDate = [msg lastModificationTime];
if ([date laterDate: fileDate] == fileDate)
{
[self logWithFormat: @"current date: %@", date];
//[self logWithFormat: @"current date: %@", date];
date = fileDate;
}
+18 -1
View File
@@ -23,6 +23,7 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#import <NGExtensions/NSObject+Logs.h>
@@ -34,6 +35,7 @@
#import "MAPIStoreDBMessage.h"
#import "MAPIStoreTypes.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
#undef DEBUG
#include <mapistore/mapistore.h>
@@ -99,6 +101,21 @@
return objectVersion;
}
//
// FIXME: how this can happen?
//
// We might get there if for some reasons, all classes weren't able
// to tell us the message class.
//
- (int) getPidTagMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx
{
*data = [@"IPM.Note" asUnicodeInMemCtx: memCtx];
[self logWithFormat: @"METHOD '%s' - unable to determine message class. Falling back to IPM.Note", __FUNCTION__];
return MAPISTORE_SUCCESS;
}
- (int) getProperties: (struct mapistore_property_data *) data
withTags: (enum MAPITAGS *) tags
andCount: (uint16_t) columnCount
@@ -135,7 +152,7 @@
[super addProperties: newNewProperties];
}
- (void) save
- (void) save: (TALLOC_CTX *) memCtx
{
uint64_t newVersion;
+1 -1
View File
@@ -65,7 +65,7 @@ static Class MAPIStoreDBMessageK = Nil;
cVersion = exchange_globcnt (([value unsignedLongLongValue] >> 16)
& 0x0000ffffffffffffLL);
version = [NSNumber numberWithUnsignedLongLong: cVersion];
[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
[self logWithFormat: @" version: %.16lx", cVersion];
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"version"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
+1 -1
View File
@@ -146,7 +146,7 @@ static Class MAPIStoreAttachmentK;
return ULLONG_MAX;
}
- (void) save
- (void) save: (TALLOC_CTX *) memCtx
{
[self subclassResponsibility: _cmd];
}
+2 -2
View File
@@ -51,7 +51,7 @@
return [self getYes: data inMemCtx: memCtx];
}
- (enum mapistore_error) saveMessage
- (enum mapistore_error) saveMessage: (TALLOC_CTX *) memCtx;
{
enum mapistore_error rc;
MAPIStoreContext *context;
@@ -60,7 +60,7 @@
context = [self context];
ownerUser = [[self userContext] sogoUser];
if ([[context activeUser] isEqual: ownerUser])
rc = [super saveMessage];
rc = [super saveMessage: memCtx];
else
rc = MAPISTORE_ERR_DENIED;
+10 -10
View File
@@ -180,7 +180,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
- (void) dealloc
{
[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
//[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
// [messageKeys release];
// [faiMessageKeys release];
@@ -366,7 +366,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
MAPIStoreMapping *mapping;
NSString *childURL;
[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
//[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
mapping = [self mapping];
childURL = [mapping urlFromID: fid];
@@ -393,7 +393,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
MAPIStoreFolder *childFolder;
SOGoUser *ownerUser;
[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
//[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
ownerUser = [[self userContext] sogoUser];
if ([[context activeUser] isEqual: ownerUser]
@@ -450,8 +450,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSArray *keys;
int rc = MAPISTORE_SUCCESS;
[self logWithFormat: @"METHOD '%s' (%d) -- tableType: %d",
__FUNCTION__, __LINE__, tableType];
//[self logWithFormat: @"METHOD '%s' (%d) -- tableType: %d",
//__FUNCTION__, __LINE__, tableType];
if (tableType == MAPISTORE_MESSAGE_TABLE)
keys = [self messageKeys];
@@ -513,8 +513,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
MAPIStoreMapping *mapping;
SOGoUser *ownerUser;
[self logWithFormat: @"METHOD '%s' -- mid: 0x%.16llx associated: %d",
__FUNCTION__, mid, isAssociated];
//[self logWithFormat: @"METHOD '%s' -- mid: 0x%.16llx associated: %d",
// __FUNCTION__, mid, isAssociated];
context = [self context];
ownerUser = [[self userContext] sogoUser];
@@ -699,7 +699,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (rc != MAPISTORE_SUCCESS)
goto end;
}
[destMsg save];
[destMsg save: memCtx];
if (!wantCopy)
rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: 0];
@@ -844,7 +844,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
[mapping registerURL: [targetMessage url]
withID: fmid];
}
[targetMessage save];
[targetMessage save: memCtx];
}
[pool release];
@@ -865,7 +865,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
[mapping registerURL: [targetMessage url]
withID: fmid];
}
[targetMessage save];
[targetMessage save: memCtx];
}
[pool release];
+2
View File
@@ -122,6 +122,8 @@
[MAPIApp setUserContext: userContext];
moduleName = [self MAPIModuleName];
parentFolder = [[userContext rootFolders] objectForKey: moduleName];
nameInContainer = nil;
if (![parentFolder newFolderWithName: folderName
nameInContainer: &nameInContainer])
mapistoreURI = [NSString stringWithFormat: @"sogo://%@@%@/%@/",
+4 -2
View File
@@ -259,7 +259,6 @@ static Class NSNumberK;
}
}
*/
- (void) _setChangeKey: (NSData *) changeKey
forMessageEntry: (NSMutableDictionary *) messageEntry
inChangeListOnly: (BOOL) inChangeListOnly
@@ -461,7 +460,10 @@ static Class NSNumberK;
[mapping setObject: cLastModified forKey: changeNumber];
[messageEntry setObject: changeNumber forKey: @"version"];
newChangeNum = [changeNumber unsignedLongValue];
newChangeNum = [changeNumber unsignedLongLongValue];
// A GLOBCNT structure is a 6-byte global namespace counter,
// we strip the first 2 bytes. The first two bytes is the ReplicaId
changeKey = [self getReplicaKeyFromGlobCnt: newChangeNum >> 16];
[self _setChangeKey: changeKey forMessageEntry: messageEntry
inChangeListOnly: NO];
+2 -2
View File
@@ -92,8 +92,8 @@
value = NSObjectFromMAPISPropValue (&res->lpProp);
lastModified = [(MAPIStoreGCSFolder *)
container lastModifiedFromMessageChangeNumber: value];
[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
[self logWithFormat: @" c_lastmodified: %@", lastModified];
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
//[self logWithFormat: @" c_lastmodified: %@", lastModified];
if (lastModified)
{
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_lastmodified"
+3 -2
View File
@@ -24,6 +24,7 @@
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSURL.h>
#import <NGImap4/NSString+Imap4.h>
#import <NGExtensions/NSString+misc.h>
#import <Mailer/SOGoMailAccount.h>
#import <Mailer/SOGoMailFolder.h>
@@ -156,7 +157,7 @@ MakeDisplayFolderName (NSString *folderName)
stringData = [NSString stringWithFormat: @"%@%@",
urlBase, [currentName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
context->url = [stringData asUnicodeInMemCtx: context];
stringData = [[currentName substringFromIndex: 6] fromCSSIdentifier];
stringData = [[[currentName substringFromIndex: 6] fromCSSIdentifier] stringByDecodingImap4FolderName];
context->name = [stringData asUnicodeInMemCtx: context];
context->main_folder = false;
context->role = MAPISTORE_MAIL_ROLE;
@@ -188,7 +189,7 @@ MakeDisplayFolderName (NSString *folderName)
if ([newFolder create])
mapistoreURI = [NSString stringWithFormat: @"sogo://%@:%@@mail/%@/",
userName, userName,
[folderName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
[[folderName stringByEncodingImap4FolderName] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
else
mapistoreURI = nil;
[MAPIApp setUserContext: nil];
+7 -6
View File
@@ -36,6 +36,7 @@
#import <NGExtensions/NSString+misc.h>
#import <NGImap4/NGImap4Connection.h>
#import <NGImap4/NGImap4Client.h>
#import <NGImap4/NSString+Imap4.h>
#import <Mailer/SOGoDraftsFolder.h>
#import <Mailer/SOGoMailAccount.h>
#import <Mailer/SOGoMailAccounts.h>
@@ -177,7 +178,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
if (folderName)
{
nameInContainer = [NSString stringWithFormat: @"folder%@",
[folderName asCSSIdentifier]];
[[folderName stringByEncodingImap4FolderName] asCSSIdentifier]];
newFolder = [SOGoMailFolderK objectWithName: nameInContainer
inContainer: sogoObject];
if ([newFolder create])
@@ -315,7 +316,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
if (![subfolderName hasPrefix: @"folder"])
abort ();
strippedName = [subfolderName substringFromIndex: 6];
strippedName = [[subfolderName substringFromIndex: 6] stringByDecodingImap4FolderName];
[representation appendFormat: @"/%@", strippedName];
return representation;
@@ -390,7 +391,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
else
value = [NSDate date];
[self logWithFormat: @"lastMessageModificationTime: %@", value];
//[self logWithFormat: @"lastMessageModificationTime: %@", value];
return value;
}
@@ -613,8 +614,8 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
[messageEntry setObject: modseq forKey: @"modseq"];
[messageEntry setObject: changeNumber forKey: @"version"];
[self logWithFormat: @"added message entry for uid %@, modseq %@,"
@" version %@", uid, modseq, changeNumber];
//[self logWithFormat: @"added message entry for uid %@, modseq %@,"
// @" version %@", uid, modseq, changeNumber];
changeKey = [self getReplicaKeyFromGlobCnt: newChangeNum >> 16];
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
@@ -796,7 +797,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
if (tableType == MAPISTORE_MESSAGE_TABLE)
{
changeNumber = [NSString stringWithUnsignedLongLong: changeNum];
changeNumber = [NSString stringWithFormat: @"0x%.16llx", changeNum];
modseq = [[self modseqFromMessageChangeNumber: changeNumber]
unsignedLongLongValue];
if (modseq > 0)
+10 -2
View File
@@ -693,7 +693,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
ngAddress = [[NGMailAddressParser mailAddressParserWithString: fullMail]
parse];
if ([ngAddress isKindOfClass: [NGMailAddress class]])
cn = [ngAddress displayName];
{
cn = [ngAddress displayName];
// If we don't have a displayName, we use the email address instead. This
// avoid bug #2119 - where Outlook won't display anything in the "From" field,
// nor in the recipient field if we reply to the email.
if (![cn length])
cn = [ngAddress address];
}
else
cn = @"";
@@ -1576,7 +1584,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
bodySetup = YES;
}
- (void) save
- (void) save: (TALLOC_CTX *) memCtx
{
NSNumber *value;
+5 -4
View File
@@ -120,7 +120,7 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK;
case PidLidAppointmentStartWhole:
case PidLidAppointmentEndWhole:
case PidLidRecurring:
[self logWithFormat: @"apt restriction on mail folder?"];
//[self logWithFormat: @"apt restriction on mail folder?"];
rc = MAPIRestrictionStateAlwaysFalse;
break;
@@ -155,10 +155,11 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK;
case PidTagChangeNumber:
{
value = [NSString stringWithFormat: @"0x%.16llx", [value unsignedLongLongValue]];
modseq = [(MAPIStoreMailFolder *)
container modseqFromMessageChangeNumber: value];
[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
[self logWithFormat: @" modseq: %.16lx", [modseq unsignedLongLongValue]];
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
//[self logWithFormat: @" modseq: %.16lx", [modseq unsignedLongLongValue]];
if (modseq)
modseq = [NSNumber numberWithUnsignedLongLong:
[modseq unsignedLongLongValue] + 1];
@@ -316,7 +317,7 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK;
ASSIGN (sortOrderings, newSortOrderings);
else
ASSIGN (sortOrderings, [NSArray arrayWithObject: @"ARRIVAL"]);
[self logWithFormat: @"new sort orderings: '%@'", sortOrderings];
//[self logWithFormat: @"new sort orderings: '%@'", sortOrderings];
}
else
ASSIGN (sortOrderings, [NSArray arrayWithObject: @"ARRIVAL"]);
+25 -2
View File
@@ -543,6 +543,7 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
NSDictionary *recipients;
NSUInteger type, bccLimit;
SOGoUser *activeUser;
NSNumber *priority;
activeUser
= [SOGoUser
@@ -596,6 +597,21 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
[headers addObject: [date rfc822DateString] forKey: @"date"];
}
[headers addObject: @"1.0" forKey: @"MIME-Version"];
priority = [mailProperties objectForKey: MAPIPropertyKey (PidTagImportance)];
if ([priority intValue] == 2)
{
[headers addObject: @"1 (Highest)" forKey: @"X-Priority"];
}
else if ([priority intValue] == 1)
{
[headers removeAllObjectsForKey: @"X-Priority"];
}
else
{
[headers addObject: @"5 (Lowest)" forKey: @"X-Priority"];
}
}
static NSArray *
@@ -904,7 +920,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
return MAPISTORE_SUCCESS;
}
- (void) save
- (void) save: (TALLOC_CTX *) memCtx
{
NSString *folderName, *flag, *newIdString, *messageKey;
NSData *changeKey, *messageData;
@@ -943,7 +959,14 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
[mapping registerURL: [self url] withID: mid];
/* synchronise the cache and update the change key with the one provided
by the client */
by the client. Before doing this, lets issue a unselect/select combo
because of timing issues with Dovecot in obtaining the latest modseq.
Sometimes, Dovecot doesn't return the newly appended UID if we do
a "UID SORT (DATE) UTF-8 (MODSEQ XYZ) (NOT DELETED)" command (where
XYZ is the HIGHESTMODSEQ+1) immediately after IMAP APPEND */
[client unselect];
[client select: folderName];
[(MAPIStoreMailFolder *) container synchroniseCache];
changeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)];
if (changeKey)
+2 -2
View File
@@ -64,7 +64,7 @@
- (int) getAttachmentTable: (MAPIStoreAttachmentTable **) tablePtr
andRowCount: (uint32_t *) countPtr;
- (int) setReadFlag: (uint8_t) flag;
- (enum mapistore_error) saveMessage;
- (enum mapistore_error) saveMessage: (TALLOC_CTX *) memCtx;
- (NSArray *) activeContainerMessageTables;
@@ -74,7 +74,7 @@
- (void) copyToMessage: (MAPIStoreMessage *) newMessage inMemCtx: (TALLOC_CTX *) memCtx;
/* subclasses */
- (void) save;
- (void) save: (TALLOC_CTX *) memCtx;
/* attachments (subclasses) */
- (MAPIStoreAttachment *) createAttachment;
+18 -35
View File
@@ -45,11 +45,10 @@
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
#import "RTFHandler.h"
#import "MAPIStoreMessage.h"
#include <unrtf.h>
#undef DEBUG
#include <stdbool.h>
#include <gen_ndr/exchange.h>
@@ -60,17 +59,6 @@ static Class MAPIStoreFolderK, MAPIStoreEmbeddedMessageK;
static NSString *resourcesDir = nil;
/* rtf conversion via unrtf */
static int
unrtf_data_output (void *data, const char *str, size_t str_len)
{
NSMutableData *rtfData = data;
[rtfData appendBytes: str length: str_len];
return str_len;
}
static NSData *
uncompressRTF (NSData *compressedRTF)
{
@@ -97,22 +85,17 @@ rtf2html (NSData *compressedRTF)
{
NSData *rtf;
NSMutableData *html = nil;
int rc;
struct unRTFOptions unrtfOptions;
rtf = uncompressRTF (compressedRTF);
if (rtf)
{
html = [NSMutableData data];
memset (&unrtfOptions, 0, sizeof (struct unRTFOptions));
unrtf_set_output_device (&unrtfOptions, unrtf_data_output, html);
unrtfOptions.config_directory = [resourcesDir UTF8String];
unrtfOptions.output_format = "html";
unrtfOptions.nopict_mode = YES;
rc = unrtf_convert_from_string (&unrtfOptions,
[rtf bytes], [rtf length]);
if (!rc)
html = nil;
//html = [NSMutableData data];
RTFHandler *handler;
handler = [[RTFHandler alloc] initWithData: rtf];
AUTORELEASE(handler);
html = [handler parse];
}
return html;
@@ -139,7 +122,7 @@ rtf2html (NSData *compressedRTF)
- (id) init
{
[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
//[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
if ((self = [super init]))
{
@@ -153,7 +136,7 @@ rtf2html (NSData *compressedRTF)
- (void) dealloc
{
[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
//[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
[activeUserRoles release];
[attachmentKeys release];
[attachmentParts release];
@@ -260,7 +243,7 @@ rtf2html (NSData *compressedRTF)
struct mapistore_message_recipient *recipient;
NSUInteger count;
[self logWithFormat: @"METHOD '%s'", __FUNCTION__];
//[self logWithFormat: @"METHOD '%s'", __FUNCTION__];
recipients = [NSMutableDictionary new];
recipientProperties = [NSDictionary dictionaryWithObject: recipients
@@ -450,7 +433,7 @@ rtf2html (NSData *compressedRTF)
NSString *key;
MAPIStoreAttachment *attachment, *newAttachment;
[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
//[self logWithFormat: @"METHOD '%s' (%d) (%d)", __FUNCTION__, __LINE__, self];
//memCtx = talloc_zero (NULL, TALLOC_CTX);
@@ -477,7 +460,7 @@ rtf2html (NSData *compressedRTF)
//talloc_free (memCtx);
}
- (enum mapistore_error) saveMessage
- (enum mapistore_error) saveMessage: (TALLOC_CTX *) memCtx
{
enum mapistore_error rc;
NSArray *containerTables;
@@ -490,7 +473,7 @@ rtf2html (NSData *compressedRTF)
BOOL userIsOwner;
MAPIStoreMessage *mainMessage;
[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
//[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__];
context = [self context];
ownerUser = [[self userContext] sogoUser];
@@ -518,7 +501,7 @@ rtf2html (NSData *compressedRTF)
/* folder modified */
notif_parameters
= talloc_zero(NULL, struct mapistore_object_notification_parameters);
= talloc_zero(memCtx, struct mapistore_object_notification_parameters);
notif_parameters->object_id = folderId;
if (isNew)
{
@@ -542,7 +525,7 @@ rtf2html (NSData *compressedRTF)
if (isNew)
{
notif_parameters
= talloc_zero(NULL,
= talloc_zero(memCtx,
struct mapistore_object_notification_parameters);
notif_parameters->object_id = [self objectId];
notif_parameters->folder_id = folderId;
@@ -562,7 +545,7 @@ rtf2html (NSData *compressedRTF)
[[containerTables objectAtIndex: count] restrictedChildKeys];
}
[self save];
[self save: memCtx];
/* We make sure that any change-related properties are removes from the
properties dictionary, to make sure that related methods will be
invoked the next time they are requested. */
@@ -937,7 +920,7 @@ rtf2html (NSData *compressedRTF)
return MAPISTORE_ERROR;
}
- (void) save
- (void) save: (TALLOC_CTX *) memCtx
{
[self subclassResponsibility: _cmd];
}
+3
View File
@@ -284,6 +284,9 @@ static Class NSExceptionK, MAPIStoreFolderK;
return MAPISTORE_SUCCESS;
}
//
// The GlobCnt is 6 bytes long.
//
- (NSData *) getReplicaKeyFromGlobCnt: (uint64_t) objectCnt
{
struct mapistore_connection_info *connInfo;
+4 -4
View File
@@ -68,7 +68,7 @@ sogo_backend_atexit (void)
GSRegisterCurrentThread ();
pool = [NSAutoreleasePool new];
NSLog (@"allocated classes:\n%s", GSDebugAllocationList (YES));
//NSLog (@"allocated classes:\n%s", GSDebugAllocationList (YES));
[pool release];
GSUnregisterCurrentThread ();
}
@@ -1024,7 +1024,7 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
}
static enum mapistore_error
sogo_message_save (void *message_object)
sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx)
{
struct MAPIStoreTallocWrapper *wrapper;
NSAutoreleasePool *pool;
@@ -1039,7 +1039,7 @@ sogo_message_save (void *message_object)
message = wrapper->instance;
GSRegisterCurrentThread ();
pool = [NSAutoreleasePool new];
rc = [message saveMessage];
rc = [message saveMessage: mem_ctx];
// [context tearDownRequest];
[pool release];
GSUnregisterCurrentThread ();
@@ -1229,7 +1229,7 @@ sogo_table_set_restrictions (void *table_object, struct mapi_SRestriction *restr
GSRegisterCurrentThread ();
pool = [NSAutoreleasePool new];
[table setRestrictions: restrictions];
[table cleanupCaches];
//[table cleanupCaches];
rc = MAPISTORE_SUCCESS;
*table_status = TBLSTAT_COMPLETE;
[pool release];
+7 -7
View File
@@ -375,12 +375,12 @@ static Class NSDataK, NSStringK;
- (void) setRestrictions: (const struct mapi_SRestriction *) res
{
EOQualifier *oldRestriction;
//EOQualifier *oldRestriction;
// [self logWithFormat: @"set restriction to (table type: %d): %@",
// type, MAPIStringForRestriction (res)];
oldRestriction = restriction;
//oldRestriction = restriction;
[restriction autorelease];
if (res)
restrictionState = [self evaluateRestriction: res
@@ -396,11 +396,11 @@ static Class NSDataK, NSStringK;
// FIXME: we should not flush the caches if the restrictions matches
[self cleanupCaches];
if (restriction)
[self logWithFormat: @"restriction set to EOQualifier: %@",
restriction];
else if (oldRestriction)
[self logWithFormat: @"restriction unset (was %@)", oldRestriction];
//if (restriction)
// [self logWithFormat: @"restriction set to EOQualifier: %@",
// restriction];
// else if (oldRestriction)
// [self logWithFormat: @"restriction unset (was %@)", oldRestriction];
}
- (MAPIRestrictionState) evaluateNotRestriction: (struct mapi_SNotRestriction *) res
+1 -1
View File
@@ -357,7 +357,7 @@
return rc;
}
- (void) save
- (void) save:(TALLOC_CTX *) memCtx
{
iCalCalendar *vCalendar;
iCalToDo *vToDo;
+2 -2
View File
@@ -52,9 +52,9 @@ static inline NSNumber *
MAPIPropertyKey (enum MAPITAGS propTag)
{
#if (GS_SIZEOF_LONG == 4)
return [NSNumber numberWithUnsignedLong: propTag];
return [NSString stringWithFormat: @"%ul", propTag];
#elif (GS_SIZEOF_INT == 4)
return [NSNumber numberWithUnsignedInt: propTag];
return [NSString stringWithFormat: @"%u", propTag];
#else
#error No suitable type for 4 bytes integers
#endif
+4 -3
View File
@@ -342,7 +342,8 @@ MAPIStoreDumpMessageProperties (NSDictionary *properties)
{
NSNumber *key;
NSArray *allKeys;
NSUInteger keyAsInt, count, max;
NSUInteger count, max;
NSUInteger keyAsInt;
id value;
allKeys = [properties allKeys];
@@ -351,7 +352,7 @@ MAPIStoreDumpMessageProperties (NSDictionary *properties)
NSLog (@"message properties (%d):", max);
value = [properties objectForKey: @"recipients"];
if (value)
if (value)
NSLog (@" recipients: %@", value);
for (count = 0; count < max; count++)
@@ -363,7 +364,7 @@ MAPIStoreDumpMessageProperties (NSDictionary *properties)
value = [properties objectForKey: key];
NSLog (@" 0x%.4x: %@ (%@)",
keyAsInt, value,
NSStringFromClass ([value class]));
NSStringFromClass ([value class]));
}
}
}
+5 -2
View File
@@ -20,6 +20,7 @@
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSCharacterSet.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSMapTable.h>
@@ -107,15 +108,17 @@ static NSMapTable *contextsTable = nil;
password = nil;
path = [NSString stringWithFormat: SAMBA_PRIVATE_DIR
@"/mapistore/%@/password", newUsername];
@"/mapistore/%@/password", newUsername];
content = [NSData dataWithContentsOfFile: path];
if (content)
{
password = [[NSString alloc] initWithData: content
encoding: NSUTF8StringEncoding];
encoding: NSUTF8StringEncoding];
[password autorelease];
password = [password stringByTrimmingCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString: @"\r\n"]];
}
return password;
+4 -1
View File
@@ -148,6 +148,7 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
- (struct XID *) asXIDInMemCtx: (void *) memCtx
{
struct XID *xid;
uint8_t *bytes;
NSUInteger max;
max = [self length];
@@ -158,7 +159,9 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
[self _extractGUID: &xid->GUID];
xid->Size = max - 16;
xid->Data = talloc_memdup (xid, [self bytes] + 16, xid->Size);
bytes = (uint8_t *) [self bytes];
xid->Data = talloc_memdup (xid, (bytes+16), xid->Size);
}
else
{
+2 -4
View File
@@ -50,8 +50,7 @@ MAPIStoreTallocWrapperDestroy (void *data)
GSRegisterCurrentThread ();
pool = [NSAutoreleasePool new];
wrapper = data;
//NSLog (@"destroying wrapped object (wrapper: %p; object: %p)...\n", wrapper, wrapper->MAPIStoreSOGoObject);
NSLog (@"destroying wrapped object (wrapper: %p)", wrapper);
//NSLog (@"destroying wrapped object (wrapper: %p; object: %p (%@))...\n", wrapper, wrapper->instance, NSStringFromClass([wrapper->instance class]));
[wrapper->instance release];
[pool release];
GSUnregisterCurrentThread ();
@@ -67,8 +66,7 @@ MAPIStoreTallocWrapperDestroy (void *data)
talloc_set_destructor ((void *) wrapper, MAPIStoreTallocWrapperDestroy);
wrapper->instance = self;
[self retain];
NSLog (@"returning wrapper: %p; object: %p", wrapper, self);
//NSLog (@"returning wrapper: %p; object: %p (%@)", wrapper, self, NSStringFromClass([self class]));
return wrapper;
}
+39 -35
View File
@@ -33,6 +33,8 @@
#import <Foundation/NSValue.h>
#import <NGExtensions/NSNull+misc.h>
#import "BSONCodec.h"
const char *indentationStep = " ";
@interface NSObject (plext)
@@ -142,41 +144,43 @@ const char *indentationStep = " ";
static void
OCDumpPListData (NSData *content)
{
NSDictionary *d;
NSPropertyListFormat format;
NSString *error = nil;
const char *formatName;
//NSDictionary *d;
//NSPropertyListFormat format;
//NSString *error = nil;
//const char *formatName;
d = [NSPropertyListSerialization propertyListFromData: content
mutabilityOption: NSPropertyListImmutable
format: &format
errorDescription: &error];
if (d)
{
switch (format)
{
case NSPropertyListOpenStepFormat:
formatName = "OpenStep";
break;
case NSPropertyListXMLFormat_v1_0:
formatName = "XML";
break;
case NSPropertyListBinaryFormat_v1_0:
formatName = "Binary";
break;
case NSPropertyListGNUstepFormat:
formatName = "GNUstep";
break;
case NSPropertyListGNUstepBinaryFormat:
formatName = "GNUstep binary";
break;
default: formatName = "unknown";
}
//d = [NSPropertyListSerialization propertyListFromData: content
// mutabilityOption: NSPropertyListImmutable
// format: &format
// errorDescription: &error];
//d = [content BSONValue];
printf ("File format is: %s\n", formatName);
[d displayWithIndentation: 0];
printf ("\n");
}
else
printf ("an error occurred: %s\n", [error UTF8String]);
// if (d)
// {
// switch (format)
// {
// case NSPropertyListOpenStepFormat:
// formatName = "OpenStep";
// break;
// case NSPropertyListXMLFormat_v1_0:
// formatName = "XML";
// break;
// case NSPropertyListBinaryFormat_v1_0:
// formatName = "Binary";
// break;
// case NSPropertyListGNUstepFormat:
// formatName = "GNUstep";
// break;
// case NSPropertyListGNUstepBinaryFormat:
// formatName = "GNUstep binary";
// break;
// default: formatName = "unknown";
// }
// printf ("File format is: %s\n", formatName);
// [d displayWithIndentation: 0];
// printf ("\n");
// }
// else
// printf ("an error occurred: %s\n", [error UTF8String]);
}
+132
View File
@@ -0,0 +1,132 @@
/*
Copyright (C) 2005-2012 Inverse inc.
This file is part of SOGo.
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.
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public
License along with OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
#include <Foundation/NSArray.h>
#include <Foundation/NSData.h>
#include <Foundation/NSMapTable.h>
#include <Foundation/NSObject.h>
#include <Foundation/NSString.h>
//
//
//
@interface RTFHandler : NSObject
{
NSMapTable *_charsets;
NSMutableData *_html;
NSData *_data;
const char *_bytes;
int _current_pos;
int _len;
}
- (id) initWithData: (NSData *) theData;
- (NSMutableData *) parse;
@end
//
//
//
@interface RTFStack: NSObject
{
NSMutableArray *a;
}
- (void) push: (id) theObject;
- (id) pop;
@end
//
//
//
@interface RTFFormattingOptions : NSObject
{
@public
BOOL bold;
BOOL italic;
BOOL underline;
BOOL strikethrough;
int font_index;
int color_index;
int start_pos;
}
@end
//
//
//
@interface RTFFontInfo : NSObject
{
@public
NSString *family;
NSString *charset;
NSString *name;
unsigned int pitch;
unsigned int index;
}
@end
//
// \fX - font, index in font table
//
@interface RTFFontTable : NSObject
{
@public
NSMapTable *fontInfos;
}
- (void) addFontInfo: (RTFFontInfo *) theFontInfo
atIndex: (unsigned int ) theIndex;
- (RTFFontInfo *) fontInfoAtIndex: (unsigned int ) theIndex;
@end
//
//
//
@interface RTFColorDef : NSObject
{
@public
unsigned char red;
unsigned char green;
unsigned char blue;
}
@end
//
// {\colortbl\red0\green0\blue0;\red128\green0\blue0;\red255\green0\blue0;}
//
// \cfX - color/foreground - index
// \cbX - color/background - index
//
//
@interface RTFColorTable : NSObject
{
@public
NSMutableArray *colorDefs;
}
- (void) addColorDef: (RTFColorDef *) theColorDef;
@end
+961
View File
@@ -0,0 +1,961 @@
/*
Copyright (C) 2005-2013 Inverse inc.
This file is part of SOGo.
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.
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public
License along with OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
#include "RTFHandler.h"
#include <Foundation/NSValue.h>
//
// Useful macros
//
#define ADVANCE _bytes++; _current_pos++;
#define REWIND _bytes--; _current_pos--;
//
// Charset definitions. See http://msdn.microsoft.com/en-us/goglobal/bb964654 for all details.
//
const unsigned short ansicpg1250[256] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
0x20ac, 0x0000, 0x201a, 0x0000, 0x201e, 0x2026, 0x2020, 0x2021, 0x0000, 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179,
0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a,
0x00a0, 0x02c7, 0x02d8, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b,
0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c,
0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7, 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7, 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7, 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7, 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9 };
const unsigned short ansicpg1251[256] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
0x0402, 0x0403, 0x201a, 0x0453, 0x201e, 0x2026, 0x2020, 0x2021, 0x20ac, 0x2030, 0x0409, 0x2039, 0x040a, 0x040c, 0x040b, 0x040f,
0x0452, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0459, 0x203a, 0x045a, 0x045c, 0x045b, 0x045f,
0x00a0, 0x040e, 0x045e, 0x0408, 0x00a4, 0x0490, 0x00a6, 0x00a7, 0x0401, 0x00a9, 0x0404, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0407,
0x00b0, 0x00b1, 0x0406, 0x0456, 0x0491, 0x00b5, 0x00b6, 0x00b7, 0x0451, 0x2116, 0x0454, 0x00bb, 0x0458, 0x0405, 0x0455, 0x0457,
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f };
const unsigned short ansicpg1252[256] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
0x20ac, 0x0000, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017d, 0x0000,
0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x0000, 0x017e, 0x0178,
0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff };
const unsigned short ansicpg1253[256] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
0x20ac, 0x0000, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0000, 0x203a, 0x0000, 0x0000, 0x0000, 0x0000,
0x00a0, 0x0385, 0x0386, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x0000, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x2015,
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x0384, 0x00b5, 0x00b6, 0x00b7, 0x0388, 0x0389, 0x038a, 0x00bb, 0x038c, 0x00bd, 0x038e, 0x038f,
0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
0x03a0, 0x03a1, 0x0000, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af,
0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x0000 };
const unsigned short ansicpg1254[256] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
0x20ac, 0x0000, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x0000, 0x0000, 0x0178,
0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
0x011e, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x0130, 0x015e, 0x00df,
0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
0x011f, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x0131, 0x015f, 0x00ff };
const unsigned short ansicpg1255[256] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
0x20ac, 0x0000, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x02c6, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x02dc, 0x2122, 0x0000, 0x203a, 0x0000, 0x0000, 0x0000, 0x0000,
0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x20aa, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00d7, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00f7, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7, 0x05b8, 0x05b9, 0x0000, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf,
0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05f0, 0x05f1, 0x05f2, 0x05f3, 0x05f4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea, 0x0000, 0x0000, 0x200e, 0x200f, 0x0000 };
const unsigned short ansicpg1256[256] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
0x20ac, 0x067e, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x02c6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
0x06af, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x06a9, 0x2122, 0x0691, 0x203a, 0x0153, 0x200c, 0x200d, 0x06ba,
0x00a0, 0x060c, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x06be, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x061b, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x061f,
0x06c1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f,
0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00d7, 0x0637, 0x0638, 0x0639, 0x063a, 0x0640, 0x0641, 0x0642, 0x0643,
0x00e0, 0x0644, 0x00e2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x0649, 0x064a, 0x00ee, 0x00ef,
0x064b, 0x064c, 0x064d, 0x064e, 0x00f4, 0x064f, 0x0650, 0x00f7, 0x0651, 0x00f9, 0x0652, 0x00fb, 0x00fc, 0x200e, 0x200f, 0x06d2 };
const unsigned short ansicpg1257[256] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
0x20ac, 0x0000, 0x201a, 0x0000, 0x201e, 0x2026, 0x2020, 0x2021, 0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x00a8, 0x02c7, 0x00b8,
0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0000, 0x203a, 0x0000, 0x00af, 0x02db, 0x0000,
0x00a0, 0x0000, 0x00a2, 0x00a3, 0x00a4, 0x0000, 0x00a6, 0x00a7, 0x00d8, 0x00a9, 0x0156, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00c6,
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00f8, 0x00b9, 0x0157, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00e6,
0x0104, 0x012e, 0x0100, 0x0106, 0x00c4, 0x00c5, 0x0118, 0x0112, 0x010c, 0x00c9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012a, 0x013b,
0x0160, 0x0143, 0x0145, 0x00d3, 0x014c, 0x00d5, 0x00d6, 0x00d7, 0x0172, 0x0141, 0x015a, 0x016a, 0x00dc, 0x017b, 0x017d, 0x00df,
0x0105, 0x012f, 0x0101, 0x0107, 0x00e4, 0x00e5, 0x0119, 0x0113, 0x010d, 0x00e9, 0x017a, 0x0117, 0x0123, 0x0137, 0x012b, 0x013c,
0x0161, 0x0144, 0x0146, 0x00f3, 0x014d, 0x00f5, 0x00f6, 0x00f7, 0x0173, 0x0142, 0x015b, 0x016b, 0x00fc, 0x017c, 0x017e, 0x02d9 };
const unsigned short ansicpg1258[256] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
0x20ac, 0x0000, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x02c6, 0x2030, 0x0000, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x02dc, 0x2122, 0x0000, 0x203a, 0x0153, 0x0000, 0x0000, 0x0178,
0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
0x00c0, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x0300, 0x00cd, 0x00ce, 0x00cf,
0x0110, 0x00d1, 0x0309, 0x00d3, 0x00d4, 0x01a0, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x01af, 0x0303, 0x00df,
0x00e0, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x0301, 0x00ed, 0x00ee, 0x00ef,
0x0111, 0x00f1, 0x0323, 0x00f3, 0x00f4, 0x01a1, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x01b0, 0x20ab, 0x00ff };
const unsigned short ansicpg874[256] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
0x20ac, 0x0000, 0x0000, 0x0000, 0x0000, 0x2026, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x00a0, 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07, 0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f,
0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17, 0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f,
0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27, 0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f,
0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37, 0x0e38, 0x0e39, 0x0e3a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0e3f,
0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47, 0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0e4e, 0x0e4f,
0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57, 0x0e58, 0x0e59, 0x0e5a, 0x0e5b, 0x0000, 0x0000, 0x0000, 0x0000 };
//
//
//
@implementation RTFStack
- (id) init
{
if ((self = [super init]))
{
a = [[NSMutableArray alloc] init];
}
return self;
}
- (void) dealloc
{
RELEASE(a);
[super dealloc];
}
- (void) push: (id) theObject
{
[a addObject: theObject];
}
- (id) pop
{
id o = nil;
if ([a count])
{
o = AUTORELEASE([[a lastObject] retain]);
[a removeLastObject];
}
return o;
}
- (id) top
{
id o = nil;
if ([a count])
{
o = AUTORELEASE([[a lastObject] retain]);
}
return o;
}
@end
//
//
//
@implementation RTFFormattingOptions
@end
//
//
//
@implementation RTFFontInfo
- (id) init
{
if ((self = [super init]))
{
}
return self;
}
- (void) dealloc
{
RELEASE(family);
RELEASE(charset);
RELEASE(name);
[super dealloc];
}
@end
//
//
//
@implementation RTFFontTable
- (id) init
{
if ((self = [super init]))
{
fontInfos = NSCreateMapTable(NSObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 128);
}
return self;
}
- (void) dealloc
{
NSFreeMapTable(fontInfos);
[super dealloc];
}
- (void) addFontInfo: (RTFFontInfo *) theFontInfo
atIndex: (unsigned int) theIndex
{
NSNumber *key;
key = [NSNumber numberWithInt: theIndex];
NSMapInsert(fontInfos, key, (void*) theFontInfo);
}
- (RTFFontInfo *) fontInfoAtIndex: (unsigned int) theIndex
{
NSNumber *key;
key = [NSNumber numberWithInt: theIndex];
return NSMapGet(fontInfos, key);
}
@end
//
//
//
@implementation RTFColorDef
@end
//
//
//
@implementation RTFColorTable
- (id) init
{
if ((self = [super init]))
{
colorDefs = [[NSMutableArray alloc] init];
}
return self;
}
- (void) dealloc
{
RELEASE(colorDefs);
[super dealloc];
}
- (void) addColorDef: (RTFColorDef *) theColorDef
{
[colorDefs addObject: theColorDef];
}
- (RTFColorDef *) colorDefAtIndex: (unsigned int) theIndex
{
return [colorDefs objectAtIndex: theIndex];
}
@end
//
//
//
@implementation RTFHandler
- (id) initWithData: (NSData *) theData
{
if ((self = [super init]))
{
ASSIGN(_data, theData);
_bytes = (char *)[_data bytes];
_len = [_data length];
_current_pos = 0;
_charsets = NSCreateMapTable(NSObjectMapKeyCallBacks, NSNonOwnedPointerMapValueCallBacks, 10);
NSMapInsert(_charsets, @"ansicpg1250", ansicpg1250);
NSMapInsert(_charsets, @"ansicpg1251", ansicpg1251);
NSMapInsert(_charsets, @"ansicpg1252", ansicpg1252);
NSMapInsert(_charsets, @"ansicpg1253", ansicpg1253);
NSMapInsert(_charsets, @"ansicpg1254", ansicpg1254);
NSMapInsert(_charsets, @"ansicpg1255", ansicpg1255);
NSMapInsert(_charsets, @"ansicpg1256", ansicpg1256);
NSMapInsert(_charsets, @"ansicpg1257", ansicpg1257);
NSMapInsert(_charsets, @"ansicpg1258", ansicpg1258);
NSMapInsert(_charsets, @"ansicpg874", ansicpg874);
}
return self;
}
- (void) dealloc
{
NSFreeMapTable(_charsets);
RELEASE(_data);
[super dealloc];
}
- (const char *) parseControlWord: (unsigned int *) len
{
const char *start, *end;
start = ADVANCE;
while (isalnum(*_bytes) || *_bytes == '-')
{
ADVANCE;
}
end = _bytes;
*len = end-start-1;
return start+1;
}
//
// {\colortbl\red0\green0\blue0;\red128\green0\blue0;\red255\green0\blue0;}
//
- (RTFColorTable *) parseColorTable
{
RTFColorTable *colorTable;
RTFColorDef *colorDef;
colorTable = [[[RTFColorTable alloc] init] autorelease];
colorDef = [[[RTFColorDef alloc] init] autorelease];
while (*_bytes != '}')
{
if (*_bytes == ';')
{
[colorTable addColorDef: colorDef];
colorDef = [[[RTFColorDef alloc] init] autorelease];
ADVANCE;
}
else if (*_bytes == '\\')
{
const char *cw;
unsigned int len;
NSString *s;
cw = [self parseControlWord: &len];
// Skip our control word
//if (strncmp(start+1, "colortbl", len) == 0)
// continue;
s = [[NSString alloc] initWithBytesNoCopy: (void *)cw
length: len
encoding: NSASCIIStringEncoding
freeWhenDone: NO];
[s autorelease];
if ([s hasPrefix: @"red"])
{
colorDef->red = [[s substringFromIndex: 3] intValue];
}
else if ([s hasPrefix: @"green"])
{
colorDef->green = [[s substringFromIndex: 4] intValue];
}
else
{
colorDef->blue = [[s substringFromIndex: 4] intValue];
}
}
else
{
ADVANCE;
}
}
return colorTable;
}
//
// Possible formats:
//
// {\fonttbl\f0\fswiss Helvetica;}
// {\fonttbl{\f0\froman\fcharset0\fprq2 Arial;}{\f1\fswiss\fprq2\fcharset0 Arial;}}
//
// FIXME: Complex ones not handled right now:
//
// {\fonttbl{\f2\fnil\fcharset256\fprq2{\*\panose 00020703090202050204}Courier New;}{...
// {\fonttbl{\f31\fnil\fcharset0\fprq0 Times New Roman Monotype{\*\falt Times New Roman};}{...
//
// We receive the full string.
//
- (RTFFontTable *) parseFontTable
{
NSMutableString *fontName;
RTFFontTable *fontTable;
RTFFontInfo *fontInfo;
unsigned int count;
fontTable = [[[RTFFontTable alloc] init] autorelease];
fontName = nil;
count = 0;
do
{
if (*_bytes == '{')
{
if (fontTable)
{
fontInfo = [[[RTFFontInfo alloc] init] autorelease];
fontName = [[[NSMutableString alloc] init] autorelease];
}
ADVANCE;
count++;
}
else if (*_bytes == '}')
{
if (fontTable) //&& ![NSAllMapTableValues(fontTable->fontInfos) containsObject: fontInfo])
{
ASSIGN(fontInfo->name, fontName);
[fontTable addFontInfo: fontInfo atIndex: fontInfo->index];
}
ADVANCE;
count--;
}
else if (*_bytes == '\\')
{
const char *cw;
unsigned int len;
NSString *s;
cw = [self parseControlWord: &len];
// 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
encoding: NSASCIIStringEncoding
freeWhenDone: NO];
[s autorelease];
// If we got a fontnum, let's parse all three fields at once)
if (isdigit(*(cw+1)))
{
fontInfo->index = [s intValue];
// We now parse <fontfamily><fcharset>
cw = [self parseControlWord: &len];
fontInfo->family = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1
length: len-1
encoding: NSASCIIStringEncoding
freeWhenDone: NO];
cw = [self parseControlWord: &len];
fontInfo->charset = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1
length: len-1
encoding: NSASCIIStringEncoding
freeWhenDone: NO];
// We now skip everything until we find our final group closer ('}')
int cc = 1;
do
{
if (*_bytes == '{')
cc++;
if (*_bytes == '}')
cc--;
ADVANCE;
}
while (cc != 0);
// move back our buffer;
REWIND;
}
}
else
{
if (isalnum(*_bytes))
[fontName appendFormat: @"%c", *_bytes];
ADVANCE;
}
} while (count != 0);
return fontTable;
}
//
//
//
- (void) parseStyleSheet
{
unsigned int count;
count = 0;
do
{
if (*_bytes == '{')
{
count++;
}
else if (*_bytes == '}')
{
count--;
}
ADVANCE;
} while (count != 0);
}
//
//
//
- (void) parsePicture
{
// Do the same as -parseStyleSheet for now, that is, ignore everything.
[self parseStyleSheet];
}
//
//
//
- (NSMutableData *) parse
{
RTFFormattingOptions *formattingOptions;
RTFColorTable *colorTable;
RTFFontTable *fontTable;
RTFStack *stack;
unsigned short *charset;
char c;
stack = [[RTFStack alloc] init];
fontTable = nil;
colorTable = nil;
charset = NULL;
_html = [[NSMutableData alloc] init];
[_html appendBytes: "<html><meta charset='utf-8'><body>" length: 34];
// Check if we got RTF data
if (_len > 4 && strncmp((const char*)_bytes, "{\\rtf", 4) != 0)
return NO;
while (_current_pos < _len)
{
c = *_bytes;
// RTF control code
if (c == '\\')
{
unsigned int len;
const char *cw;
NSString *s;
if (*(_bytes+1) == '\'' && charset)
{
// A hexadecimal value, based on the specified character set (may be used to identify 8-bit values).
NSString *s;
NSData *d;
const char *b1, *b2;
unsigned short index;
ADVANCE;
ADVANCE;
b1 = ADVANCE;
b2 = ADVANCE;
index = (isdigit(*b1) ? *b1 - 48 : toupper(*b1) - 55) * 16;
index += (isdigit(*b2) ? *b2 - 48 : toupper(*b2) - 55);
s = [NSString stringWithCharacters: &(charset[index]) length: 1];
d = [s dataUsingEncoding: NSUTF8StringEncoding];
[_html appendData: d];
continue;
}
else if (*(_bytes+1) == '*')
{
int cc = 1;
do
{
if (*_bytes == '{')
cc++;
if (*_bytes == '}')
cc--;
ADVANCE;
}
while (cc != 0);
continue;
}
cw = [self parseControlWord: &len];
s = [[NSString alloc] initWithBytesNoCopy: (void *)cw
length: len
encoding: NSASCIIStringEncoding
freeWhenDone: NO];
[s autorelease];
if (strncmp(cw, "ansicpg", 7) == 0)
{
charset = NSMapGet(_charsets, s);
}
else if (strncmp(cw, "fonttbl", 7) == 0)
{
// We rewind our buffer so we start at the beginning of {\fonttbl...
_bytes = cw-2;
_current_pos -= 10;
fontTable = [self parseFontTable];
// 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;
[self parseStyleSheet];
REWIND;
}
else if (strncmp(cw, "colortbl", 8) == 0)
{
colorTable = [self parseColorTable];
}
else if (strncmp(cw, "pict", 4) == 0)
{
_bytes = cw-2;
_current_pos -= 7;
[self parsePicture];
REWIND;
}
else if ([s isEqualToString: @"b"] && formattingOptions)
{
[_html appendBytes: "<b>" length: 3];
formattingOptions->bold = YES;
}
else if ([s isEqualToString: @"b0"] && formattingOptions)
{
[_html appendBytes: "</b>" length: 4];
formattingOptions->bold = NO;
}
else if ([s hasPrefix: @"cf"] && [s length] > 2)
{
RTFColorDef *colorDef;
int color_index;
char *v;
color_index = [[s substringFromIndex: 2] intValue];
if (!formattingOptions)
continue;
if (formattingOptions->color_index >= 0) // && color_index != formattingOptions->color_index)
{
[_html appendBytes: "</font>" length: 7];
}
formattingOptions->color_index = color_index;
colorDef = [colorTable colorDefAtIndex: color_index];
v = malloc(23*sizeof(char));
memset(v, 0, 23);
sprintf(v, "<font color=\"#%02x%02x%02x\">", colorDef->red, colorDef->green, colorDef->blue);
[_html appendBytes: v length: strlen(v)];
free(v);
}
else if ([s hasPrefix: @"fcs"])
{
// ignore
}
else if ([s hasPrefix: @"fs"])
{
// ignore
}
else if ([s hasPrefix: @"fbidis"])
{
// ignore
}
else if ([s hasPrefix: @"fromhtml"])
{
// ignore
}
else if ([s hasPrefix: @"fromtext"])
{
// ignore
}
else if ([s hasPrefix: @"f"] && [s length] > 1)
{
RTFFontInfo *fontInfo;
int font_index;
font_index = [[s substringFromIndex: 1] intValue];
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]);
[_html appendBytes: v length: strlen(v)];
free(v);
}
else if ([s isEqualToString: @"i"] && formattingOptions)
{
[_html appendBytes: "<i>" length: 3];
formattingOptions->italic = YES;
}
else if ([s isEqualToString: @"i0"] && formattingOptions)
{
[_html appendBytes: "</i>" length: 4];
formattingOptions->italic = NO;
}
else if ([s isEqualToString: @"tab"])
{
[_html appendBytes: "&nbsp;&nbsp;" length: 12];
}
else if ([s isEqualToString: @"softline"] || [s isEqualToString: @"par"])
{
[_html appendBytes: "<br>" length: 4];
}
else if ([s isEqualToString: @"strike"] && formattingOptions)
{
[_html appendBytes: "<strike>" length: 8];
formattingOptions->strikethrough = YES;
}
else if ([s isEqualToString: @"strike0"] && formattingOptions)
{
[_html appendBytes: "</strike>" length: 9];
formattingOptions->strikethrough = NO;
}
else if ([s hasPrefix: @"u"] && [s length] > 1 && isdigit([s characterAtIndex: 1]))
{
NSData *d;
unichar ch;
ch = (unichar)[[s substringFromIndex: 1] intValue];
s = [NSString stringWithCharacters: &ch length: 1];
d = [s dataUsingEncoding: NSUTF8StringEncoding];
[_html appendData: d];
}
else if ([s isEqualToString: @"ul"] && formattingOptions)
{
[_html appendBytes: "<u>" length: 3];
formattingOptions->underline = YES;
}
else if (([s isEqualToString: @"ul0"] || [s isEqualToString: @"ulnone"])
&& formattingOptions)
{
[_html appendBytes: "</u>" length: 4];
formattingOptions->underline = NO;
}
// If a space delimits the control word, the space does not appear in the document.
// Any characters following the delimiter, including spaces, will appear in the document.
if (*_bytes == ' ')
{
ADVANCE;
}
}
else if (c == '{')
{
formattingOptions = [[[RTFFormattingOptions alloc] init] autorelease];
formattingOptions->bold = NO;
formattingOptions->italic = NO;
formattingOptions->strikethrough = NO;
formattingOptions->underline = NO;
formattingOptions->font_index = -1;
formattingOptions->color_index = -1;
formattingOptions->start_pos = [_html length];
[stack push: formattingOptions];
ADVANCE;
}
else if (c == '}')
{
formattingOptions = [stack pop];
if (formattingOptions)
{
// Handle {\b bold} vs. \b bold \b0
if (formattingOptions->bold)
{
[_html appendBytes: "</b>" length: 4];
}
if (formattingOptions->italic)
{
[_html appendBytes: "</i>" length: 4];
}
if (formattingOptions->strikethrough)
{
[_html appendBytes: "</strike>" length: 9];
}
if (formattingOptions->underline)
{
[_html appendBytes: "</u>" length: 4];
}
if (formattingOptions->font_index >= 0)
{
[_html appendBytes: "</font>" length: 7];
}
if (formattingOptions->color_index >= 0)
{
[_html appendBytes: "</font>" length: 7];
}
}
formattingOptions = [stack top];
ADVANCE;
}
else
{
// We avoid appending NULL bytes
if (*_bytes)
[_html appendBytes: _bytes length: 1];
ADVANCE;
}
}
[_html appendBytes: "</body></html>" length: 14];
RELEASE(stack);
return AUTORELEASE(_html);
}
@end
+9 -16
View File
@@ -46,6 +46,7 @@
#import "GCSSpecialQueries+OpenChange.h"
#import "MAPIStoreTypes.h"
#import "SOGoMAPIDBFolder.h"
#import "BSONCodec.h"
#import "SOGoMAPIDBObject.h"
@@ -156,9 +157,9 @@ static EOAttribute *textColumn = nil;
- (void) setupFromRecord: (NSDictionary *) record
{
NSInteger intValue;
NSString *propsValue, *error;
NSString *propsValue;//, *error;
NSDictionary *newValues;
NSPropertyListFormat format;
//NSPropertyListFormat format;
objectType = [[record objectForKey: @"c_type"] intValue];
intValue = [[record objectForKey: @"c_creationdate"] intValue];
@@ -174,13 +175,8 @@ static EOAttribute *textColumn = nil;
propsValue = [record objectForKey: @"c_content"];
if ([propsValue isNotNull])
{
newValues = [NSPropertyListSerialization propertyListFromData: [propsValue dataByDecodingBase64]
mutabilityOption: NSPropertyListMutableContainers
format: &format
errorDescription: &error];
newValues = [[propsValue dataByDecodingBase64] BSONValue];
[properties addEntriesFromDictionary: newValues];
// [properties addEntriesFromDictionary: [propsValue
// objectFromJSONString]];
}
else
[properties removeAllObjects];
@@ -255,13 +251,13 @@ static EOAttribute *textColumn = nil;
className = @"MAPIStoreNotesMessage";
else
className = @"MAPIStoreDBMessage";
[self logWithFormat: @"PidTagMessageClass = '%@', returning '%@'",
mapiMsgClass, className];
//[self logWithFormat: @"PidTagMessageClass = '%@', returning '%@'",
// mapiMsgClass, className];
}
else
{
[self warnWithFormat: @"PidTagMessageClass is not set, falling back"
@" to 'MAPIStoreDBMessage'"];
//[self warnWithFormat: @"PidTagMessageClass is not set, falling back"
// @" to 'MAPIStoreDBMessage'"];
className = @"MAPIStoreDBMessage";
}
break;
@@ -526,10 +522,7 @@ static EOAttribute *textColumn = nil;
if ([properties count] > 0)
{
content = [NSPropertyListSerialization
dataFromPropertyList: properties
format: plistFormat
errorDescription: NULL];
content = [properties BSONRepresentation];
propsValue = [adaptor formatValue: [content stringByEncodingBase64]
forAttribute: textColumn];
}
+84
View File
@@ -0,0 +1,84 @@
#!/usr/bin/python
import getopt
import os
import re
import string
import sys
h_template = """unsigned short %(charsetName)s[%(len)d] = { %(values)s };"""
CHAR_UNDEF = "0x0000"
MAP_LEN = 256
itemsPerLine = 16
def usage():
usageMsg = """
Usage: %s -f inputFile
""" % (os.path.basename(sys.argv[0]))
sys.stderr.write(usageMsg)
def parseCharsetFile(file = None):
if file is None:
return None
charmap = [CHAR_UNDEF] * MAP_LEN
# Sample line:
# FD = U+200E : LEFT-TO-RIGHT MARK
for line in file.xreadlines():
m = re.search("(\w{2}) = U\+(\w{4}) :", line)
if not m:
sys.stderr.write("Skipping weird line: %s" % line)
continue
ind = int(m.group(1), base=16)
unicodeValue = str(m.group(2)).lower()
charmap[ind] = "0x%s" % (unicodeValue)
return charmap
def formatCharacterMap(charmap = None):
if not charmap:
return None
value = ""
for i in xrange(0,MAP_LEN-1):
char = charmap[i]
if i % itemsPerLine == 0:
value += "\n "
value += "%s, " % (char)
i += 1
value += charmap[MAP_LEN-1]
return value
if __name__ == '__main__':
inputFile = None
try:
opts, args = getopt.getopt(sys.argv[1:], "f:")
except getopt.GetoptError, err:
sys.stderr.write(str(err))
usage()
sys.exit(2)
for o, a in opts:
if o == "-f":
inputFile = a
else:
assert False, "unhandled option"
if not inputFile:
usage()
sys.exit(1)
f = open(inputFile, "r", 1)
charsetMap = parseCharsetFile(f)
charsetValues = formatCharacterMap(charsetMap)
print h_template % {"len": len(charsetMap),
"charsetName": os.path.basename(inputFile),
"values": charsetValues}
+4 -2
View File
@@ -23,6 +23,8 @@
#ifndef ICALEVENT_MAPISTORE_H
#define ICALEVENT_MAPISTORE_H
#include <talloc.h>
#import <NGCards/iCalEvent.h>
@class MAPIStoreUserContext;
@@ -34,8 +36,8 @@
- (void) updateFromMAPIProperties: (NSDictionary *) properties
inUserContext: (MAPIStoreUserContext *) userContext
withActiveUser: (SOGoUser *) activeUser;
withActiveUser: (SOGoUser *) activeUser
inMemCtx: (TALLOC_CTX *) memCtx;
@end
#endif /* ICALEVENT_MAPISTORE_H */
+6 -5
View File
@@ -20,7 +20,6 @@
* Boston, MA 02111-1307, USA.
*/
#include <talloc.h>
#include <util/attr.h>
#import <Foundation/NSArray.h>
@@ -75,16 +74,17 @@
@implementation iCalEvent (MAPIStoreProperties)
- (void) _setupEventRecurrence: (NSData *) mapiRecurrenceData
inMemCtx: (TALLOC_CTX *) memCtx
{
struct Binary_r *blob;
struct AppointmentRecurrencePattern *pattern;
blob = [mapiRecurrenceData asBinaryInMemCtx: NULL];
pattern = get_AppointmentRecurrencePattern (blob, blob);
blob = [mapiRecurrenceData asBinaryInMemCtx: memCtx];
pattern = get_AppointmentRecurrencePattern (memCtx, blob);
[(iCalCalendar *) parent
setupRecurrenceWithMasterEntity: self
fromRecurrencePattern: &pattern->RecurrencePattern];
talloc_free (blob);
//talloc_free (blob);
}
- (void) _setupEventAlarmFromProperties: (NSDictionary *) properties
@@ -134,6 +134,7 @@
- (void) updateFromMAPIProperties: (NSDictionary *) properties
inUserContext: (MAPIStoreUserContext *) userContext
withActiveUser: (SOGoUser *) activeUser
inMemCtx: (TALLOC_CTX *) memCtx
{
BOOL isAllDay;
iCalDateTime *start, *end;
@@ -328,7 +329,7 @@
value = [properties
objectForKey: MAPIPropertyKey (PidLidAppointmentRecur)];
if (value)
[self _setupEventRecurrence: value];
[self _setupEventRecurrence: value inMemCtx: memCtx];
/* alarm */
[self _setupEventAlarmFromProperties: properties];
File diff suppressed because it is too large. Load diff
Binary file not shown.
-75
View File
@@ -1,75 +0,0 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the <ctype.h> header file. */
#define HAVE_CTYPE_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#define HAVE_MALLOC 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdio.h> header file. */
#define HAVE_STDIO_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strchr' function. */
#define HAVE_STRCHR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strstr' function. */
#define HAVE_STRSTR 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Name of package */
#define PACKAGE "unrtf"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "bug-unrtf@gnu.org"
/* Define to the full name of this package. */
#define PACKAGE_NAME "unrtf"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "unrtf 0.21.2"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "unrtf"
/* Define to the version of this package. */
#define PACKAGE_VERSION "0.21.2"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "0.21.2"
/* Define to rpl_malloc if the replacement function should be used. */
/* #undef malloc */
+1 -1
View File
@@ -27,7 +27,7 @@
#import "EOQualifier+GCS.h"
#if __GNU_LIBOBJC__ >= 20100911
#if (defined(__GNU_LIBOBJC__) && (__GNU_LIBOBJC__ >= 20100911)) || defined(APPLE_RUNTIME) || defined(__GNUSTEP_RUNTIME__)
# define sel_eq(__A__,__B__) sel_isEqual(__A__,__B__)
#endif
+1 -1
View File
@@ -44,7 +44,7 @@
#import "EOQualifier+GCS.h"
#import "GCSStringFormatter.h"
#if __GNU_LIBOBJC__ >= 20100911
#if (defined(__GNU_LIBOBJC__) && (__GNU_LIBOBJC__ >= 20100911)) || defined(APPLE_RUNTIME) || defined(__GNUSTEP_RUNTIME__)
# define sel_eq(__A__,__B__) sel_isEqual(__A__,__B__)
#endif
+34 -13
View File
@@ -155,20 +155,41 @@
- (NSString *) escapedForCards
{
NSString *string;
NSMutableString *string;
unsigned int len, i;
unichar c;
string = [self stringByReplacingString: @"\\"
withString: @"\\\\"];
string = [string stringByReplacingString: @","
withString: @"\\,"];
// string = [string stringByReplacingString: @":"
// withString: @"\\:"];
string = [string stringByReplacingString: @";"
withString: @"\\;"];
string = [string stringByReplacingString: @"\n"
withString: @"\\n"];
string = [string stringByReplacingString: @"\r"
withString: @"\\r"];
len = [self length];
string = [NSMutableString stringWithCapacity: len * 1.5];
for (i = 0; i < len; i++)
{
c = [self characterAtIndex: i];
switch (c)
{
case '\\':
[string appendString: @"\\\\"];
break;
case ',':
[string appendString: @"\\,"];
break;
//case ':':
// [string appendString: @"\\:"];
//break;
case ';':
[string appendString: @"\\;"];
break;
case'\n':
[string appendString: @"\\n"];
break;
case'\r':
[string appendString: @"\\r"];
break;
default:
[string appendFormat: @"%C", c];
}
}
return string;
}
+5 -4
View File
@@ -330,14 +330,15 @@ lastPossibleRecurrenceStartDateUsingFirstInstanceCalendarDateRange: (NGCalendarD
rRules = [[self recurrenceRules] objectEnumerator];
rule = [rRules nextObject];
while (rule && ![rule isInfinite] & !date)
while (rule && ![rule isInfinite] && !date)
{
calc = [iCalRecurrenceCalculator
recurrenceCalculatorForRecurrenceRule: rule
withFirstInstanceCalendarDateRange: _r];
withFirstInstanceCalendarDateRange: _r];
rdate = [[calc lastInstanceCalendarDateRange] startDate];
if (!date
|| ([date compare: rdate] == NSOrderedAscending))
if (!rdate)
date = [_r startDate];
else if (!date || ([date compare: rdate] == NSOrderedAscending))
date = rdate;
else
rule = [rRules nextObject];
+1 -1
View File
@@ -72,7 +72,7 @@
- (void) setCompleted: (NSCalendarDate *) newCompletedDate
{
[(iCalDateTime *) [self uniqueChildWithTag: @"completed"]
setDate: newCompletedDate];
setDateTime: newCompletedDate];
if (newCompletedDate)
[self setStatus: @"COMPLETED"];
else
+20
View File
@@ -0,0 +1,20 @@
# /etc/fail2ban/filter.d/sogo.conf
#
# Fail2Ban configuration file
# By Arnd Brandes
# SOGo
#
[Definition]
# Option: failregex
# Filter Ban in /var/log/sogo/sogo.log
# Note: the error log may contain multiple hosts, whereas the first one
# is the client and all others are poxys. We match the first one, only
failregex = Login from '<HOST>.*' for user '.*' might not have worked
# Option: ignoreregex
# Notes.: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =
+9
View File
@@ -0,0 +1,9 @@
[SOGo]
enabled = true
port = http,https
# in proxy-free setup this would be:
# port = 20000
filter = sogo
logpath = /var/log/sogo/sogo.log
maxretry = 5
@@ -2,7 +2,7 @@
import getopt
import imaplib
#import ldb
import ldb
import plistlib
import os
import re
@@ -16,7 +16,7 @@ imapport = 143
sambaprivate = '/var/lib/samba/private'
mapistorefolder = "%s/mapistore" % (sambaprivate)
sogoSysDefaultsFile = "/etc/sogo/sogo.conf"
sogoUserDefaultsFile = "/home/sogo/GNUstep/Defaults/.GNUstepDefaults"
sogoUserDefaultsFile = os.path.expanduser("~sogo/GNUstep/Defaults/.GNUstepDefaults")
# - takes a username and optionally its password
# - removes the entry in samba's ldap tree via ldbedit (NOTYET)
@@ -79,13 +79,25 @@ def main():
except (shutil.Error, OSError) as e:
print "Error during mapistoreCleanup, continuing: %s" % str(e)
# try:
# pass
# #ldbCleanup(sambaprivate, username)
# except ldb.LdbError as e:
# print "Error during ldbCleanup, continuing: %s" % str(e)
try:
ldbCleanup(sambaprivate, username)
except ldb.LdbError as e:
print "Error during ldbCleanup, continuing: %s" % str(e)
sqlCleanup(username)
try:
sqlCleanup(username)
except Exception as e:
print "Error during sqlCleanup, continuing: %s" % str(e)
def getsep(client):
seq = None
(code, data) = client.list("", "")
if code == "OK" and data is not None:
# yes this is ugly but it works on cyrus and dovecot.
# (\\Noinferiors \\HasNoChildren) "/" INBOX
m = re.search(".*\s+[\"\']?(.)[\"\']?\s+[\"\']?.*[\"\']?$", data[0])
sep = m.group(1)
return sep
def extractmb(si):
inparen = False
@@ -118,13 +130,13 @@ def extractmb(si):
return parts[-1]
def cleanupmb(mb, client):
(code, data) = client.list("%s/" % mb, "%")
def cleanupmb(mb, sep, client):
(code, data) = client.list("%s%s" % (mb, sep), "%")
if code == "OK":
for si in data:
if si is not None:
submb = extractmb(si)
cleanupmb(submb, client)
cleanupmb(submb, sep, client)
else:
raise Exception, "Failure while cleaning up '%s'" % mb
client.unsubscribe(mb)
@@ -135,6 +147,7 @@ def cleanupmb(mb, client):
print "mailbox '%s' coult NOT be deleted (code = '%s')" % (mb, code)
def imapCleanup(imaphost, imapport, username, userpass):
print "Starting IMAP cleanup"
client = imaplib.IMAP4(imaphost, imapport)
(code, data) = client.login(username, userpass)
if code != "OK":
@@ -142,34 +155,60 @@ def imapCleanup(imaphost, imapport, username, userpass):
print "Logged in as '%s'" % username
for foldername in ("Sync Issues", "Junk E-mail"):
sep = getsep(client)
if not sep:
client.logout()
return
for foldername in ("Sync Issues", "Junk E-mail",
"INBOX%sSync Issues" % sep, "INBOX%sJunk E-mail" % sep,
"Probl&AOg-mes de synchronisation"):
(code, data) = client.list(foldername, "%")
if code == "OK":
for si in data:
if si is not None:
mb = extractmb(si)
cleanupmb(mb, client)
cleanupmb(mb, sep, client)
client.logout()
def mapistoreCleanup(mapistorefolder, username):
print "Starting MAPIstore cleanup"
# delete the user's folder under the mapistore and under mapistore/SOGo
shutil.rmtree("%s/%s" % (mapistorefolder, username), ignore_errors=True)
mapistoreUserDir = "%s/%s" % (mapistorefolder, username)
for dirpath, dirnames, filenames in os.walk(mapistoreUserDir):
for f in filenames:
if f != "password":
os.unlink("%s/%s" % (dirpath,f))
break #one level only
shutil.rmtree("%s/SOGo/%s" % (mapistorefolder, username), ignore_errors=True)
# NOTYET
#def ldbCleanup(sambaprivate, username):
# conn = ldb.Ldb("%s/openchange.ldb" % (sambaprivate))
#### entries = conn.search(None, expression="(|(cn=%s)(MAPIStoreURI=sogo://%s:*)(MAPIStoreURI=sogo://%s@*))" % (username,username,username),
# entries = conn.search(None, expression="cn=%s" % (username),
# scope=ldb.SCOPE_SUBTREE)
# for entry in entries:
# print "Deleting %s" % (entry.dn)
# conn.delete(entry.dn)
def ldbCleanup(sambaprivate, username):
conn = ldb.Ldb("%s/openchange.ldb" % (sambaprivate))
# find the DN of the user
entries = conn.search(None, expression="(cn=%s)" % (username), scope=ldb.SCOPE_SUBTREE)
if not entries:
print "cn = %s not found in openchange.ldb" %(username)
return
for entry in entries:
# search again, but with the user's DN as a base
subentries = conn.search(entry.dn.extended_str(), expression="(distinguishedName=*)", scope=ldb.SCOPE_SUBTREE)
for subentry in subentries:
print "Deleting %s" % (subentry.dn)
conn.delete(subentry.dn)
def mysqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, username):
import MySQLdb
try:
import MySQLdb
except ImportError:
msg ="""The python 'MySQLdb' module is not available
On Debian based distro, install it using 'apt-get install python-mysqlbd'
On RHEL, install it using 'yum install MySQL-python'"""
raise Exception(msg)
conn= MySQLdb.connect(host=dbhost, port=int(dbport), user=dbuser, passwd=dbpass, db=dbname)
conn = MySQLdb.connect(host=dbhost, port=int(dbport), user=dbuser, passwd=dbpass, db=dbname)
c=conn.cursor()
tablename="socfs_%s" % (username)
c.execute("TRUNCATE TABLE %s" % tablename)
@@ -177,28 +216,38 @@ def mysqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, username):
def postgresqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, username):
import pg
try:
import pg
except ImportError:
msg ="""The python 'pg' module is not available
On Debian based distro, install it using 'apt-get install python-pygresql'
On RHEL, install it using 'yum install python-pgsql'"""
raise Exception(msg)
conn = pg.connect(host=dbhost, port=int(dbport), user=dbuser, passwd=dbpass, dbname=dbname)
tablename = "socfs_%s" % username
conn.query("DELETE FROM %s" % tablename)
print "table '%s' emptied" % tablename
print "Table '%s' emptied" % tablename
def getOCSFolderInfoURL():
global sogoSysDefaultsFile, sogoUserDefaultsFile
OCSFolderInfoURL = ""
# read defaults from /etc/sogo/sogo.conf
if os.path.exists(sogoSysDefaultsFile):
sogoDefaults = plistlib.readPlist(sogoSysDefaultsFile)
if "OCSFolderInfoURL" in sogoDefaults:
OCSFolderInfoURL = sogoDefaults["OCSFolderInfoURL"]
# read defaults from defaults files
# order is important, user defaults must have precedence
for f in [sogoSysDefaultsFile, sogoUserDefaultsFile]:
if os.path.exists(f):
# FIXME: this is ugly, we should have a python plist parser
# plistlib only supports XML plists.
# the following magic replaces this shell pipeline:
# sogo-tool dump-defaults -f %s | awk -F\\" '/ OCSFolderInfoURL =/ {print $2}'
p1 = subprocess.Popen(["sogo-tool", "dump-defaults", "-f", f], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["awk", "-F\"", "/ OCSFolderInfoURL =/ {print $2}"], stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits.
tmp = p2.communicate()[0]
# defaults from user directory must have precedence
if os.path.exists(sogoUserDefaultsFile):
sogoDefaults = plistlib.readPlist(sogoUserDefaultsFile)
if "sogod" in sogoDefaults and "OCSFolderInfoURL" in sogoDefaults["sogod"]:
OCSFolderInfoURL = sogoDefaults['sogod']['OCSFolderInfoURL']
if tmp: OCSFolderInfoURL = tmp
return OCSFolderInfoURL
@@ -226,6 +275,7 @@ def asCSSIdentifier(inputString):
return "".join(newChars)
def sqlCleanup(username):
print "Starting SQL cleanup"
OCSFolderInfoURL = getOCSFolderInfoURL()
if OCSFolderInfoURL is None:
raise Exception("Couldn't fetch OCSFolderInfoURL or it is not set. the socfs_%s table should be truncated manually" % (username))
@@ -233,6 +283,9 @@ def sqlCleanup(username):
# postgresql://sogo:sogo@127.0.0.1:5432/sogo/sogo_folder_info
m = re.search("(.+)://(.+):(.+)@(.+):(\d+)/(.+)/(.+)", OCSFolderInfoURL)
if not m:
raise Exception("Unable to parse OCSFolderInfoURL: %s" % OCSFolderInfoURL)
proto = m.group(1)
dbuser = m.group(2)
dbpass = m.group(3)
@@ -248,7 +301,7 @@ def sqlCleanup(username):
elif (proto == "mysql"):
mysqlCleanup(dbhost, dbport, dbuser, dbpass, dbname, encodedUserName)
else:
raise Exception("Unknown sql proto: " % (proto))
raise Exception("Unknown sql proto: %s" % (proto))
if __name__ == "__main__":
main()
+1 -1
View File
@@ -4,7 +4,7 @@ set -o pipefail
#set -x
PROGNAME="$(basename $0)"
BACKUP_DIR=/home/sogo/backups
BACKUP_DIR=~sogo/backups
SOGO_TOOL=/usr/sbin/sogo-tool
DAYS_TO_KEEP="30"
+2 -2
View File
@@ -1,5 +1,5 @@
# The amount of processes that should be spawned (Default: 1)
# PREFORK=1
# The amount of processes that should be spawned (Default: 3)
# PREFORK=3
# The name of the account under which SOGo will be running (Default: sogo)
# USER=sogo
+1 -1
View File
@@ -34,7 +34,7 @@ DAEMON=/usr/sbin/sogod
DESC="SOGo"
USER=$NAME
PREFORK=1
PREFORK=3
PIDFILE=/var/run/$NAME/$NAME.pid
LOGFILE=/var/log/$NAME/$NAME.log
+1 -1
View File
@@ -37,7 +37,7 @@ DAEMON=/usr/sbin/sogod
DESC="SOGo"
USER=$NAME
PREFORK=1
PREFORK=3
PIDFILE=/var/run/$NAME/$NAME.pid
LOGFILE=/var/log/$NAME/$NAME.log
+109
View File
@@ -0,0 +1,109 @@
{
/* ********************* Main SOGo configuration file **********************
* *
* Since the content of this file is a dictionary in OpenStep plist format, *
* the curly braces enclosing the body of the configuration are mandatory. *
* See the Installation Guide for details on the format. *
* *
* C and C++ style comments are supported. *
* *
* This example configuration contains only a subset of all available *
* configuration parameters. Please see the installation guide more details. *
* *
* ~sogo/GNUstep/Defaults/.GNUstepDefaults has precedence over this file, *
* make sure to move it away to avoid unwanted parameter overrides. *
* *
* **************************************************************************/
/* Database configuration (mysql:// or postgresql://) */
//SOGoProfileURL = "postgresql://sogo:sogo@localhost:5432/sogo/sogo_user_profile";
//OCSFolderInfoURL = "postgresql://sogo:sogo@localhost:5432/sogo/sogo_folder_info";
//OCSSessionsFolderURL = "postgresql://sogo:sogo@localhost:5432/sogo/sogo_sessions_folder";
/* Mail */
//SOGoDraftsFolderName = Drafts;
//SOGoSentFolderName = Sent;
//SOGoTrashFolderName = Trash;
//SOGoIMAPServer = localhost;
//SOGoSieveServer = sieve://127.0.0.1:4190;
//SOGoSMTPServer = 127.0.0.1;
//SOGoMailDomain = acme.com;
//SOGoMailingMechanism = smtp;
//SOGoForceExternalLoginWithEmail = NO;
//SOGoMailSpoolPath = /var/spool/sogo;
//NGImap4ConnectionStringSeparator = "/";
//SOGoAppointmentSendEMailNotifications = NO;
//SOGoACLsSendEMailNotifications = NO;
/* Authentication */
//SOGoPasswordChangeEnabled = YES;
/* LDAP authentication example */
//SOGoUserSources = (
// {
// type = ldap;
// CNFieldName = cn;
// UIDFieldName = uid;
// IDFieldName = uid; // first field of the DN for direct binds
// bindFields = (uid, mail); // array of fields to use for indirect binds
// baseDN = "ou=users,dc=acme,dc=com";
// bindDN = "uid=sogo,ou=users,dc=acme,dc=com";
// bindPassword = qwerty;
// canAuthenticate = YES;
// displayName = "Shared Addresses";
// hostname = ldap://127.0.0.1:389;
// id = public;
// isAddressBook = YES;
// }
//);
/* SQL authentication example */
/* These database columns MUST be present in the view/table:
* c_uid - will be used for authentication - it's the username or username@domain.tld)
* c_name - which can be identical to c_uid - will be used to uniquely identify entries
* c_password - password of the user, plain-text, md5 or sha encoded for now
* c_cn - the user's common name - such as "John Doe"
* mail - the user's mail address
* See the installation guide for more details
*/
//SOGoUserSources =
// (
// {
// type = sql;
// id = directory;
// viewURL = "postgresql://sogo:sogo@127.0.0.1:5432/sogo/sogo_view";
// canAuthenticate = YES;
// isAddressBook = YES;
// userPasswordAlgorithm = md5;
// }
// );
/* Web Interface */
//SOGoPageTitle = SOGo;
//SOGoVacationEnabled = YES;
//SOGoForwardEnabled = YES;
//SOGoSieveScriptsEnabled = YES;
//SOGoMailAuxiliaryUserAccountsEnabled = YES;
/* General */
//SOGoLanguage = English;
//SOGoTimeZone = America/Montreal;
//SOGoCalendarDefaultRoles = (
// PublicDAndTViewer,
// ConfidentialDAndTViewer
//);
//SOGoSuperUsernames = (sogo1, sogo2); // This is an array - keep the parens!
//SxVMemLimit = 384
/* Debug */
//SOGoDebugRequests = YES;
//SoDebugBaseURL = YES;
//ImapDebugEnabled = YES;
//LDAPDebugEnabled = YES;
//PGDebugEnabled = YES;
//MySQL4DebugEnabled = YES;
//SOGoUIxDebugEnabled = YES;
//WODontZipResponse = YES;
//WOLogFile = /var/log/sogo/sogo.log;
}
+4 -2
View File
@@ -1,8 +1,8 @@
# Sogod cronjobs
# Vacation messages expiration
# Make sure to set authname and authpassword with the credentials of a sieve admin
#0 0 * * * sogo /usr/sbin/sogo-tool expire-autoreply authname:authpassword
# The credentials file should contain the sieve admin credentials (username:passwd)
#0 0 * * * sogo /usr/sbin/sogo-tool expire-autoreply -p /etc/sogo/sieve.creds
# Session cleanup - runs every minute
# - Ajust the nbMinutes parameter to suit your needs
@@ -10,6 +10,8 @@
#* * * * * sogo /usr/sbin/sogo-tool expire-sessions 60
# Email alarms - runs every minutes
# If you need to use SMTP AUTH for outgoing mails, specify credentials to use
# with '-p /path/to/credentialsFile' (same format as the sieve credentials)
#* * * * * sogo /usr/sbin/sogo-ealarms-notify
# Daily backups
+52
View File
@@ -0,0 +1,52 @@
#!/bin/bash
set -e
# This script only works with mysql
# updates c_content to longtext in SOGo/OpenChange cache tables
# to avoid truncation of data at 64k
defaultusername=$USER
defaulthostname=127.0.0.1
defaultdatabase=sogo
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 growContent() {
oldIFS="$IFS"
IFS=" "
part="`echo -e \"ALTER TABLE $table MODIFY c_content LONGTEXT;\\n\"`";
sqlscript="$sqlscript$part"
IFS="$oldIFS"
}
echo "This script will ask for the sql password twice" >&2
echo "Converting c_content from TEXT to LONGTEXT in SOGo/OpenChange cache tables" >&2
tables=`mysql -p -s -u $username -h $hostname $database -e "show tables like 'socfs_%';"`
for table in $tables;
do
growContent
done
echo "$sqlscript" | mysql -p -s -u $username -h $hostname $database
+2 -1
View File
@@ -1,6 +1,7 @@
#!/bin/sh
# SOGOSPOOL must match the value of the configuration parameter SOGoMailSpoolPath
SOGOSPOOL=/var/spool/sogo
/usr/sbin/tmpwatch 24 "$SOGOSPOOL"
find "$SOGOSPOOL" -depth -mindepth 1 -type d -empty -exec /bin/rmdir {} \; 2> /dev/null
find "$SOGOSPOOL" -mindepth 1 -type d -user sogo -empty -delete > /dev/null
+5 -5
View File
@@ -1,7 +1,7 @@
<?php
/* updates.php - this file is part of SOGo
*
* Copyright (C) 2006-2012 Inverse inc.
* Copyright (C) 2006-2013 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
@@ -28,12 +28,12 @@ $plugins
= array(
"sogo-connector@inverse.ca"
=> array( "application" => "thunderbird",
"version" => "17.0.2",
"filename" => "sogo-connector-17.0.2.xpi" ),
"version" => "17.0.3",
"filename" => "sogo-connector-17.0.3.xpi" ),
"sogo-integrator@inverse.ca"
=> array( "application" => "thunderbird",
"version" => "17.0.2",
"filename" => "sogo-integrator-17.0.2.xpi" ),
"version" => "17.0.3",
"filename" => "sogo-integrator-17.0.3.xpi" ),
"{e2fda1a4-762b-4020-b5ad-a41df1933103}"
=> array( "application" => "thunderbird",
"version" => "1.9",
@@ -0,0 +1,66 @@
"Personal Calendar" = "التقويم الشخصي";
vevent_class0 = "(حدث عام)";
vevent_class1 = "(حدث خاص)";
vevent_class2 = "(حدث سري)";
vtodo_class0 = "(مهمة عامة)";
vtodo_class1 = "(مهمة خاصة)";
vtodo_class2 = "(مهمة سرية)";
/* Receipts */
"The event \"%{Summary}\" was created" = "أُنشِئ الحدث \"%{Summary}\"";
"The event \"%{Summary}\" was deleted" = "حُذِفَ الحدث \"%{Summary}\"";
"The event \"%{Summary}\" was updated" = "حُدِّث الحدث \"%{Summary}\"";
"The following attendees(s) were notified:" = "تم ابلاغ المدعو (المدعويين) الأتي أسماءهم:";
"The following attendees(s) were added:" = "تم أضافة المدعو (المدعويين) الأتي أسماءهم:";
"The following attendees(s) were removed:" = "تم مسح المدعو (المدعويين) الأتي أسماءهم:";
/* IMIP messages */
"calendar_label" = "التقويم:";
"startDate_label" = "البداية:";
"endDate_label" = "النهاية:";
"due_label" = "تاريخ الاستحقاق:";
"location_label" = "المكان:";
"summary_label" = "الملخص:";
"comment_label" = "التعليق:";
/* Invitation */
"Event Invitation: \"%{Summary}\"" = "دعوة الحدث: \"%{Summary}\"";
"(sent by %{SentBy}) " = "(أرسلت بواسطة٪ {SentBy})";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "وقد دعت%{Organizer} %{SentByText} الى %{Summary} . ⏎\n⏎\nبداية:٪ {StartDate} ⏎\nنهاية:%{EndDate}⏎\nالوصف:%{Description}\n";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText}قام بدعوتك %{Summary}. ⏎\n⏎\nبداية:٪ {StartDate} في {٪ StartTime} ⏎\nالغاية: {٪ EndDate} في {٪ EndTime} ⏎\nالوصف:%{Description}\n";
/* Deletion */
"Event Cancelled: \"%{Summary}\"" = "الحدث الغي : \"%{Summary}\"";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
= "ألغى%{Organizer} %{SentByText} هذا الحدث:.%{Summary} ⏎\n⏎\nبداية:٪ {StartDate} ⏎\nنهاية:%{EndDate} ⏎\nالوصف:%{Description}";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
= "%{Organizer} %{SentByText}قام بإلغاء هذا الحدث: %{Summary}.⏎\n⏎\nبداية:٪ {StartDate} في {٪ StartTime} ⏎\nالغاية: {٪ EndDate} في {٪ EndTime} ⏎\nالوصف:%{Description}";
/* Update */
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
= "موعد \"%{Summary}\" بتاريخ %{OldStartDate} قد تغير";
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
= "تعيين \"%{Summary}\" ل٪ {OldStartDate} في {٪ OldStartTime} قد تغيرت";
"The following parameters have changed in the \"%{Summary}\" meeting:"
= " لقد تغيرت المحددات التالية في الاجتماع \"%{Summary}\":";
"Please accept or decline those changes."
= "يرجى قبول أو رفض تلك التغييرات.";
/* Reply */
"Accepted invitation: \"%{Summary}\"" = "دعوةٌ مقبولة: \"%{Summary}\"";
"Declined invitation: \"%{Summary}\"" = "دعوةٌ مرفوضة: \"%{Summary}\"";
"Delegated invitation: \"%{Summary}\"" = "دعوة تفويض: \"%{Summary}\"";
"Not yet decided on invitation: \"%{Summary}\"" = "دعوةٌ لم تقرر بشأنها: \"%{Summary}\"";
"%{Attendee} %{SentByText}has accepted your event invitation."
= "وقد قبلت%{Attendee} %{SentByText} دعوتك الحدث.";
"%{Attendee} %{SentByText}has declined your event invitation."
= "وقد رفض %{Attendee} %{SentByText} دعوتك للحدث";
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
= "وقد فوض%{Attendee} %{SentByText} الدعوة إلى %{Delegate}.";
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
= "%{Attendee} %{SentByText} لم يقرر حتى الآن حضورهذا الحدث الخاص بك.";
/* Resources */
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "لا يمكن الوصول إلى الموارد: \"%{Cn} %{SystemEmail}\"";
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "الحد الأقصى لعدد الحجوزات في وقت واحد (%{NumberOfSimultaneousBookings}) وصلت للموارد \"%{Cn} %{SystemEmail}\" . الحدث المتضارب في الموعد هو \"٪ {EventTitle}\"، ويبدأ فى٪ {StartDate}.";
@@ -8,23 +8,15 @@ vtodo_class1 = "(Privat opgave)";
vtodo_class2 = "(Hemmelig opgave)";
/* Receipts */
"Title:" = "Titel:";
"Start:" = "Start:";
"End:" = "Slut:";
"Receipt: users invited to a meeting" = "Kvittering: brugere inviteret til et møde";
"You have invited the following attendees(s):" = "Du har inviteret følgende deltager(e):";
"... to attend the following event:" = "... til at deltage i følgende begivenhed:";
"Receipt: invitation updated" = "Kvittering: invitation opdateret";
"The following attendees(s):" = "Følgende deltager(e):";
"... have been notified of the changes to the following event:" = "... er blevet underrettet om ændringer i følgende begivenheder:";
"Receipt: attendees removed from an event" = "Kvittering: deltagere fjernet fra en begivenhed";
"You have removed the following attendees(s):" = "Du har fjernet følgende deltager(e):";
"... from the following event:" = "... fra følgende begivenhed:";
"The event \"%{Summary}\" was created" = "Begivenheden \"%{Summary}\" blev oprettet";
"The event \"%{Summary}\" was deleted" = "Begivenheden \"%{Summary}\" blev slettet";
"The event \"%{Summary}\" was updated" = "Begivenheden \"%{Summary}\" blev opdateret";
"The following attendees(s) were notified:" = "Følgende deltager(e) blev underrettet:";
"The following attendees(s) were added:" = "Følgende deltager(e) blev tilføjet:";
"The following attendees(s) were removed:" = "Følgende deltager(e) blev fjernet:";
/* IMIP messages */
"calendar_label" = "Kalender:";
"startDate_label" = "Start:";
"endDate_label" = "Slut:";
"due_label" = "Forfaldsdato:";
@@ -33,32 +25,33 @@ vtodo_class2 = "(Hemmelig opgave)";
"comment_label" = "Kommentér:";
/* Invitation */
"Event Invitation: \"%{Summary}\"" = "Begivenhed Invitation: \"%{Opsummering}\"";
"Event Invitation: \"%{Summary}\"" = "Begivenhed Invitation: \"%{Summary}\"";
"(sent by %{SentBy}) " = "(Sendt af%{SentBy})";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer}%{SentByText} har inviteret dig til%{Summary}.
Start:%{StartDate}ved%{StartTime}
End:%{EndDate}ved%{endTime}
Description:%{Description}";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText}har inviteret dig til %{Summary}.\n\nStart: %{StartDate}\nSlut: %{EndDate}\nBeskrivelse: %{Description}";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer}%{SentByText} har inviteret dig til%{Summary}.\n\nStart:%{StartDate}ved%{StartTime}\nEnd:%{EndDate}ved%{endTime}\nDescription:%{Description}";
/* Deletion */
"Event Cancelled: \"%{Summary}\"" = "Begivenhed Annulleret: \"%{Opsummering}\"";
"Event Cancelled: \"%{Summary}\"" = "Begivenhed Annulleret: \"%{Summary}\"";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
= "%{Organizer} %{SentByText}har aflyst denne begivenhed: %{Summary}.\n\nStart: %{StartDate}\nSlut: %{EndDate}\nBeskrivelse: %{Description}";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
= "%{Organizer} %{SentByText}har annulleret denne begivenhed: %{Summary}.
Start: %{StartDate} at %{StartTime}
End: %{EndDate} at %{EndTime}
Description: %{Description}";
= "%{Organizer} %{SentByText}har annulleret denne begivenhed: %{Summary}.\n\nStart: %{StartDate} %{StartTime}\nSlut: %{EndDate} %{EndTime}\nBeskrivelse: %{Description}";
/* Update */
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
= "Aftalen \"%{Summary}\" for %{OldStartDate} er ændret";
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
= "Aftalen \"%{Summary}\" den %{OldStartDate} kl. %{OldStartTime} er blevet ændret";
"The following parameters have changed in the \"%{Summary}\" meeting:"
= "Følgende parametre har ændret sig i \"% {Opsummering}\" møde:";
= "Følgende parametre har ændret sig i \"%{Summary}\" møde:";
"Please accept or decline those changes."
= "Venligst acceptér eller afvis disse ændringer.";
/* Reply */
"Accepted invitation: \"%{Summary}\"" = "Accepterede invitationen: \"%{Summary}\"";
"Declined invitation: \"%{Summary}\"" = "Afslåede invitationen: \"%{Summary}\"";
"Delegated invitation: \"%{Summary}\"" = "Delegerede invitationen: \"%{Summary}\"";
"Not yet decided on invitation: \"%{Summary}\"" = "Ikke taget stilling til invitationen: \"%{Summary}\"";
"%{Attendee} %{SentByText}has accepted your event invitation."
= "%{Attendee} %{SentByText} har accepteret din begivenhedsinvitation.";
"%{Attendee} %{SentByText}has declined your event invitation."
@@ -69,4 +62,5 @@ Description: %{Description}";
= "%{Attendee} %{SentByText} har endnu ikke taget stilling til din begivenhedsinvitation.";
/* Resources */
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\"." = "Maximalt antal samtidige bookings (%{NumberOfSimultaneousBookings}) er nået for \"%{Cn} %{SystemEmail}\".";
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "Kan ikke tilgå ressourcen: \"%{Cn} %{SystemEmail}\"";
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "Maksimalt antal tilladte indkaldelser (%{NumberOfSimultaneousBookings}) er nået for ressource \"%{Cn} %{SystemEmail}\". Konflikter med begivenheden \"%{EventTitle}\", som starter %{StartDate}.";
+2 -2
View File
@@ -50,10 +50,10 @@ Appointments_OBJC_FILES = \
Appointments_RESOURCE_FILES += \
product.plist \
\
MSExchangeFreeBusySOAPResponseMap.plist \
MSExchangeFreeBusySOAPRequest.wo
Appointments_LANGUAGES = 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 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
@@ -27,13 +27,13 @@ vtodo_class2 = "(Vertrauliche Aufgabe)";
/* Invitation */
"Event Invitation: \"%{Summary}\"" = "Termineinladung: \"%{Summary}\"";
"(sent by %{SentBy}) " = "(gesendet von %{SentBy}) ";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText} Hat Sie eingeladen zu %{Summary}.\n\nBeginn: %{StartDate}\nEnde: %{EndDate}\nBeschreibung: %{Description}";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText} Hat Sie eingeladen zu \"%{Summary}\".\n\nBeginn: %{StartDate}\nEnde: %{EndDate}\nBeschreibung: %{Description}";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText} hat Sie eingeladen zu \"%{Summary}\".\n\nBeginn: %{StartDate} um %{StartTime}\nEnde: %{EndDate} um %{EndTime}\nBeschreibung: %{Description}";
/* Deletion */
"Event Cancelled: \"%{Summary}\"" = "Termin abgesagt: \"%{Summary}\"";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
= "%{Organizer} %{SentByText} hat den folgenden Termin abgesagt: %{Summary}.\n\nBeginn: %{StartDate}\nEnde: %{EndDate}\nBeschreibung: %{Description}";
= "%{Organizer} %{SentByText} hat den folgenden Termin abgesagt: \"%{Summary}\".\n\nBeginn: %{StartDate}\nEnde: %{EndDate}\nBeschreibung: %{Description}";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
= "%{Organizer} %{SentByText} hat diesen Termin abgesagt: \"%{Summary}\".\n\nBeginn: %{StartDate} um %{StartTime}\nEnde: %{EndDate} um %{EndTime}\nBeschreibung: %{Description}";
@@ -45,7 +45,7 @@ vtodo_class2 = "(Vertrauliche Aufgabe)";
"The following parameters have changed in the \"%{Summary}\" meeting:"
= "Folgendes wurde am Termin \"%{Summary}\" geändert:";
"Please accept or decline those changes."
= "Bitte akzeptieren Sie diese Änderung oder lehnen Sie ab.";
= "Bitte akzeptieren Sie diese Änderung oder lehnen Sie diese ab.";
/* Reply */
"Accepted invitation: \"%{Summary}\"" = "Einladung zugestimmt: \"%{Summary}\"";
+10 -1
View File
@@ -20,6 +20,7 @@
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSBundle.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
@@ -97,8 +98,10 @@ size_t curl_body_function_freebusy(void *ptr, size_t size, size_t nmemb, void *i
MSExchangeFreeBusySOAPRequest *soapRequest;
MSExchangeFreeBusyResponse *freeBusyResponse;
NSString *rawRequest, *url, *body, *hostname, *httpauth, *authname, *password;
NSString *mapFile;
NSArray *infos = nil;
NSDictionary *root;
NSBundle *bundle;
CURL *curl;
struct curl_slist *headerlist=NULL;
@@ -161,7 +164,13 @@ size_t curl_body_function_freebusy(void *ptr, size_t size, size_t nmemb, void *i
}
if (sax == nil && parser != nil)
{
sax = [[SaxObjectDecoder alloc] initWithMappingAtPath:@"./MSExchangeFreeBusySOAPResponseMap.plist"];
bundle = [NSBundle bundleForClass: [self class]];
mapFile = [bundle pathForResource: @"MSExchangeFreeBusySOAPResponseMap" ofType: @"plist"];
if (![mapFile length])
{
[self errorWithFormat: @"mapFile not found (MSExchangeFreeBusySOAPResponseMap.plist)"];
}
sax = [[SaxObjectDecoder alloc] initWithMappingAtPath: mapFile];
[parser setContentHandler:sax];
//[parser setErrorHandler:sax];
}
@@ -8,23 +8,15 @@ vtodo_class1 = "(Privat oppgave)";
vtodo_class2 = "(Konfidensiell oppgave)";
/* Receipts */
"Title:" = "Tittel:";
"Start:" = "Start:";
"End:" = "Slutt:";
"Receipt: users invited to a meeting" = "Kvittering: brukere invitert til et møte";
"You have invited the following attendees(s):" = "Du har invitert følende deltagere:";
"... to attend the following event:" = "... til å delta i følgende hendelse:";
"Receipt: invitation updated" = "Kvittering: invitasjon oppdatert";
"The following attendees(s):" = "Følgende deltager(e):";
"... have been notified of the changes to the following event:" = "... har blitt informert om endringene i følgende hendelse:";
"Receipt: attendees removed from an event" = "Kvittering: deltagere fjernet fra en hendelse";
"You have removed the following attendees(s):" = "Du har tatt bort følgende deltagere:";
"... from the following event:" = "... fra følgende hendelse:";
"The event \"%{Summary}\" was created" = "Hendelsen \"%{Summary}\" ble opprettet";
"The event \"%{Summary}\" was deleted" = "Hendelsen \"%{Summary}\" ble slettet";
"The event \"%{Summary}\" was updated" = "Hendelsen \"%{Summary}\" ble oppdatert";
"The following attendees(s) were notified:" = "Følgende deltaker(e) ble varslet:";
"The following attendees(s) were added:" = "Følgende deltaker(e) ble lagt til:";
"The following attendees(s) were removed:" = "Følgende deltaker(e) ble fjernet:";
/* IMIP messages */
"calendar_label" = "Kalender:";
"startDate_label" = "Start:";
"endDate_label" = "Slutt:";
"due_label" = "Forfallsdato:";
@@ -35,27 +27,31 @@ vtodo_class2 = "(Konfidensiell oppgave)";
/* Invitation */
"Event Invitation: \"%{Summary}\"" = "Hendelseinvitasjon: \"%{Summary}\"";
"(sent by %{SentBy}) " = "(sendt av %{SentBy})";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText} har invitert deg til %{Summary}.\n\nStart: %{StartDate} %{StartTime}\nSlutt: %{EndDate} %{EndTime}\nBeskrivelse: %{Description}";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText} har invitert deg til %{Summary}.⏎ ⏎ Start: %{StartDate}⏎ Slutt: %{EndDate}⏎ Beskrivelse: %{Description}";
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText} har invitert deg til %{Summary}.\n\nStart: %{StartDate} klokken %{StartTime}\nSlutt: %{EndDate} klokken %{EndTime}\nBeskrivelse: %{Description}";
/* Deletion */
"Event Cancelled: \"%{Summary}\"" = "Hendelse avlyst: \"%{Summary}\"";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
= "";
= "%{Organizer} %{SentByText} har avlyst hendelsen: %{Summary}.⏎ ⏎ Start: %{StartDate}⏎ Slutt: %{EndDate}⏎ Beskrivelse: %{Description}";
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
= "%{Organizer} %{SentByText} har avlyst : %{Summary}.\n\nStart: %{StartDate} %{StartTime}\nEnd: %{EndDate} %{EndTime}\nBeskrivelse: %{Description}";
= "%{Organizer} %{SentByText} har avlyst : %{Summary}.\n\nStart: %{StartDate} klokken %{StartTime}\nEnd: %{EndDate} klokken %{EndTime}\nBeskrivelse: %{Description}";
/* Update */
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
= "";
= "Avtalen \"%{Summary}\", %{OldStartDate} er endret";
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
= "Avtalen \"%{Summary}\" for %{OldStartDate} klokken %{OldStartTime} er endret.";
"The following parameters have changed in the \"%{Summary}\" meeting:"
= "Følgende parametre er endret for \"%{Summary}\" møtet:";
= "Følgende parametre er endret for \"%{Summary}\"-møtet:";
"Please accept or decline those changes."
= "Vennligst godta eller avvis endringene.";
/* Reply */
"Accepted invitation: \"%{Summary}\"" = "Aksepterte invitasjonen: \"%{Summary}\"";
"Declined invitation: \"%{Summary}\"" = "Avviste invitasjonen: \"%{Summary}\"";
"Delegated invitation: \"%{Summary}\"" = "Delegerte invitasjonen: \"%{Summary}\"";
"Not yet decided on invitation: \"%{Summary}\"" = "Fortsatt ikke svart på invitasjonen: \"%{Summary}";
"%{Attendee} %{SentByText}has accepted your event invitation."
= "%{Attendee} %{SentByText} har godtatt invitasjonen.";
"%{Attendee} %{SentByText}has declined your event invitation."
@@ -63,7 +59,8 @@ vtodo_class2 = "(Konfidensiell oppgave)";
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
= "%{Attendee} %{SentByText} har delegert invitasjonen til %{Delegate}.";
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
= "%{Attendee} %{SentByText} had ends ikke var på invitasjonen.";
= "%{Attendee} %{SentByText} har ikke svart på invitasjonen.";
/* Resources */
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\"." = "Maksimalt antall samtidige bookinger (%{NumberOfSimultaneousBookings}) er nåd for ressurs \"%{Cn} %{SystemEmail}\".";
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "Kan ikke få tilgang til ressurs: \"%{Cn} %{SystemEmail}\"";
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "Maksimum antall samtidige reservasjoner (%{NumberOfSimultaneousBookings}) er nådd for ressursen \"%{Cn} %{SystemEmail}\". Kolliderende hendelse er \"%{EventTitle}\", som starter %{StartDate}.";
@@ -48,6 +48,10 @@ vtodo_class2 = "(Конфиденциальная задача)";
= "Пожалуйста подтвердите или отмените эти изменения.";
/* Reply */
"Accepted invitation: \"%{Summary}\"" = "Принятое приглашение: \"%{Summary}\"";
"Declined invitation: \"%{Summary}\"" = "Отклонённое приглашение: \"%{Summary}\"";
"Delegated invitation: \"%{Summary}\"" = "Делегированное приглашение: \"%{Summary}\"";
"Not yet decided on invitation: \"%{Summary}\"" = "Пока нет решения по приглашению: \"%{Summary}\"";
"%{Attendee} %{SentByText}has accepted your event invitation."
= "%{Attendee} %{SentByText}согласился участвовать в запланированном мероприятии.";
"%{Attendee} %{SentByText}has declined your event invitation."
+67 -28
View File
@@ -873,7 +873,9 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
NSMutableDictionary *newRecord;
NSDictionary *oldRecord;
NGCalendarDateRange *newRecordRange;
NSComparisonResult compare;
int recordIndex, secondsOffsetFromGMT;
NSNumber *dateSecs;
newRecord = nil;
recurrenceId = [component recurrenceId];
@@ -895,30 +897,24 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
[recurrenceId setTimeZone: tz];
}
if ([dateRange containsDate: [component startDate]] ||
[dateRange containsDate: [component endDate]])
compare = [[dateRange startDate] compare: recurrenceId];
if ((compare == NSOrderedAscending || compare == NSOrderedSame) &&
[[dateRange endDate] compare: recurrenceId] == NSOrderedDescending)
{
recordIndex = [self _indexOfRecordMatchingDate: recurrenceId
inArray: ma];
// The recurrence exception intersects with the date range;
// find the occurence and replace it with the new record
recordIndex = [self _indexOfRecordMatchingDate: recurrenceId inArray: ma];
if (recordIndex > -1)
{
newRecord = [self fixupRecord: [component quickRecord]];
[newRecord setObject: [NSNumber numberWithInt: 1]
forKey: @"c_iscycle"];
oldRecord = [ma objectAtIndex: recordIndex];
[newRecord setObject: [oldRecord objectForKey: @"c_recurrence_id"]
forKey: @"c_recurrence_id"];
// 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"];
[ma replaceObjectAtIndex: recordIndex withObject: newRecord];
}
if ([dateRange containsDate: [component startDate]])
{
newRecord = [self fixupRecord: [component quickRecord]];
[ma replaceObjectAtIndex: recordIndex withObject: newRecord];
}
else
// The range doesn't cover the exception; remove it from the records
[ma removeObjectAtIndex: recordIndex];
}
else
[self errorWithFormat:
@"missing exception record for recurrence-id %@ (uid %@)",
@@ -926,16 +922,33 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
}
else
{
// The recurrence id of the exception is outside the date range;
// simply add the exception to the records array
newRecord = [self fixupRecord: [component quickRecord]];
newRecordRange = [NGCalendarDateRange
calendarDateRangeWithStartDate: [newRecord objectForKey: @"startDate"]
endDate: [newRecord objectForKey: @"endDate"]];
if ([dateRange doesIntersectWithDateRange: newRecordRange])
[ma addObject: newRecord];
[ma addObject: newRecord];
else
newRecord = nil;
}
if (newRecord)
[self _fixExceptionRecord: newRecord fromRow: row];
{
recurrenceId = [component recurrenceId];
dateSecs = [NSNumber numberWithInt: [recurrenceId timeIntervalSince1970]];
[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"];
[self _fixExceptionRecord: newRecord fromRow: row];
}
}
//
@@ -961,7 +974,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
{
components = [[elements objectAtIndex: 0] allObjects];
max = [components count];
for (count = 1; count < max; count++)
for (count = 1; count < max; count++) // skip master event
[self _appendCycleException: [components objectAtIndex: count]
firstInstanceCalendarDateRange: fir
fromRow: row
@@ -2223,10 +2236,39 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
return @"";
}
/*
RFC5842 states:
3.1. DAV:resource-id Property
The DAV:resource-id property is a REQUIRED property that enables
clients to determine whether two bindings are to the same resource.
The value of DAV:resource-id is a URI, and may use any registered URI
scheme that guarantees the uniqueness of the value across all
resources for all time (e.g., the urn:uuid: URN namespace defined in
[RFC4122] or the opaquelocktoken: URI scheme defined in [RFC4918]).
<!ELEMENT resource-id (href)>
...
so we must STRIP any username prefix, to make the ID global.
*/
- (NSString *) davResourceId
{
NSString *name, *prefix;
prefix = [NSString stringWithFormat: @"%@_", [self ownerInContext: context]];
name = [self nameInContainer];
if ([name hasPrefix: prefix])
{
name = [name substringFromIndex: [prefix length]];
}
return [NSString stringWithFormat: @"urn:uuid:%@:calendars:%@",
[self ownerInContext: context], [self nameInContainer]];
[self ownerInContext: context], name];
}
- (NSArray *) davScheduleCalendarTransparency
@@ -2888,9 +2930,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
NSMutableString *content;
NSString *uid;
uid = [self globallyUniqueObjectId];
[event setUid: uid];
// We first look if there's an event with the same UID in our calendar. If not,
// let's reuse what is in the event, otherwise generate a new GUID and use it.
uid = [event uid];
@@ -1,8 +1,6 @@
/* SOGoAppointmentFolders.h - this file is part of SOGo
*
* Copyright (C) 2007 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2007-2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,8 +33,8 @@
NSMutableArray *folderObjectKeys;
}
- (SOGoWebAppointmentFolder *) newWebCalendarWithName: (NSString *) folderDisplayName
atURL: (NSString *) url;
- (SOGoWebAppointmentFolder *) newWebCalendarWithURL: (NSString *) urlString
nameInContainer: (NSString *) name;
- (void) reloadWebCalendars: (BOOL) forceReload;
+41 -12
View File
@@ -1,9 +1,7 @@
/* SOGoAppointmentFolders.m - this file is part of SOGo
*
* Copyright (C) 2007-2010 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2007-2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -133,18 +131,29 @@ static SoSecurityManager *sm = nil;
return [self labelForKey: @"Personal Calendar" inContext: context];
}
- (SOGoWebAppointmentFolder *)
newWebCalendarWithName: (NSString *) folderDisplayName
atURL: (NSString *) urlString
- (SOGoWebAppointmentFolder *) newWebCalendarWithURL: (NSString *) urlString
nameInContainer: (NSString *) name
{
NSException *error;
SOGoAppointmentFolder *aptFolder;
NSString *folderDisplayName, *tmp;
SOGoWebAppointmentFolder *webCalendar;
NSString *name;
SOGoAppointmentFolder *aptFolder;
NSException *error;
NSURL *url;
folderDisplayName = [self labelForKey: @"Web Calendar"];
webCalendar = nil;
tmp = [urlString lastPathComponent];
if (tmp)
{
if ([[tmp pathExtension] caseInsensitiveCompare: @"ics"] == NSOrderedSame)
folderDisplayName = [tmp substringToIndex: [tmp length] - 4];
else
folderDisplayName = tmp;
}
if ([folderDisplayName length] > 0 && [urlString length] > 0)
{
url = [NSURL URLWithString: urlString];
@@ -154,6 +163,10 @@ static SoSecurityManager *sm = nil;
nameInContainer: &name];
if (!error)
{
// We make sure we initialized our subfolfers list. This can happen
// when auto-creating Web calendars during the logon process.
[self subFolders];
aptFolder = [subFolders objectForKey: name];
[aptFolder setFolderPropertyValue: urlString
inCategory: @"WebCalendars"];
@@ -561,9 +574,25 @@ static SoSecurityManager *sm = nil;
folder = [SOGoWebAppointmentFolder
folderWithSubscriptionReference: ref
inContainer: self];
if (folder
&& (forceReload || [folder reloadOnLogin]))
[folder loadWebCalendar];
if (forceReload || [folder reloadOnLogin] || !folder)
{
if (!folder)
{
NSString *s, *urlString;
urlString = [[calSettings objectForKey: @"WebCalendars"] objectForKey: ref];
s = [ref lastPathComponent];
// See bug #2007. Some admins want to subscribe users to Web calendars
// using sogo-tool. If they do that, the db tables won't be created
// so we must detect that here and create them upon login.
folder = [self newWebCalendarWithURL: urlString
nameInContainer: s];
}
[folder loadWebCalendar];
}
}
}
+22 -12
View File
@@ -1798,20 +1798,18 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
iCalCalendar *oldCalendar;
iCalEvent *oldEvent, *newEvent;
iCalEventChanges *changes;
NSArray *oldEvents, *newEvents;
NSMutableArray *oldEvents, *newEvents;
NSCalendarDate *recurrenceId;
BOOL master;
int i;
//
// We check what has changed in the event and react accordingly.
//
newEvents = [calendar events];
newEvents = [NSMutableArray arrayWithArray: [calendar events]];
oldCalendar = [self calendar: NO secure: NO];
oldEvents = [oldCalendar events];
oldEvents = [NSMutableArray arrayWithArray: [oldCalendar events]];
recurrenceId = nil;
master = NO;
for (i = [newEvents count]-1; i >= 0; i--)
{
@@ -1842,8 +1840,8 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
}
else
{
[calendar removeChild: oldEvent];
[oldCalendar removeChild: newEvent];
[newEvents removeObject: newEvent];
[oldEvents removeObject: oldEvent];
}
}
@@ -1860,7 +1858,6 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
{
oldEvent = [oldEvents objectAtIndex: 0];
newEvent = [newEvents objectAtIndex: 0];
master = YES;
}
// A RECURRENCE-ID was added
else if ([newEvents count] > [oldEvents count])
@@ -1892,25 +1889,38 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
if ([[newEvent attendees] count] || [[oldEvent attendees] count])
{
NSString *uid;
// newEvent might be nil here, if we're deleting a RECURRENCE-ID with attendees
// If that's the case, we use the oldEvent for now just to obtain the organizer
// and we'll swap it back to nil once we're done.
if (!newEvent)
newEvent = oldEvent;
// We fetch the organizer's uid. Sometimes, the recurrence-id will
// have it, sometimes not. If it doesn't, we fetch it from the master event.
uid = [[newEvent organizer] uid];
if (!uid && !master)
if (!uid && !recurrenceId)
uid = [[[[[newEvent parent] events] objectAtIndex: 0] organizer] uid];
// With Thunderbird 10, if you create a recurring event with an exception
// occurence, and invite someone, the PUT will have the organizer in the
// recurrence-id and not in the master event. We must fix this, otherwise
// SOGo will break.
if (!master && ![[[[[newEvent parent] events] objectAtIndex: 0] organizer] uid])
if (!recurrenceId && ![[[[[newEvent parent] events] objectAtIndex: 0] organizer] uid])
[[[[newEvent parent] events] objectAtIndex: 0]
setOrganizer: [newEvent organizer]];
if (newEvent == oldEvent)
newEvent = nil;
if (uid && [uid caseInsensitiveCompare: owner] == NSOrderedSame)
{
if ((ex = [self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent]))
// A RECCURENCE-ID was removed
if (!newEvent && oldEvent)
[self prepareDeleteOccurence: oldEvent];
// The master event was changed, A RECCURENCE-ID was added or modified
else if ((ex = [self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent]))
return ex;
}
//
@@ -1,5 +1,5 @@
/*
Copyright (C) 2006-2012 Inverse inc.
Copyright (C) 2006-2013 Inverse inc.
Copyright (C) 2000-2005 SKYRIX Software AG
This file is part of SOGo.
@@ -140,6 +140,11 @@
return newEndDate;
}
- (NSString *) location
{
return [apt location];
}
- (NSString *) summary
{
return [apt summary];
@@ -760,6 +760,10 @@
SOGoUser *ownerUser;
SOGoDomainDefaults *dd;
// If defined, we return immediately. When not defined, we send the notifications correctly
if ([object firstChildWithTag: @"X-SOGo-Send-Appointment-Notifications"])
return;
ownerUser = [SOGoUser userWithLogin: owner];
dd = [ownerUser domainDefaults];
if ([dd appointmentSendEMailNotifications] && [object isStillRelevant])
+3 -1
View File
@@ -294,7 +294,9 @@
contact = [contacts lastObject];
email = [contact valueForKey: @"c_email"];
source = [contact objectForKey: @"source"];
if ([email length] && [source MSExchangeHostname])
if ([email length]
&& [source conformsToProtocol: @protocol (SOGoDNSource)]
&& [source MSExchangeHostname])
{
exchangeFreeBusy = [[MSExchangeFreeBusy alloc] init];
[exchangeFreeBusy autorelease];
@@ -1,6 +1,6 @@
/* SOGoWebAppointmentFolder.m - this file is part of SOGo
*
* Copyright (C) 2009-2010 Inverse inc.
* Copyright (C) 2009-2013 Inverse inc.
*
* Author: Cyril Robert <crobert@inverse.ca>
* Ludovic Marcotte <lmarcotte@inverse.ca>
@@ -37,6 +37,7 @@
#import <NGCards/iCalCalendar.h>
#import <GDLContentStore/GCSFolder.h>
#import <SOGo/SOGoAuthenticator.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserSettings.h>
#import <SOGo/NSDictionary+Utilities.h>
@@ -69,27 +70,23 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
NSString *authValue, *userPassword;
NSArray *parts, *keys;
userPassword = [[self authenticatorInContext: context]
passwordInContext: context];
userPassword = [[self authenticatorInContext: context] passwordInContext: context];
if ([userPassword length] == 0)
{
authData = nil;
userPassword = [[SOGoSystemDefaults sharedSystemDefaults] encryptionKey];
}
authValue
= [[self folderPropertyValueInCategory: @"WebCalendarsAuthentication"]
decryptWithKey: userPassword];
parts = [authValue componentsSeparatedByString: @":"];
if ([parts count] == 2)
{
keys = [NSArray arrayWithObjects: @"username", @"password", nil];
authData = [NSDictionary dictionaryWithObjects: parts
forKeys: keys];
}
else
{
authValue
= [[self folderPropertyValueInCategory: @"WebCalendarsAuthentication"]
decryptWithKey: userPassword];
parts = [authValue componentsSeparatedByString: @":"];
if ([parts count] == 2)
{
keys = [NSArray arrayWithObjects: @"username", @"password", nil];
authData = [NSDictionary dictionaryWithObjects: parts
forKeys: keys];
}
else
authData = nil;
}
authData = nil;
return authData;
}
@@ -99,18 +96,18 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
{
NSString *authValue, *userPassword;
userPassword = [[self authenticatorInContext: context]
passwordInContext: context];
if ([userPassword length] > 0)
{
if (!username)
username = @"";
if (!password)
password = @"";
authValue = [NSString stringWithFormat: @"%@:%@", username, password];
[self setFolderPropertyValue: [authValue encryptWithKey: userPassword]
inCategory: @"WebCalendarsAuthentication"];
}
userPassword = [[self authenticatorInContext: context] passwordInContext: context];
if ([userPassword length] == 0) {
userPassword = [[SOGoSystemDefaults sharedSystemDefaults] encryptionKey];
}
if (!username)
username = @"";
if (!password)
password = @"";
authValue = [NSString stringWithFormat: @"%@:%@", username, password];
[self setFolderPropertyValue: [authValue encryptWithKey: userPassword]
inCategory: @"WebCalendarsAuthentication"];
}
- (NSDictionary *) loadWebCalendar
@@ -1,8 +1,6 @@
/* iCalEntityObject+SOGo.h - this file is part of SOGo
*
* Copyright (C) 2007 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2007-2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -48,6 +46,8 @@ extern NSNumber *iCalDistantFutureNumber;
- (NSMutableDictionary *) quickRecord;
- (int) priorityNumber;
- (NSString *) createdBy;
- (NSNumber *) quickRecordDateAsNumber: (NSCalendarDate *) _date
withOffset: (int) offset
forAllDay: (BOOL) allDay;
@@ -242,4 +242,19 @@ NSNumber *iCalDistantFutureNumber = nil;
return priorityNumber;
}
- (NSString *) createdBy
{
NSString *created_by;
created_by = [[self firstChildWithTag: @"X-SOGo-Component-Created-By"] flattenedValuesForKey: @""];
// We consider "SENT-BY" in case our custom header isn't found
if (![created_by length])
{
created_by = [[self organizer] sentBy];
}
return created_by;
}
@end
+11
View File
@@ -64,6 +64,9 @@
return isStillRelevent;
}
//
//
//
- (NSMutableDictionary *) quickRecord
{
NSMutableDictionary *row;
@@ -88,7 +91,15 @@
title = [self summary];
if (![title isNotNull])
title = @"";
if ([title length] > 1000)
title = [title substringToIndex: 1000];
location = [self location];
if ([location length] > 255)
location = [location substringToIndex: 255];
sequence = [self sequence];
accessClass = [self symbolicAccessClass];
isAllDay = [self isAllDay];
@@ -0,0 +1 @@
"Personal Address Book" = "دفتر العناوين الشخصية";
+1 -1
View File
@@ -27,7 +27,7 @@ Contacts_OBJC_FILES = \
Contacts_RESOURCE_FILES += \
product.plist \
Contacts_LANGUAGES = 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 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
+2 -10
View File
@@ -1,8 +1,6 @@
/* SOGoContactFolders.m - this file is part of SOGo
*
* Copyright (C) 2006-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2006-2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,13 +18,6 @@
* Boston, MA 02111-1307, USA.
*/
/* MailItems IPF.Note
ContactItems IPF.Contact
AppointmentItems IPF.Appointment
NoteItems IPF.StickyNote
TaskItems IPF.Task
JournalItems IPF.Journal */
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
@@ -50,6 +41,7 @@
#import "SOGoContactFolders.h"
#define XMLNS_INVERSEDAV @"urn:inverse:params:xml:ns:inverse-dav"
@implementation SOGoContactFolders
+ (NSString *) gcsFolderType
+4 -1
View File
@@ -200,7 +200,10 @@
- (NSArray *) toOneRelationshipKeys
{
return [source allEntryIDs];
NSString *userDomain;
userDomain = [[context activeUser] domain];
return [source allEntryIDsVisibleFromDomain: userDomain];
}
- (NSException *) saveLDIFEntry: (SOGoContactLDIFEntry *) ldifEntry
+37 -24
View File
@@ -21,6 +21,7 @@
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
@@ -65,7 +66,7 @@
@"<D:href>"];
[r appendContentString: baseURL];
if (![baseURL hasSuffix: @"/"])
[r appendContentString: @"/"];
[r appendContentString: @"/"];
[r appendContentString: name];
[r appendContentString: @"</D:href>"
@"<D:propstat>"
@@ -89,9 +90,10 @@
- (void) _appendComponentsMatchingFilters: (NSArray *) filters
toResponse: (WOResponse *) response
context: (id) localContext
context: (id) localContext
{
unsigned int count, max;
unsigned int count,i , max;
NSAutoreleasePool *pool;
NSDictionary *currentFilter, *contact;
NSEnumerator *contacts;
NSString *baseURL, *domain;
@@ -103,16 +105,27 @@
for (count = 0; count < max; count++)
{
currentFilter = [filters objectAtIndex: count];
contacts = [[(id<SOGoContactFolder>)self lookupContactsWithFilter: [[currentFilter allValues] lastObject]
onCriteria: @"name_or_address"
sortBy: @"c_givenname"
ordering: NSOrderedDescending
inDomain: domain]
objectEnumerator];
contacts =
[[(id<SOGoContactFolder>)self lookupContactsWithFilter: [[currentFilter allValues] lastObject]
onCriteria: @"name_or_address"
sortBy: @"c_givenname"
ordering: NSOrderedDescending
inDomain: domain] objectEnumerator];
pool = [[NSAutoreleasePool alloc] init];
i = 0;
while ((contact = [contacts nextObject]))
[self _appendObject: contact withBaseURL: baseURL
toREPORTResponse: response];
{
[self _appendObject: contact withBaseURL: baseURL
toREPORTResponse: response];
if (i % 10 == 0)
{
RELEASE(pool);
pool = [[NSAutoreleasePool alloc] init];
}
i++;
}
RELEASE(pool);
}
}
@@ -123,10 +136,10 @@
newString = [theString lowercaseString];
return ([newString isEqualToString: @"sn"]
|| [newString isEqualToString: @"givenname"]
|| [newString isEqualToString: @"email"]
|| [newString isEqualToString: @"mail"]
|| [newString isEqualToString: @"telephonenumber"]);
|| [newString isEqualToString: @"givenname"]
|| [newString isEqualToString: @"email"]
|| [newString isEqualToString: @"mail"]
|| [newString isEqualToString: @"telephonenumber"]);
}
- (NSDictionary *) _parseContactFilter: (id <DOMElement>) filterElement
@@ -145,12 +158,12 @@
ranges = [filterElement getElementsByTagName: @"text-match"];
if ([(NSArray *) ranges count]
&& [(NSArray *) [[ranges objectAtIndex: 0] childNodes] count])
{
filterData = [NSMutableDictionary dictionary];
[filterData setObject: [(NGDOMNode *)[ranges objectAtIndex: 0] textValue]
forKey: [filterElement attribute: @"name"]];
}
&& [(NSArray *) [[ranges objectAtIndex: 0] childNodes] count])
{
filterData = [NSMutableDictionary dictionary];
[filterData setObject: [(NGDOMNode *)[ranges objectAtIndex: 0] textValue]
forKey: [filterElement attribute: @"name"]];
}
}
return filterData;
@@ -166,7 +179,7 @@
filters = [NSMutableArray array];
children = [(NSArray *)[parentNode getElementsByTagName: @"prop-filter"]
objectEnumerator];
objectEnumerator];
while ((node = [children nextObject]))
{
filter = [self _parseContactFilter: node];
@@ -193,7 +206,7 @@
[self _appendComponentsMatchingFilters: filters
toResponse: r
context: queryContext];
context: queryContext];
[r appendContentString: @"</D:multistatus>"];
return r;
+9
View File
@@ -16,6 +16,7 @@ Mailer_OBJC_FILES += \
SOGoMailAccounts.m \
SOGoMailAccount.m \
SOGoMailFolder.m \
SOGoMailLabel.m \
SOGoMailNamespace.m \
SOGoMailObject.m \
SOGoMailObject+Draft.m \
@@ -35,6 +36,7 @@ Mailer_OBJC_FILES += \
\
EOQualifier+MailDAV.m \
NSData+Mail.m \
NSDictionary+Mail.m \
NSString+Mail.m \
SOGoUser+Mailer.m
@@ -42,6 +44,8 @@ Mailer_RESOURCE_FILES += \
product.plist \
Mailer_RESOURCE_FILES += \
SOGoMailArabicForward.wo \
SOGoMailArabicReply.wo \
SOGoMailBrazilianPortugueseForward.wo \
SOGoMailBrazilianPortugueseReply.wo \
SOGoMailCatalanForward.wo \
@@ -54,6 +58,8 @@ Mailer_RESOURCE_FILES += \
SOGoMailDutchReply.wo \
SOGoMailEnglishForward.wo \
SOGoMailEnglishReply.wo \
SOGoMailFinnishForward.wo \
SOGoMailFinnishReply.wo \
SOGoMailFrenchForward.wo \
SOGoMailFrenchReply.wo \
SOGoMailGermanForward.wo \
@@ -72,6 +78,8 @@ Mailer_RESOURCE_FILES += \
SOGoMailPolishReply.wo \
SOGoMailRussianForward.wo \
SOGoMailRussianReply.wo \
SOGoMailSlovakForward.wo \
SOGoMailSlovakReply.wo \
SOGoMailSpanishSpainForward.wo \
SOGoMailSpanishSpainReply.wo \
SOGoMailSpanishArgentinaForward.wo \
@@ -85,6 +93,7 @@ Mailer_RESOURCE_FILES += \
ADDITIONAL_INCLUDE_DIRS += -I../../SOPE/
ADDITIONAL_INCLUDE_DIRS += $(shell xml2-config --cflags)
ADDITIONAL_LIB_DIRS += -L../../SOPE/GDLContentStore/obj/
-include GNUmakefile.preamble
@@ -1,8 +1,6 @@
/* UIxColorPicker.h - this file is part of SOGo
/* NSDictionary+Mail.h - this file is part of SOGo
*
* Copyright (C) 2008 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,12 +18,17 @@
* Boston, MA 02111-1307, USA.
*/
#ifndef UIXCOLORPICKER_H
#define UIXCOLORPICKER_H
#ifndef NSDICTIONARY_MAIL_H
#define NSDICTIONARY_MAIL_H
#import <SOGoUI/UIxComponent.h>
#import <Foundation/NSDictionary.h>
@class NSString;
@interface NSDictionary (SOGoExtension)
- (NSString *) filename;
@interface UIxColorPicker : UIxComponent
@end
#endif /* UIXCOLORPICKER_H */
#endif /* NSDICTIONARY_MAIL_H */
+73
View File
@@ -0,0 +1,73 @@
/* NSDictionary+Mail.m - this file is part of SOGo
*
* Copyright (C) 2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import "NSDictionary+Mail.h"
@implementation NSDictionary (SOGoExtension)
- (NSString *) filename
{
NSDictionary *parameters;
NSString *filename;
filename = [[self objectForKey: @"parameterList"]
objectForKey: @"name"];
if (!filename)
{
parameters = [[self objectForKey: @"disposition"]
objectForKey: @"parameterList"];
filename = [parameters objectForKey: @"filename"];
// We might have something like filename*=UTF-8''foobar
// See RFC2231 for details. If it was folded before, it will
// be unfolded when we get here.
if (!filename)
{
filename = [parameters objectForKey: @"filename*"];
if (filename)
{
NSRange r;
filename = [filename stringByUnescapingURL];
// We skip up to the language
r = [filename rangeOfString: @"'"];
if (r.length)
{
r = [filename rangeOfString: @"'" options: 0 range: NSMakeRange(r.location+1, [filename length]-r.location-1)];
if (r.length)
filename = [filename substringFromIndex: r.location+1];
}
}
}
}
return filename;
}
@end
+1 -3
View File
@@ -1,8 +1,6 @@
/* NSString+Mail.h - this file is part of SOGo
*
* Copyright (C) 2007 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2007-2013 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Loaded 100 of 505 files, more files were not shown because too many files have changed in this diff. Show more