Compare commits
330
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5e77ad86c | ||
|
|
5bc0a0a932 | ||
|
|
582af53af0 | ||
|
|
13f01b512b | ||
|
|
cdb25b141d | ||
|
|
a9868b1c93 | ||
|
|
2cf66e037d | ||
|
|
6587f4f193 | ||
|
|
c8a4ea5548 | ||
|
|
148fd4936c | ||
|
|
a7fef39448 | ||
|
|
5a3d0d27e0 | ||
|
|
eb9111b5fa | ||
|
|
eb7d1f08bc | ||
|
|
854fed529c | ||
|
|
3c29e0724d | ||
|
|
cebaed9059 | ||
|
|
aae26602b0 | ||
|
|
05233d9c53 | ||
|
|
e862194b32 | ||
|
|
884fbfdb73 | ||
|
|
c05cf00db7 | ||
|
|
198db855f6 | ||
|
|
1c439c866e | ||
|
|
616ee7c6e4 | ||
|
|
37d3234b60 | ||
|
|
449d838dc2 | ||
|
|
6a9bcfda68 | ||
|
|
d0b09ebe35 | ||
|
|
0361b7dfdb | ||
|
|
38b350382a | ||
|
|
73141a645e | ||
|
|
f07526423f | ||
|
|
ba35a4b003 | ||
|
|
47c4ad5807 | ||
|
|
0f3e31ebf1 | ||
|
|
87261f3280 | ||
|
|
bd2759ecdf | ||
|
|
be1bcf3c9b | ||
|
|
053b090aff | ||
|
|
189f2218a8 | ||
|
|
656869a4a2 | ||
|
|
16f62e2393 | ||
|
|
9289615996 | ||
|
|
fdea04c08c | ||
|
|
edca3638ec | ||
|
|
05990e9a14 | ||
|
|
3cce9b2012 | ||
|
|
7dc65af300 | ||
|
|
84e999229b | ||
|
|
3dbfb0ed2d | ||
|
|
d1f3417c3a | ||
|
|
7c7031333e | ||
|
|
1e48481426 | ||
|
|
8ae1624604 | ||
|
|
7166f5a597 | ||
|
|
55052ea36f | ||
|
|
99d38417cc | ||
|
|
29eed182a7 | ||
|
|
744610dbe1 | ||
|
|
d2b739d261 | ||
|
|
2ba8254ecc | ||
|
|
28e600a4e6 | ||
|
|
ab6e4841ba | ||
|
|
91f1ab6a60 | ||
|
|
32a534919d | ||
|
|
5b77c2b724 | ||
|
|
70086e5ee6 | ||
|
|
7ddc1b9e2d | ||
|
|
6d93db96e4 | ||
|
|
27445d3b85 | ||
|
|
60d6abe542 | ||
|
|
baacf8516d | ||
|
|
46a48faf23 | ||
|
|
193720cfbb | ||
|
|
f40580d632 | ||
|
|
ca4d89fb08 | ||
|
|
906985c1f3 | ||
|
|
de8bf64c70 | ||
|
|
0c38a9e555 | ||
|
|
3c6c90d434 | ||
|
|
72a4b075d6 | ||
|
|
24c0fb1cc4 | ||
|
|
7241e3e30e | ||
|
|
1d705dc00b | ||
|
|
df42ab2a46 | ||
|
|
53f9d0d7f5 | ||
|
|
f59c77a950 | ||
|
|
cd4abe4b5b | ||
|
|
69b0f9fcbf | ||
|
|
dceead3997 | ||
|
|
573c2ec114 | ||
|
|
6a68c255bd | ||
|
|
e9d8b729b6 | ||
|
|
1e7dfc0934 | ||
|
|
d7e6648396 | ||
|
|
65603201f7 | ||
|
|
9fd6f75c4e | ||
|
|
b96f25f99f | ||
|
|
d7851999da | ||
|
|
e6ab0a590a | ||
|
|
be531100c6 | ||
|
|
e946a67ddf | ||
|
|
2fe87f14fd | ||
|
|
b2f012cae2 | ||
|
|
33659aa947 | ||
|
|
df1ab29872 | ||
|
|
61e59b864e | ||
|
|
0a590ba388 | ||
|
|
ab92516dd0 | ||
|
|
7b90b892fc | ||
|
|
b654ffb806 | ||
|
|
6de689bbe2 | ||
|
|
7eb8b9c2c3 | ||
|
|
3877f3001f | ||
|
|
4d2c734781 | ||
|
|
e57d875e0a | ||
|
|
b1df03adc7 | ||
|
|
c4bc215a47 | ||
|
|
bd776152db | ||
|
|
c6374b52ec | ||
|
|
734c164ae0 | ||
|
|
c9936d7ecf | ||
|
|
9f381e768d | ||
|
|
b531b6160c | ||
|
|
885e59a2af | ||
|
|
8a041860a0 | ||
|
|
d5f76ac832 | ||
|
|
12b7fea825 | ||
|
|
1c82af8842 | ||
|
|
6cef5245e1 | ||
|
|
0069a4200b | ||
|
|
e24c20c48a | ||
|
|
256b679798 | ||
|
|
b85ed0db1c | ||
|
|
048bae2fc5 | ||
|
|
19e542396b | ||
|
|
249a1fcf14 | ||
|
|
7dad5ad84e | ||
|
|
16105d37b8 | ||
|
|
e08ebd2390 | ||
|
|
03553980fd | ||
|
|
33fd60efb3 | ||
|
|
b8e2255a07 | ||
|
|
e687dbf155 | ||
|
|
bf398889bf | ||
|
|
f42d52743d | ||
|
|
70cd64a626 | ||
|
|
4359b05da8 | ||
|
|
e26e3d7307 | ||
|
|
25dbd4849d | ||
|
|
045b275b27 | ||
|
|
a2a89e8720 | ||
|
|
7ec1973e0f | ||
|
|
2581f6c568 | ||
|
|
20369631c9 | ||
|
|
1221da2443 | ||
|
|
f27b8b6a54 | ||
|
|
a79a9c4eff | ||
|
|
a6b393c2c1 | ||
|
|
faf228022a | ||
|
|
3e87ba92db | ||
|
|
0a87ff97b6 | ||
|
|
031cd210f7 | ||
|
|
9d9a434fdc | ||
|
|
41ed498d65 | ||
|
|
d28482557f | ||
|
|
4c97d54939 | ||
|
|
c08263d1c3 | ||
|
|
dc96466462 | ||
|
|
1734b387a3 | ||
|
|
871115e349 | ||
|
|
a764286879 | ||
|
|
5304461e4c | ||
|
|
6b25f08943 | ||
|
|
a0022e06f7 | ||
|
|
f24e65b6d8 | ||
|
|
0fb006c19f | ||
|
|
47a3f1a19d | ||
|
|
f25344182d | ||
|
|
f24e3a0a31 | ||
|
|
afb7bc309c | ||
|
|
cfee5aa3f4 | ||
|
|
2a51f6f385 | ||
|
|
4cffea43eb | ||
|
|
cafce5753d | ||
|
|
5d6a5f5d5e | ||
|
|
8e5a26dfb1 | ||
|
|
4cb0facd72 | ||
|
|
854bce28fb | ||
|
|
49e964c529 | ||
|
|
3281cea2a2 | ||
|
|
82253e91d2 | ||
|
|
1d1ed9a031 | ||
|
|
2bd8a2935f | ||
|
|
8a25e38827 | ||
|
|
4ec19d46fa | ||
|
|
d46a39e252 | ||
|
|
23e10d30be | ||
|
|
f049e2430a | ||
|
|
a53c66e8a4 | ||
|
|
4fb3492ea8 | ||
|
|
353f40ac3e | ||
|
|
96c831f726 | ||
|
|
59b3219f2d | ||
|
|
d7fdfc6cb2 | ||
|
|
d02f58b3cd | ||
|
|
62fee93d86 | ||
|
|
139c14d9e1 | ||
|
|
8ee15c6f77 | ||
|
|
5d17414018 | ||
|
|
3cd91846a6 | ||
|
|
e9eb8bdc86 | ||
|
|
3739cb1536 | ||
|
|
30f10ee8f0 | ||
|
|
dfb8788270 | ||
|
|
3810833e1b | ||
|
|
29e05c7c81 | ||
|
|
0a08285fac | ||
|
|
01f20a42ad | ||
|
|
3a61a2566b | ||
|
|
d2dda86529 | ||
|
|
cc125d2192 | ||
|
|
4da1e41d93 | ||
|
|
e24eb10c4f | ||
|
|
dd9e51fd16 | ||
|
|
9932d1413b | ||
|
|
ff13c49540 | ||
|
|
1e33b4bf26 | ||
|
|
e23a7df125 | ||
|
|
4ca476db9e | ||
|
|
33840c71cd | ||
|
|
1b983ef691 | ||
|
|
eec8c07d4f | ||
|
|
84ba93fc0a | ||
|
|
37a6f82659 | ||
|
|
b4aaa68d85 | ||
|
|
5487f34b9e | ||
|
|
e07734fa5f | ||
|
|
6a8e6cd762 | ||
|
|
663351029a | ||
|
|
c26e5fa7fe | ||
|
|
74c01dc448 | ||
|
|
a009c71034 | ||
|
|
b4ebc90dd0 | ||
|
|
95dc134ca6 | ||
|
|
9c4b7d8481 | ||
|
|
9fb9f2cae6 | ||
|
|
15f9b7d22e | ||
|
|
5f179ed6b0 | ||
|
|
93f9a7273e | ||
|
|
15e082896c | ||
|
|
63ff9751d7 | ||
|
|
d12c651d59 | ||
|
|
41a6c02aa3 | ||
|
|
a026e75c0e | ||
|
|
46815042c9 | ||
|
|
c79af52b67 | ||
|
|
e882dedac9 | ||
|
|
13277bbdb9 | ||
|
|
7e8a83aefb | ||
|
|
f1846191d5 | ||
|
|
a7c3f33447 | ||
|
|
a8d67edb44 | ||
|
|
89766b2e7e | ||
|
|
7d65d808f6 | ||
|
|
fa5e99d58d | ||
|
|
67c2d508ea | ||
|
|
19923d10db | ||
|
|
e57b6835e6 | ||
|
|
bcab7e7dc9 | ||
|
|
2572eedd89 | ||
|
|
efb45bfba6 | ||
|
|
4f38b5cf3f | ||
|
|
71b9772546 | ||
|
|
c13c389ae5 | ||
|
|
caf6f0ec6c | ||
|
|
4952ff7914 | ||
|
|
8981dcd645 | ||
|
|
470a53a548 | ||
|
|
7b65b7400e | ||
|
|
90c61abdb6 | ||
|
|
f8387b90ff | ||
|
|
feb02c54b9 | ||
|
|
49a2299414 | ||
|
|
43044bf88f | ||
|
|
0532d331a3 | ||
|
|
70fc05091f | ||
|
|
469e5c647e | ||
|
|
4bfb43a4ad | ||
|
|
5e0c7ae4f2 | ||
|
|
3daa7e55b7 | ||
|
|
6913502810 | ||
|
|
24971070f6 | ||
|
|
3d90e3a539 | ||
|
|
b5fdaa78cd | ||
|
|
f94adb5473 | ||
|
|
e34ba5689c | ||
|
|
7b5da8a2c9 | ||
|
|
451c82c815 | ||
|
|
488a76c5e3 | ||
|
|
a4bd966cc0 | ||
|
|
ecc36c9025 | ||
|
|
716daf027d | ||
|
|
0b7c32510b | ||
|
|
547dfa0d90 | ||
|
|
225a28258f | ||
|
|
e01b190e57 | ||
|
|
cd7d410262 | ||
|
|
4bcf90c693 | ||
|
|
0408415c61 | ||
|
|
c1c0c1ab44 | ||
|
|
3ea94940c2 | ||
|
|
321675ba99 | ||
|
|
9eb1418e36 | ||
|
|
d8804c699d | ||
|
|
4e9db74e29 | ||
|
|
7150ebde6b | ||
|
|
6fbd975e00 | ||
|
|
e0a1a47953 | ||
|
|
da757a19c6 | ||
|
|
ea13fd14c9 | ||
|
|
902a5d8f70 | ||
|
|
be0090be06 | ||
|
|
2d455bf0ca | ||
|
|
1d8e72646c | ||
|
|
c066136a06 | ||
|
|
46b53b31fd | ||
|
|
6093c4dd2e | ||
|
|
61ded01171 |
No files matched your search
@@ -9,3 +9,5 @@ tags
|
||||
*.swp
|
||||
SoObjects/SOGo/SOGo.framework/
|
||||
SoObjects/SOGo/derived_src/
|
||||
Tests/*/config.py
|
||||
*.pyc
|
||||
+11
-1
@@ -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
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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 = ¤t;
|
||||
|
||||
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 = ¤t;
|
||||
|
||||
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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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)\""
|
||||
|
||||
@@ -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
|
||||
@@ -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]];
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -911,7 +911,7 @@ fromProperties: (NSDictionary *) attachmentProps
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) save
|
||||
- (void) save:(TALLOC_CTX *) memCtx
|
||||
{
|
||||
NSArray *elements, *units;
|
||||
CardElement *element;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -146,7 +146,7 @@ static Class MAPIStoreAttachmentK;
|
||||
return ULLONG_MAX;
|
||||
}
|
||||
|
||||
- (void) save
|
||||
- (void) save: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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://%@@%@/%@/",
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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"]);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -357,7 +357,7 @@
|
||||
return rc;
|
||||
}
|
||||
|
||||
- (void) save
|
||||
- (void) save:(TALLOC_CTX *) memCtx
|
||||
{
|
||||
iCalCalendar *vCalendar;
|
||||
iCalToDo *vToDo;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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: " " 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
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
Executable
+84
@@ -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}
|
||||
@@ -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 */
|
||||
@@ -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.
@@ -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 */
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
- (void) setCompleted: (NSCalendarDate *) newCompletedDate
|
||||
{
|
||||
[(iCalDateTime *) [self uniqueChildWithTag: @"completed"]
|
||||
setDate: newCompletedDate];
|
||||
setDateTime: newCompletedDate];
|
||||
if (newCompletedDate)
|
||||
[self setStatus: @"COMPLETED"];
|
||||
else
|
||||
|
||||
@@ -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 =
|
||||
@@ -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()
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Executable
+52
@@ -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
@@ -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
@@ -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}.";
|
||||
@@ -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}\"";
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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
|
||||
@@ -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" = "دفتر العناوين الشخصية";
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -200,7 +200,10 @@
|
||||
|
||||
- (NSArray *) toOneRelationshipKeys
|
||||
{
|
||||
return [source allEntryIDs];
|
||||
NSString *userDomain;
|
||||
|
||||
userDomain = [[context activeUser] domain];
|
||||
return [source allEntryIDsVisibleFromDomain: userDomain];
|
||||
}
|
||||
|
||||
- (NSException *) saveLDIFEntry: (SOGoContactLDIFEntry *) ldifEntry
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
@@ -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,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
Reference in new issue
Block a user