Compare commits
909
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b57dd57c53 | ||
|
|
2102385f08 | ||
|
|
c0e528a2fb | ||
|
|
240557a5c5 | ||
|
|
ebd0b9e188 | ||
|
|
eefb9056ca | ||
|
|
cb03a1d97e | ||
|
|
9dd5dc4c47 | ||
|
|
aedb66f972 | ||
|
|
b808067cf7 | ||
|
|
f19b213c02 | ||
|
|
5aa19ebfb7 | ||
|
|
9e152adc7d | ||
|
|
fd8d7bb6ed | ||
|
|
72a38c51b4 | ||
|
|
599264b3d9 | ||
|
|
d4745ef598 | ||
|
|
fadf52b01e | ||
|
|
4e83dce4a6 | ||
|
|
540ed1f63b | ||
|
|
44f748659e | ||
|
|
9dd444e668 | ||
|
|
73decf2df9 | ||
|
|
f63ae5c3bb | ||
|
|
d60f49d8fa | ||
|
|
68cb3d091c | ||
|
|
9b58693873 | ||
|
|
0b7824a8b7 | ||
|
|
0a78b65cdc | ||
|
|
c34603b3eb | ||
|
|
d92bf122ed | ||
|
|
03ddcfd07a | ||
|
|
1d25944c43 | ||
|
|
da2067dd86 | ||
|
|
3529d52c3b | ||
|
|
30f23ba07a | ||
|
|
a93874b6fe | ||
|
|
12f4f236e8 | ||
|
|
699399f339 | ||
|
|
dc338e2062 | ||
|
|
163e4637aa | ||
|
|
ea91767410 | ||
|
|
a668d89ef9 | ||
|
|
50c790c846 | ||
|
|
de13f49bd3 | ||
|
|
044e426d22 | ||
|
|
a2e300fec5 | ||
|
|
07d47829ab | ||
|
|
4755358685 | ||
|
|
e27cdff8cc | ||
|
|
4526227b1c | ||
|
|
aeba0aaf2f | ||
|
|
795ec46c81 | ||
|
|
b294c5381a | ||
|
|
e5fe211dcd | ||
|
|
1016f6d8b8 | ||
|
|
70fbeab27a | ||
|
|
4b816677b0 | ||
|
|
5387b5d5a3 | ||
|
|
e51a37c37a | ||
|
|
58cb40caa7 | ||
|
|
9705fd7086 | ||
|
|
a8ccaac1fa | ||
|
|
42acf8974c | ||
|
|
a838871361 | ||
|
|
696aff84cb | ||
|
|
f143048217 | ||
|
|
e328d43403 | ||
|
|
aae02741f9 | ||
|
|
276588a548 | ||
|
|
31a51ccc83 | ||
|
|
aab87212d0 | ||
|
|
4030cf86fd | ||
|
|
1b5970b9bc | ||
|
|
ed4e70faab | ||
|
|
ef601c0409 | ||
|
|
21dcb57ca9 | ||
|
|
485a9d4462 | ||
|
|
7c00ad7110 | ||
|
|
95d0a18c08 | ||
|
|
10729b9a5f | ||
|
|
2de72e5070 | ||
|
|
4cd0c501bd | ||
|
|
1f71cff18d | ||
|
|
e47bc8cb1b | ||
|
|
6bb2065f46 | ||
|
|
1aab0595a1 | ||
|
|
9cb1b899b0 | ||
|
|
4c01417690 | ||
|
|
3d7192ffef | ||
|
|
2d3a5b4243 | ||
|
|
2edacc94ce | ||
|
|
e51f8625d6 | ||
|
|
635c647f48 | ||
|
|
929915542c | ||
|
|
42131c564a | ||
|
|
d56d9f8b08 | ||
|
|
a5cc2bb5d5 | ||
|
|
9e83ff9f04 | ||
|
|
f2ffb52318 | ||
|
|
5bd2f558bf | ||
|
|
520b1094be | ||
|
|
bd56f4cf9f | ||
|
|
7c25b53fdf | ||
|
|
e1b8d80420 | ||
|
|
132234cc19 | ||
|
|
4c6a0e6936 | ||
|
|
d5f95c6b30 | ||
|
|
5d28d81c1e | ||
|
|
5039a30405 | ||
|
|
256a64172e | ||
|
|
e897bb0399 | ||
|
|
4f1ce3f2df | ||
|
|
9d6e779bb0 | ||
|
|
c9e7eac3fd | ||
|
|
fbdcfd49fc | ||
|
|
297eefd58f | ||
|
|
decda96697 | ||
|
|
c8ea2000d8 | ||
|
|
d7b010526b | ||
|
|
9cc4bfd9be | ||
|
|
f70c0fa6e6 | ||
|
|
dfc0d23fa7 | ||
|
|
eb11e2e672 | ||
|
|
8d9ba7c04b | ||
|
|
fed57435d4 | ||
|
|
35af07fef1 | ||
|
|
99e5c1b93c | ||
|
|
31f0472db4 | ||
|
|
93158f5121 | ||
|
|
fec263a3d6 | ||
|
|
8c99fdc99a | ||
|
|
296d510572 | ||
|
|
51cbb980ad | ||
|
|
e6d1cb9231 | ||
|
|
6876ba8709 | ||
|
|
d2695bab82 | ||
|
|
37f4b11834 | ||
|
|
693f80dc9a | ||
|
|
f5b28b0274 | ||
|
|
1f3149fa63 | ||
|
|
cd181c3503 | ||
|
|
aa663fd03e | ||
|
|
2380890428 | ||
|
|
3e76de1e6e | ||
|
|
eff8ab3e0e | ||
|
|
187cd5e4ae | ||
|
|
4d702c2be9 | ||
|
|
5539b7a823 | ||
|
|
1c52093537 | ||
|
|
5a408bf14b | ||
|
|
ee3276f01d | ||
|
|
ace7e0771f | ||
|
|
1d2763af3c | ||
|
|
d63e277fc6 | ||
|
|
9e905b43ff | ||
|
|
9f7c205da9 | ||
|
|
89655cf192 | ||
|
|
7b4f4cbc0d | ||
|
|
03c6118224 | ||
|
|
f2da7d67d7 | ||
|
|
13a6290d0d | ||
|
|
7a401374f2 | ||
|
|
2cc37238c1 | ||
|
|
e3fbde3c16 | ||
|
|
b74dd0c942 | ||
|
|
dd19f380ad | ||
|
|
d3f59ba621 | ||
|
|
aa5d1f3842 | ||
|
|
c68ca9dbb7 | ||
|
|
5ccd33c126 | ||
|
|
82f0471fb1 | ||
|
|
7e06894700 | ||
|
|
1d868ff73c | ||
|
|
a49bb9ab03 | ||
|
|
d4ab5dd21b | ||
|
|
5624bf47ae | ||
|
|
d4e01a83a0 | ||
|
|
c12200c7b5 | ||
|
|
a8845d262f | ||
|
|
7437ca1ab8 | ||
|
|
66d4b9ec43 | ||
|
|
f321e1c949 | ||
|
|
0e2b1e41a7 | ||
|
|
1eced8bcec | ||
|
|
7099432caf | ||
|
|
0236d9ef46 | ||
|
|
c4fdba678e | ||
|
|
bd4f42b948 | ||
|
|
2bbb88e014 | ||
|
|
3c53186db3 | ||
|
|
1a7e5c248f | ||
|
|
47701e880a | ||
|
|
5413ac8aa3 | ||
|
|
cf91004ae6 | ||
|
|
15dee723d4 | ||
|
|
50791b9c3a | ||
|
|
fa9bd3995e | ||
|
|
4fb71ffdd0 | ||
|
|
6bfc44fb53 | ||
|
|
a95fd25e09 | ||
|
|
ff1dc9c82d | ||
|
|
b5a7447cba | ||
|
|
687521d60c | ||
|
|
b09e7163dd | ||
|
|
020f362aa1 | ||
|
|
c7283b8890 | ||
|
|
978e1cdaf0 | ||
|
|
c1ee1378ff | ||
|
|
ac8cf16885 | ||
|
|
fe0221f630 | ||
|
|
6e4aa79038 | ||
|
|
34215142bd | ||
|
|
0eb1b00c6b | ||
|
|
3339f53f19 | ||
|
|
d913bce41a | ||
|
|
b82c96a2dd | ||
|
|
85e181edc4 | ||
|
|
841e29b091 | ||
|
|
30a96f33e9 | ||
|
|
ce80cd5ec0 | ||
|
|
c9944f0265 | ||
|
|
dc2d153e0c | ||
|
|
c2322eedac | ||
|
|
b0f37e792f | ||
|
|
7b297ed483 | ||
|
|
5a927dfeb3 | ||
|
|
5e60a68634 | ||
|
|
be441f5cd3 | ||
|
|
b064512549 | ||
|
|
46c952ee13 | ||
|
|
c21a2c647a | ||
|
|
5754278ffa | ||
|
|
867bc4bc96 | ||
|
|
8a177bea47 | ||
|
|
53b2e19fee | ||
|
|
bf3a072e6b | ||
|
|
dd59ef6c1d | ||
|
|
5ad4d317df | ||
|
|
b265de91fd | ||
|
|
ec3e0e87f9 | ||
|
|
9a6cf0eb66 | ||
|
|
42c2edce19 | ||
|
|
99765aae53 | ||
|
|
3c0059192d | ||
|
|
81f13404bf | ||
|
|
30377c0fd6 | ||
|
|
88207d27c4 | ||
|
|
9ba7425e56 | ||
|
|
f1873edf21 | ||
|
|
54100c1f78 | ||
|
|
395400ca61 | ||
|
|
218aeb5f28 | ||
|
|
522dc5f85a | ||
|
|
8076a1a7ef | ||
|
|
164f7fd709 | ||
|
|
21f5dd747b | ||
|
|
914379884b | ||
|
|
a83080ae3a | ||
|
|
f3b7bf4728 | ||
|
|
9e8ecfac2c | ||
|
|
01fd6f4309 | ||
|
|
2537abf9e6 | ||
|
|
b316d928fc | ||
|
|
0b189e9ca7 | ||
|
|
629db3c728 | ||
|
|
612f2867a1 | ||
|
|
5076365956 | ||
|
|
a440defa61 | ||
|
|
c6bc8245a2 | ||
|
|
2e73b66e53 | ||
|
|
5c4da276bf | ||
|
|
3787296fd6 | ||
|
|
691ab3ff27 | ||
|
|
3fa0c83626 | ||
|
|
20adc2d821 | ||
|
|
a44ebee39a | ||
|
|
b55ef0d05b | ||
|
|
9984204987 | ||
|
|
e73fc61a27 | ||
|
|
9a831a85c0 | ||
|
|
c42fa9489c | ||
|
|
b3bc6bb7dc | ||
|
|
985db9465c | ||
|
|
defd9ab84b | ||
|
|
3f2c6efe7e | ||
|
|
be6bd47c15 | ||
|
|
eda112c4bd | ||
|
|
d29cdf2467 | ||
|
|
94b6213ba9 | ||
|
|
37a419a7ae | ||
|
|
2ba3371ea2 | ||
|
|
c7f1d8bb5e | ||
|
|
8593ee9fbb | ||
|
|
fe7a12bad0 | ||
|
|
d90e1dc0ec | ||
|
|
27bf8459c2 | ||
|
|
f5432525ec | ||
|
|
59cc13f41c | ||
|
|
3d4311194c | ||
|
|
667e6dff7c | ||
|
|
f3ea377bdb | ||
|
|
491f8b4f2a | ||
|
|
936f6cb073 | ||
|
|
78771d7abb | ||
|
|
e470996dcf | ||
|
|
ab23d0f766 | ||
|
|
2c59495005 | ||
|
|
279ee42d35 | ||
|
|
565ad6900b | ||
|
|
302187410c | ||
|
|
de47df7c76 | ||
|
|
d2f164dfb7 | ||
|
|
98e780dc6f | ||
|
|
dad9b71a5b | ||
|
|
77baffb85c | ||
|
|
09b3b4e13f | ||
|
|
dc43146a4e | ||
|
|
6ba9bd5295 | ||
|
|
1bcdac328a | ||
|
|
5f9c87cae3 | ||
|
|
b6076c9e8e | ||
|
|
321193472d | ||
|
|
0b5e38e88c | ||
|
|
4935eb23a9 | ||
|
|
96588aef6a | ||
|
|
f8d71966b9 | ||
|
|
c86499f658 | ||
|
|
68c72f681c | ||
|
|
78dfe84d41 | ||
|
|
a1647d9cd0 | ||
|
|
030272d48a | ||
|
|
ed799c5c35 | ||
|
|
a755546f75 | ||
|
|
8237aaf74a | ||
|
|
9d9f7b4c56 | ||
|
|
c355254467 | ||
|
|
6ffeba59ed | ||
|
|
609c5aabf7 | ||
|
|
0bbdd01025 | ||
|
|
c65a9155be | ||
|
|
b19d894f27 | ||
|
|
23cc8154cc | ||
|
|
2acf9830f1 | ||
|
|
7121233a18 | ||
|
|
ae6ed0c055 | ||
|
|
d05fd407bd | ||
|
|
0d43b02cab | ||
|
|
ccc0d61202 | ||
|
|
d18e80df08 | ||
|
|
d08c490992 | ||
|
|
6464e35704 | ||
|
|
711e159b4b | ||
|
|
ee4e46439f | ||
|
|
b8a7a43fd0 | ||
|
|
50f4f8a5c6 | ||
|
|
1419f4b6ca | ||
|
|
1e45606681 | ||
|
|
1c0cd2bc28 | ||
|
|
662201a428 | ||
|
|
39510a3242 | ||
|
|
3cd1c641ab | ||
|
|
d8f5673a14 | ||
|
|
c08f507dbf | ||
|
|
40d9fa059f | ||
|
|
33f03f1cfc | ||
|
|
2628b0e79a | ||
|
|
f778031176 | ||
|
|
b7bfc17f5b | ||
|
|
80533a6f9a | ||
|
|
530e7a9d99 | ||
|
|
d2ecb1e95e | ||
|
|
39dfc84800 | ||
|
|
140803ebf2 | ||
|
|
d225865a3f | ||
|
|
904c2f071a | ||
|
|
f496f2b28f | ||
|
|
b1b8116aff | ||
|
|
e67661e84b | ||
|
|
0f4e966ecf | ||
|
|
89e947b07b | ||
|
|
fe6bd70b72 | ||
|
|
020563016b | ||
|
|
52863bf820 | ||
|
|
4973580b4b | ||
|
|
84199e9c70 | ||
|
|
8ff6fc8c1f | ||
|
|
3404ae8105 | ||
|
|
76f0ec9ae0 | ||
|
|
0f578876af | ||
|
|
cfb741fc9f | ||
|
|
544cb85e4d | ||
|
|
ffe4d0f232 | ||
|
|
43926f28cb | ||
|
|
5a8d986cad | ||
|
|
c7068b11a7 | ||
|
|
5499746b3a | ||
|
|
bb102e07e1 | ||
|
|
558795327e | ||
|
|
bbb9f31c29 | ||
|
|
5a1816a5d4 | ||
|
|
38fecebafd | ||
|
|
6dd5210cbf | ||
|
|
04a6e579cf | ||
|
|
5dfb57a955 | ||
|
|
4b5abdb5ce | ||
|
|
0b10e20d37 | ||
|
|
12da6dc021 | ||
|
|
bf07ed5043 | ||
|
|
153c2c33e5 | ||
|
|
96e93c0eeb | ||
|
|
28399b698a | ||
|
|
2657612136 | ||
|
|
89ae2a3d8d | ||
|
|
cfe6a30d64 | ||
|
|
b74b73bca4 | ||
|
|
eb539c1354 | ||
|
|
6672e03c22 | ||
|
|
ccd031693e | ||
|
|
156463c084 | ||
|
|
95ca7d0193 | ||
|
|
28163b859c | ||
|
|
49fb7b3487 | ||
|
|
20b3a98282 | ||
|
|
6e988404d9 | ||
|
|
93ced64456 | ||
|
|
fcf88444c9 | ||
|
|
ad550a61bc | ||
|
|
f4e80aa819 | ||
|
|
450e3f03e2 | ||
|
|
889570d672 | ||
|
|
845624f569 | ||
|
|
90299dbe91 | ||
|
|
52fd2174b8 | ||
|
|
9389957b5f | ||
|
|
5020e3658b | ||
|
|
767bad7c94 | ||
|
|
9926653faa | ||
|
|
903c4280f4 | ||
|
|
8ad854e30d | ||
|
|
aa54210c44 | ||
|
|
464a405cee | ||
|
|
5e978940f9 | ||
|
|
38e5588c67 | ||
|
|
db96b2830e | ||
|
|
24520418f9 | ||
|
|
623f2720f5 | ||
|
|
ccdb968e22 | ||
|
|
8d115733c3 | ||
|
|
375cccacc2 | ||
|
|
bc1d9020cc | ||
|
|
c3ce235972 | ||
|
|
b10f3e1d62 | ||
|
|
7b1febe841 | ||
|
|
5289079d67 | ||
|
|
76dd9b1b32 | ||
|
|
a79205fb7c | ||
|
|
11d03569a4 | ||
|
|
ee71829134 | ||
|
|
04e0286992 | ||
|
|
ecf297208a | ||
|
|
a4bc4fc652 | ||
|
|
e14414ed56 | ||
|
|
efba979f3d | ||
|
|
9b5d37ff3d | ||
|
|
e80c7da188 | ||
|
|
b4aa8b27d4 | ||
|
|
3cd973b365 | ||
|
|
c427a62fb0 | ||
|
|
d19369a5aa | ||
|
|
f4679ec4ab | ||
|
|
fee7adfc0c | ||
|
|
9b0a2c5fae | ||
|
|
9e776be2ce | ||
|
|
4189406962 | ||
|
|
348ba65c6e | ||
|
|
af5599015b | ||
|
|
8f8885a8ea | ||
|
|
9c2d7b5316 | ||
|
|
8635eab502 | ||
|
|
b02de72e57 | ||
|
|
b2c2fc5dcd | ||
|
|
f0ec431f30 | ||
|
|
38963916aa | ||
|
|
970f5e5bfe | ||
|
|
5bb6cea09e | ||
|
|
0660db7bf6 | ||
|
|
827bc00982 | ||
|
|
d51d5c85b0 | ||
|
|
fdb36970d4 | ||
|
|
77755770a8 | ||
|
|
3106fa44c8 | ||
|
|
33edaacb13 | ||
|
|
d19593afc3 | ||
|
|
403d6fa54f | ||
|
|
39455a283a | ||
|
|
6d29e50f22 | ||
|
|
656835ca19 | ||
|
|
62255eaf33 | ||
|
|
ba7670ad59 | ||
|
|
adb3c3a0e6 | ||
|
|
dbffc50f06 | ||
|
|
4d0361759a | ||
|
|
fe3f1d6678 | ||
|
|
93fa67c492 | ||
|
|
00b22a71db | ||
|
|
2e2d8b6963 | ||
|
|
bb88643568 | ||
|
|
f161cbe56b | ||
|
|
71b03b925d | ||
|
|
0114f8dc6a | ||
|
|
877ce7e4e4 | ||
|
|
418d30193b | ||
|
|
4edb87978b | ||
|
|
faa5d83cf6 | ||
|
|
5f54ee09f1 | ||
|
|
5c6e19a67c | ||
|
|
77fa55c6a4 | ||
|
|
6c1e443d01 | ||
|
|
6918650f5b | ||
|
|
b9462ed86d | ||
|
|
3d75d6affa | ||
|
|
69ff0634b4 | ||
|
|
00c923df7a | ||
|
|
b6930fde26 | ||
|
|
5a5b4cc829 | ||
|
|
333d279246 | ||
|
|
9a12fb24a6 | ||
|
|
888db0b1be | ||
|
|
3ec8847590 | ||
|
|
823da43776 | ||
|
|
c2d539d3c8 | ||
|
|
edf69e5989 | ||
|
|
6cdf9f55b4 | ||
|
|
3baef22df4 | ||
|
|
90e79e7605 | ||
|
|
6a3a249bd6 | ||
|
|
c5017fc69e | ||
|
|
7c86a43e48 | ||
|
|
e4eef9b780 | ||
|
|
2d6bdd37da | ||
|
|
450ec06bd8 | ||
|
|
0bd29e250e | ||
|
|
4685c0ff2a | ||
|
|
ace9fa9e4e | ||
|
|
58dfa2e43b | ||
|
|
9d0bc5570b | ||
|
|
5ed142853a | ||
|
|
fc1dfcff10 | ||
|
|
4f6c099564 | ||
|
|
d081f3c6eb | ||
|
|
98493fbcac | ||
|
|
b30f20e1b3 | ||
|
|
87fc7b39cc | ||
|
|
c7ef7a1d2f | ||
|
|
7316d13176 | ||
|
|
6a9e3a6e96 | ||
|
|
0f2d0e9069 | ||
|
|
cc5cc30c24 | ||
|
|
dc3e42fd62 | ||
|
|
d23f7f1cc2 | ||
|
|
a576b95663 | ||
|
|
2e02380a93 | ||
|
|
fc16d6ad90 | ||
|
|
bdfe95a7fb | ||
|
|
0d919dbd02 | ||
|
|
c18f5c2246 | ||
|
|
ab322093cd | ||
|
|
350fe2e7e0 | ||
|
|
f3f7ca8599 | ||
|
|
3a103fd0dd | ||
|
|
c5cac316c3 | ||
|
|
a8525658b3 | ||
|
|
5f82d3fb37 | ||
|
|
edebdf1171 | ||
|
|
9fb69a8095 | ||
|
|
bf87c71671 | ||
|
|
30488f4f6d | ||
|
|
4ca3a1f42d | ||
|
|
efbf8825b1 | ||
|
|
becfdc215f | ||
|
|
d805cdfef4 | ||
|
|
cc1555af22 | ||
|
|
72b1fc1f3f | ||
|
|
12863f1d2f | ||
|
|
39601a9cf9 | ||
|
|
0cb1504f2c | ||
|
|
d19c883622 | ||
|
|
a1c6a6676e | ||
|
|
59c8a0f722 | ||
|
|
6dc912eee5 | ||
|
|
1a0915ebf6 | ||
|
|
6bff05b84a | ||
|
|
b5eb13c3b7 | ||
|
|
1fab2028e2 | ||
|
|
b7ebf6e781 | ||
|
|
d9a929762f | ||
|
|
165337bebc | ||
|
|
46ccd04c70 | ||
|
|
440a86d3f2 | ||
|
|
0b4c355c2c | ||
|
|
36c1ba88a5 | ||
|
|
2303a250c5 | ||
|
|
cbf9b6da3e | ||
|
|
a64d55f95c | ||
|
|
9a3f8549ea | ||
|
|
212ff64828 | ||
|
|
7541fb62e0 | ||
|
|
e5c71a4179 | ||
|
|
3c62cc744e | ||
|
|
0b490a00c6 | ||
|
|
2bad5c0da4 | ||
|
|
293b93ec69 | ||
|
|
dc385a82ff | ||
|
|
4172c216f5 | ||
|
|
09e354ed0e | ||
|
|
d7fb79381e | ||
|
|
700a00b822 | ||
|
|
ffbc20916a | ||
|
|
746eea4bb6 | ||
|
|
987700cd87 | ||
|
|
a55d5c95b5 | ||
|
|
907c30061f | ||
|
|
2ee09159a2 | ||
|
|
114622fee0 | ||
|
|
74085ed96b | ||
|
|
8979aebe31 | ||
|
|
020fa78848 | ||
|
|
ddf97ebb13 | ||
|
|
b02a4f82a0 | ||
|
|
2c2c5241eb | ||
|
|
24ad2493a4 | ||
|
|
e0e4a94b87 | ||
|
|
dc3741f436 | ||
|
|
feac8bb8f4 | ||
|
|
9f11e68de8 | ||
|
|
15de70b938 | ||
|
|
ea24e9586b | ||
|
|
4e9911419a | ||
|
|
bfa3cf379c | ||
|
|
4002da9323 | ||
|
|
d5c09f6114 | ||
|
|
737a19e653 | ||
|
|
43248fb5ea | ||
|
|
1118dbceff | ||
|
|
369060a52f | ||
|
|
4da53b88b6 | ||
|
|
8924a2b670 | ||
|
|
62537e0c15 | ||
|
|
7ef976bfe4 | ||
|
|
05515673b7 | ||
|
|
84f4698225 | ||
|
|
e5fdc28241 | ||
|
|
7ddf7be705 | ||
|
|
b63ee6998d | ||
|
|
0b3095f7ed | ||
|
|
e88af22708 | ||
|
|
d68008b5fd | ||
|
|
e2d6e8ffe9 | ||
|
|
2ad02b8386 | ||
|
|
58afdedcc1 | ||
|
|
e6be7e00ba | ||
|
|
74eb0846e8 | ||
|
|
4f4b00cc54 | ||
|
|
ad40bff91f | ||
|
|
13f4e5a4de | ||
|
|
459b183a42 | ||
|
|
9fa9b7acab | ||
|
|
a393128d7a | ||
|
|
73ac55acfe | ||
|
|
e1393c3af2 | ||
|
|
d27c792324 | ||
|
|
42d306a24b | ||
|
|
6a7e06b0bb | ||
|
|
e36e9fd826 | ||
|
|
aface8f8cf | ||
|
|
790fc8e940 | ||
|
|
35d1ca8775 | ||
|
|
e8ca329070 | ||
|
|
f4ed7d9448 | ||
|
|
c7825601e6 | ||
|
|
d07e254026 | ||
|
|
0f08571a83 | ||
|
|
781e408091 | ||
|
|
549c57f8a6 | ||
|
|
45bc5a5368 | ||
|
|
d51bef162a | ||
|
|
1535660a31 | ||
|
|
90063ae563 | ||
|
|
b27cfc2bd8 | ||
|
|
5496dd97d9 | ||
|
|
31f2e4b549 | ||
|
|
ec8c2d08e2 | ||
|
|
1ce9d71635 | ||
|
|
a6c440d245 | ||
|
|
e3d3eb171d | ||
|
|
3a4365b15a | ||
|
|
7f3d57c8dc | ||
|
|
e93853d910 | ||
|
|
fcba6f2ddb | ||
|
|
eb50f94b2b | ||
|
|
9f7b69b037 | ||
|
|
c6cd3b0e1d | ||
|
|
31026a5bed | ||
|
|
08fbc00d7a | ||
|
|
957336b24c | ||
|
|
2a925de52c | ||
|
|
cf8dd02411 | ||
|
|
da37b3f868 | ||
|
|
24450a9c20 | ||
|
|
964f79db35 | ||
|
|
c0f51cf731 | ||
|
|
ae3ce7186d | ||
|
|
5034a72ed1 | ||
|
|
fdad1e061a | ||
|
|
d5d54822b0 | ||
|
|
81cdf5be7b | ||
|
|
959ea0f62f | ||
|
|
1c666e8ead | ||
|
|
7692832672 | ||
|
|
2bfd9f983d | ||
|
|
2a5e19a762 | ||
|
|
258f5e0b25 | ||
|
|
3609e41205 | ||
|
|
2ea2edbccd | ||
|
|
fab9e938fc | ||
|
|
9a2f3914e2 | ||
|
|
f13b3dd201 | ||
|
|
413550a025 | ||
|
|
06ac255f1a | ||
|
|
0682b24438 | ||
|
|
a01926b878 | ||
|
|
58ff8139e9 | ||
|
|
70bb512bb8 | ||
|
|
7b580f8af6 | ||
|
|
11d9765a69 | ||
|
|
24a3ecd2d6 | ||
|
|
139ed39663 | ||
|
|
875d23aea0 | ||
|
|
c4ad8a64fa | ||
|
|
c464791d92 | ||
|
|
92bf494973 | ||
|
|
47ab4b837c | ||
|
|
e30fb0d1fb | ||
|
|
3efbf65f80 | ||
|
|
0982d50643 | ||
|
|
532105f1fa | ||
|
|
7cdfaf4d9c | ||
|
|
8cb19546df | ||
|
|
6dc02abe80 | ||
|
|
f70876aa05 | ||
|
|
3efdbf0166 | ||
|
|
348c81bf6c | ||
|
|
44158af057 | ||
|
|
4bb1fa0995 | ||
|
|
05882362f0 | ||
|
|
90a3fcacaf | ||
|
|
45ac6845a5 | ||
|
|
b4af6f5033 | ||
|
|
6bbd182559 | ||
|
|
7290fa2ea2 | ||
|
|
788f36b96e | ||
|
|
cb0d327f90 | ||
|
|
b646e35f5d | ||
|
|
f3a5df37ae | ||
|
|
7a7547c7c3 | ||
|
|
11e7af3450 | ||
|
|
16d312eb98 | ||
|
|
295b53df66 | ||
|
|
cab6a8c1e2 | ||
|
|
59ad8a2e5a | ||
|
|
ab8feff67d | ||
|
|
b9294da996 | ||
|
|
18a300ca5b | ||
|
|
b8b45eda75 | ||
|
|
370be4f835 | ||
|
|
2720aebf04 | ||
|
|
bf02b3046f | ||
|
|
3d4a965412 | ||
|
|
372206e69e | ||
|
|
9dc00acd53 | ||
|
|
9d5f42eefa | ||
|
|
f4dcd37570 | ||
|
|
c4858ffb2b | ||
|
|
d72188e2da | ||
|
|
3647f066da | ||
|
|
e207cc79a7 | ||
|
|
eb84e618e6 | ||
|
|
669bd99a2d | ||
|
|
3b0ead7bbd | ||
|
|
4483d47e89 | ||
|
|
a5213b3321 | ||
|
|
e6e34ae053 | ||
|
|
815b3b4b03 | ||
|
|
b08d98e2e1 | ||
|
|
1d2c0ed350 | ||
|
|
0bdbe5bbac | ||
|
|
acfa96263b | ||
|
|
99b1353faf | ||
|
|
27e57e397e | ||
|
|
778612bf41 | ||
|
|
9d92318524 | ||
|
|
cf9b7fab36 | ||
|
|
f1037e7d48 | ||
|
|
233b9c0613 | ||
|
|
89206f3705 | ||
|
|
a87daf282c | ||
|
|
fb4889a15e | ||
|
|
3fdabf8671 | ||
|
|
66c52f22dd | ||
|
|
8f7334f11d | ||
|
|
624833eca9 | ||
|
|
431c53b84d | ||
|
|
c9d9f7b47a | ||
|
|
1667f8879d | ||
|
|
3611c4021d | ||
|
|
bba0d6f44d | ||
|
|
bf390f17dd | ||
|
|
834aba85a6 | ||
|
|
d878c69c15 | ||
|
|
d9d59c6b52 | ||
|
|
69000a0929 | ||
|
|
876d9cfa21 | ||
|
|
117e6b6bc1 | ||
|
|
01e2256483 | ||
|
|
49e7cf0994 | ||
|
|
b3d6973fb1 | ||
|
|
aae522259f | ||
|
|
68ef8784a0 | ||
|
|
da821ea6c7 | ||
|
|
4dee99e0ba | ||
|
|
eea08d083d | ||
|
|
8055acfd4a | ||
|
|
1fc947d8c8 | ||
|
|
7b3a238fb9 | ||
|
|
99d121fd3e | ||
|
|
eab3ee111a | ||
|
|
9445315b30 | ||
|
|
eeb6be1f08 | ||
|
|
c106f54b27 | ||
|
|
29108bbb62 | ||
|
|
9c6884bd7d | ||
|
|
0aac4897fa | ||
|
|
2a99d1fd80 | ||
|
|
ba148eec5b | ||
|
|
49c4884cc9 | ||
|
|
e5d6ee93c3 | ||
|
|
40eff05d4e | ||
|
|
be031fe2c9 | ||
|
|
0fe1419289 | ||
|
|
9db633cada | ||
|
|
8a2d7d56e0 | ||
|
|
0c17e745f1 | ||
|
|
18bc75e50b | ||
|
|
68ad3c1045 | ||
|
|
85c8aebbd4 | ||
|
|
0a8834193f | ||
|
|
91e4c2cefc | ||
|
|
b80d8dbb06 | ||
|
|
525d1ad80f | ||
|
|
332dd0d96d | ||
|
|
a45000d15d | ||
|
|
3301bdb055 | ||
|
|
2f82b5cfd3 | ||
|
|
e3b64e035d | ||
|
|
1470258b5c | ||
|
|
83fee27ca8 | ||
|
|
e5b0596bc9 | ||
|
|
26e8276b08 | ||
|
|
078ba95f8e | ||
|
|
65525dd33b | ||
|
|
da81f7bc58 | ||
|
|
8fcd594be6 | ||
|
|
548f056b9c | ||
|
|
dffdbf318c | ||
|
|
161bcfac87 | ||
|
|
c6f17cd45c | ||
|
|
38713a6c67 | ||
|
|
8cef98eba1 | ||
|
|
2144d3122a | ||
|
|
9d272ae063 | ||
|
|
fcd0140ffd | ||
|
|
d783782af7 | ||
|
|
869b3c4cd1 | ||
|
|
2da2937391 | ||
|
|
5034d6655a | ||
|
|
d1446f7dc1 | ||
|
|
c5a219add8 | ||
|
|
bc2c839fbc | ||
|
|
2e736490d5 | ||
|
|
20bf66d931 | ||
|
|
864a7f8028 | ||
|
|
7b5541b5d1 | ||
|
|
744cba4422 | ||
|
|
ded467e0a2 | ||
|
|
a718b87d91 | ||
|
|
6e2e71b202 | ||
|
|
04e63e5edf | ||
|
|
f1a50bcb74 | ||
|
|
0672b96b8b | ||
|
|
93fa74d279 | ||
|
|
ffa4079fa8 | ||
|
|
8f75bdce2d | ||
|
|
4f53ea70e1 | ||
|
|
b72a9383a4 | ||
|
|
d3d9a720dc | ||
|
|
02daebe36b | ||
|
|
336e4c93e9 | ||
|
|
47252affba |
No files matched your search
+5
-6
@@ -9,6 +9,7 @@
|
||||
*/*/obj/
|
||||
*/obj/
|
||||
.scss-lint-config.yml_
|
||||
ActiveSync/ActiveSync.SOGo
|
||||
Documentation/*.docbook
|
||||
Documentation/*.pdf
|
||||
SoObjects/SOGo/SOGo.framework/
|
||||
@@ -20,12 +21,10 @@ UI/WebServerResources/bower_components/
|
||||
UI/WebServerResources/css/
|
||||
UI/WebServerResources/css/styles.css
|
||||
UI/WebServerResources/css/styles.css.map
|
||||
UI/WebServerResources/js/Common.js*
|
||||
UI/WebServerResources/js/Contacts.js*
|
||||
UI/WebServerResources/js/Mailer.js*
|
||||
UI/WebServerResources/js/Preferences.js*
|
||||
UI/WebServerResources/js/Scheduler.js*
|
||||
UI/WebServerResources/js/vendor/
|
||||
UI/WebServerResources/js/*.js
|
||||
UI/WebServerResources/js/*.js.map
|
||||
UI/WebServerResources/js/vendor/*.js
|
||||
UI/WebServerResources/js/vendor/*.js.map
|
||||
UI/WebServerResources/node_modules/
|
||||
UI/WebServerResources/scss/.sass-cache/
|
||||
config.make
|
||||
|
||||
+33
@@ -15,13 +15,16 @@ trans.es_ES = UI/MailerUI/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/MailerUI/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/MailerUI/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/MailerUI/French.lproj/Localizable.strings
|
||||
trans.hr_HR = UI/MailerUI/Croatian.lproj/Localizable.strings
|
||||
trans.hu = UI/MailerUI/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/MailerUI/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/MailerUI/Italian.lproj/Localizable.strings
|
||||
trans.mk_MK = UI/MailerUI/Macedonian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/MailerUI/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/MailerUI/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/MailerUI/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/MailerUI/Polish.lproj/Localizable.strings
|
||||
trans.pt = UI/MailerUI/Portuguese.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/MailerUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/MailerUI/Slovak.lproj/Localizable.strings
|
||||
@@ -44,13 +47,16 @@ trans.es_ES = UI/PreferencesUI/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/PreferencesUI/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/PreferencesUI/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/PreferencesUI/French.lproj/Localizable.strings
|
||||
trans.hr_HR = UI/PreferencesUI/Croatian.lproj/Localizable.strings
|
||||
trans.hu = UI/PreferencesUI/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/PreferencesUI/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/PreferencesUI/Italian.lproj/Localizable.strings
|
||||
trans.mk_MK = UI/PreferencesUI/Macedonian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/PreferencesUI/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/PreferencesUI/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/PreferencesUI/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/PreferencesUI/Polish.lproj/Localizable.strings
|
||||
trans.pt = UI/PreferencesUI/Portuguese.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/PreferencesUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/PreferencesUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/PreferencesUI/Slovak.lproj/Localizable.strings
|
||||
@@ -73,13 +79,16 @@ trans.es_ES = UI/Scheduler/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/Scheduler/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/Scheduler/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/Scheduler/French.lproj/Localizable.strings
|
||||
trans.hr_HR = UI/Scheduler/Croatian.lproj/Localizable.strings
|
||||
trans.hu = UI/Scheduler/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/Scheduler/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/Scheduler/Italian.lproj/Localizable.strings
|
||||
trans.mk_MK = UI/Scheduler/Macedonian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/Scheduler/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/Scheduler/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/Scheduler/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/Scheduler/Polish.lproj/Localizable.strings
|
||||
trans.pt = UI/Scheduler/Portuguese.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/Scheduler/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/Scheduler/Slovak.lproj/Localizable.strings
|
||||
@@ -102,13 +111,16 @@ trans.es_ES = UI/Contacts/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/Contacts/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/Contacts/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/Contacts/French.lproj/Localizable.strings
|
||||
trans.hr_HR = UI/Contacts/Croatian.lproj/Localizable.strings
|
||||
trans.hu = UI/Contacts/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/Contacts/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/Contacts/Italian.lproj/Localizable.strings
|
||||
trans.mk_MK = UI/Contacts/Macedonian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/Contacts/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/Contacts/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/Contacts/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/Contacts/Polish.lproj/Localizable.strings
|
||||
trans.pt = UI/Contacts/Portuguese.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/Contacts/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/Contacts/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/Contacts/Slovak.lproj/Localizable.strings
|
||||
@@ -131,13 +143,16 @@ trans.es_ES = UI/MainUI/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/MainUI/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/MainUI/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/MainUI/French.lproj/Localizable.strings
|
||||
trans.hr_HR = UI/MainUI/Croatian.lproj/Localizable.strings
|
||||
trans.hu = UI/MainUI/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/MainUI/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/MainUI/Italian.lproj/Localizable.strings
|
||||
trans.mk_MK = UI/MainUI/Macedonian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/MainUI/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/MainUI/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/MainUI/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/MainUI/Polish.lproj/Localizable.strings
|
||||
trans.pt = UI/MainUI/Portuguese.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/MainUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/MainUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/MainUI/Slovak.lproj/Localizable.strings
|
||||
@@ -160,13 +175,16 @@ trans.es_ES = UI/Common/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/Common/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/Common/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/Common/French.lproj/Localizable.strings
|
||||
trans.hr_HR = UI/Common/Croatian.lproj/Localizable.strings
|
||||
trans.hu = UI/Common/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/Common/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/Common/Italian.lproj/Localizable.strings
|
||||
trans.mk_MK = UI/Common/Macedonian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/Common/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/Common/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/Common/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/Common/Polish.lproj/Localizable.strings
|
||||
trans.pt = UI/Common/Portuguese.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/Common/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/Common/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/Common/Slovak.lproj/Localizable.strings
|
||||
@@ -189,13 +207,16 @@ trans.es_ES = UI/AdministrationUI/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/AdministrationUI/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/AdministrationUI/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/AdministrationUI/French.lproj/Localizable.strings
|
||||
trans.hr_HR = UI/AdministrationUI/Croatian.lproj/Localizable.strings
|
||||
trans.hu = UI/AdministrationUI/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/AdministrationUI/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/AdministrationUI/Italian.lproj/Localizable.strings
|
||||
trans.mk_MK = UI/AdministrationUI/Macedonian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/AdministrationUI/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/AdministrationUI/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/AdministrationUI/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/AdministrationUI/Polish.lproj/Localizable.strings
|
||||
trans.pt = UI/AdministrationUI/Portuguese.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/AdministrationUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/AdministrationUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/AdministrationUI/Slovak.lproj/Localizable.strings
|
||||
@@ -218,13 +239,16 @@ trans.es_ES = SoObjects/Appointments/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = SoObjects/Appointments/Basque.lproj/Localizable.strings
|
||||
trans.fi = SoObjects/Appointments/Finnish.lproj/Localizable.strings
|
||||
trans.fr = SoObjects/Appointments/French.lproj/Localizable.strings
|
||||
trans.hr_HR = SoObjects/Appointments/Croatian.lproj/Localizable.strings
|
||||
trans.hu = SoObjects/Appointments/Hungarian.lproj/Localizable.strings
|
||||
trans.is = SoObjects/Appointments/Icelandic.lproj/Localizable.strings
|
||||
trans.it = SoObjects/Appointments/Italian.lproj/Localizable.strings
|
||||
trans.mk_MK = SoObjects/Appointments/Macedonian.lproj/Localizable.strings
|
||||
trans.nb_NO = SoObjects/Appointments/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = SoObjects/Appointments/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = SoObjects/Appointments/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = SoObjects/Appointments/Polish.lproj/Localizable.strings
|
||||
trans.pt = SoObjects/Appointments/Portuguese.lproj/Localizable.strings
|
||||
trans.pt_BR = SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = SoObjects/Appointments/Russian.lproj/Localizable.strings
|
||||
trans.sk = SoObjects/Appointments/Slovak.lproj/Localizable.strings
|
||||
@@ -247,13 +271,16 @@ trans.es_ES = SoObjects/Contacts/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = SoObjects/Contacts/Basque.lproj/Localizable.strings
|
||||
trans.fi = SoObjects/Contacts/Finnish.lproj/Localizable.strings
|
||||
trans.fr = SoObjects/Contacts/French.lproj/Localizable.strings
|
||||
trans.hr_HR = SoObjects/Contacts/Croatian.lproj/Localizable.strings
|
||||
trans.hu = SoObjects/Contacts/Hungarian.lproj/Localizable.strings
|
||||
trans.is = SoObjects/Contacts/Icelandic.lproj/Localizable.strings
|
||||
trans.it = SoObjects/Contacts/Italian.lproj/Localizable.strings
|
||||
trans.mk_MK = SoObjects/Contacts/Macedonian.lproj/Localizable.strings
|
||||
trans.nb_NO = SoObjects/Contacts/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = SoObjects/Contacts/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = SoObjects/Contacts/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = SoObjects/Contacts/Polish.lproj/Localizable.strings
|
||||
trans.pt = SoObjects/Contacts/Portuguese.lproj/Localizable.strings
|
||||
trans.pt_BR = SoObjects/Contacts/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = SoObjects/Contacts/Russian.lproj/Localizable.strings
|
||||
trans.sk = SoObjects/Contacts/Slovak.lproj/Localizable.strings
|
||||
@@ -276,13 +303,16 @@ trans.es_ES = SoObjects/Mailer/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = SoObjects/Mailer/Basque.lproj/Localizable.strings
|
||||
trans.fi = SoObjects/Mailer/Finnish.lproj/Localizable.strings
|
||||
trans.fr = SoObjects/Mailer/French.lproj/Localizable.strings
|
||||
trans.hr_HR = SoObjects/Mailer/Croatian.lproj/Localizable.strings
|
||||
trans.hu = SoObjects/Mailer/Hungarian.lproj/Localizable.strings
|
||||
trans.is = SoObjects/Mailer/Icelandic.lproj/Localizable.strings
|
||||
trans.it = SoObjects/Mailer/Italian.lproj/Localizable.strings
|
||||
trans.mk_MK = SoObjects/Mailer/Macedonian.lproj/Localizable.strings
|
||||
trans.nb_NO = SoObjects/Mailer/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = SoObjects/Mailer/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = SoObjects/Mailer/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = SoObjects/Mailer/Polish.lproj/Localizable.strings
|
||||
trans.pt = SoObjects/Mailer/Portuguese.lproj/Localizable.strings
|
||||
trans.pt_BR = SoObjects/Mailer/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = SoObjects/Mailer/Russian.lproj/Localizable.strings
|
||||
trans.sk = SoObjects/Mailer/Slovak.lproj/Localizable.strings
|
||||
@@ -305,13 +335,16 @@ trans.es_ES = UI/MailPartViewers/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/MailPartViewers/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/MailPartViewers/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/MailPartViewers/French.lproj/Localizable.strings
|
||||
trans.hr_HR = UI/MailPartViewers/Croatian.lproj/Localizable.strings
|
||||
trans.hu = UI/MailPartViewers/Hungarian.lproj/Localizable.strings
|
||||
trans.is = UI/MailPartViewers/Icelandic.lproj/Localizable.strings
|
||||
trans.it = UI/MailPartViewers/Italian.lproj/Localizable.strings
|
||||
trans.mk_MK = UI/MailPartViewers/Macedonian.lproj/Localizable.strings
|
||||
trans.nb_NO = UI/MailPartViewers/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = UI/MailPartViewers/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = UI/MailPartViewers/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = UI/MailPartViewers/Polish.lproj/Localizable.strings
|
||||
trans.pt = UI/MailPartViewers/Portuguese.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/MailPartViewers/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/MailPartViewers/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/MailPartViewers/Slovak.lproj/Localizable.strings
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
# compilation settings
|
||||
ifeq ($(HAS_LIBRARY_ssl),yes)
|
||||
ADDITIONAL_CPPFLAGS += -DHAVE_OPENSSL=1
|
||||
BUNDLE_LIBS += -lcrypto
|
||||
endif
|
||||
@@ -31,7 +31,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define __NGDOMELEMENTACTIVESYNC_H__
|
||||
|
||||
#import <DOM/DOMElement.h>
|
||||
#import <DOM/DOMProtocols.h>
|
||||
|
||||
@class NSDictionary;
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ static NSArray *asElementArray = nil;
|
||||
int i, count;
|
||||
|
||||
if (!asElementArray)
|
||||
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", @"Category", nil];
|
||||
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", @"Category", @"Exception", nil];
|
||||
|
||||
data = [NSMutableDictionary dictionary];
|
||||
|
||||
|
||||
@@ -30,8 +30,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import "NGMimeMessage+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGMail/NGMailAddress.h>
|
||||
#import <NGMail/NGMailAddressParser.h>
|
||||
|
||||
+196
-54
@@ -29,16 +29,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#import "NGVCard+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
|
||||
#import <NGCards/CardElement.h>
|
||||
|
||||
#import <Contacts/NGVCard+SOGo.h>
|
||||
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
@@ -46,13 +42,49 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "NSDate+ActiveSync.h"
|
||||
#include "NSString+ActiveSync.h"
|
||||
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
|
||||
@implementation NGVCard (ActiveSync)
|
||||
|
||||
//
|
||||
// This function is called for each elements which can be ghosted according to specs.
|
||||
// https://msdn.microsoft.com/en-us/library/gg650908%28v=exchg.80%29.aspx
|
||||
//
|
||||
- (BOOL) _isGhosted: (NSString *) element
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
NSArray *supportedElements;
|
||||
|
||||
supportedElements = [context objectForKey: @"SupportedElements"];
|
||||
|
||||
// If the client does not include a Supported element in the initial Sync command request for
|
||||
// a folder, then all of the elements that can be ghosted are considered not ghosted.
|
||||
if (!supportedElements)
|
||||
return NO;
|
||||
|
||||
// If the client includes an empty Supported element in the initial Sync command request for
|
||||
// a folder, then all elements that can be ghosted are considered ghosted.
|
||||
if (![supportedElements count])
|
||||
return YES;
|
||||
|
||||
// If the client includes a Supported element that contains child elements in the initial
|
||||
// Sync command request for a folder, then each child element of that Supported element is
|
||||
// considered not ghosted. All elements that can be ghosted that are not included as child
|
||||
// elements of the Supported element are considered ghosted.
|
||||
if (!([supportedElements indexOfObject: element] == NSNotFound))
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSArray *emails, *addresses, *categories, *elements;
|
||||
CardElement *n, *homeAdr, *workAdr;
|
||||
NSMutableString *s;
|
||||
NSMutableString *s, *a;
|
||||
NSString *url;
|
||||
id o;
|
||||
|
||||
@@ -63,7 +95,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if ((o = [n flattenedValueAtIndex: 0 forKey: @""]))
|
||||
[s appendFormat: @"<LastName xmlns=\"Contacts:\">%@</LastName>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
|
||||
if ((o = [n flattenedValueAtIndex: 1 forKey: @""]))
|
||||
[s appendFormat: @"<FirstName xmlns=\"Contacts:\">%@</FirstName>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
@@ -146,16 +178,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
if ([addresses count])
|
||||
{
|
||||
homeAdr = [addresses objectAtIndex: 0];
|
||||
a = [NSMutableString string];
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 2 forKey: @""]))
|
||||
[s appendFormat: @"<HomeStreet xmlns=\"Contacts:\">%@</HomeStreet>", [o activeSyncRepresentationInContext: context]];
|
||||
[a appendString: o];
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 1 forKey: @""]) && [o length])
|
||||
[a appendFormat: @"\n%@", o];
|
||||
|
||||
[s appendFormat: @"<HomeStreet xmlns=\"Contacts:\">%@</HomeStreet>", [a activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 3 forKey: @""]))
|
||||
[s appendFormat: @"<HomeCity xmlns=\"Contacts:\">%@</HomeCity>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 4 forKey: @""]))
|
||||
[s appendFormat: @"<HomeState xmlns=\"Contacts:\">%@</HomeState>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 5 forKey: @""]))
|
||||
[s appendFormat: @"<HomePostalCode xmlns=\"Contacts:\">%@</HomePostalCode>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
@@ -171,9 +209,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
if ([addresses count])
|
||||
{
|
||||
workAdr = [addresses objectAtIndex: 0];
|
||||
a = [NSMutableString string];
|
||||
|
||||
if ((o = [workAdr flattenedValueAtIndex: 2 forKey: @""]))
|
||||
[s appendFormat: @"<BusinessStreet xmlns=\"Contacts:\">%@</BusinessStreet>", [o activeSyncRepresentationInContext: context]];
|
||||
[a appendString: o];
|
||||
|
||||
if ((o = [workAdr flattenedValueAtIndex: 1 forKey: @""]) && [o length])
|
||||
[a appendFormat: @"\n%@", o];
|
||||
|
||||
[s appendFormat: @"<BusinessStreet xmlns=\"Contacts:\">%@</BusinessStreet>", [a activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [workAdr flattenedValueAtIndex: 3 forKey: @""]))
|
||||
[s appendFormat: @"<BusinessCity xmlns=\"Contacts:\">%@</BusinessCity>", [o activeSyncRepresentationInContext: context]];
|
||||
@@ -190,7 +234,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Other, less important fields
|
||||
if ((o = [self birthday]))
|
||||
[s appendFormat: @"<Birthday xmlns=\"Contacts:\">%@</Birthday>", [o activeSyncRepresentationInContext: context]];
|
||||
{
|
||||
NSTimeZone *userTimeZone;
|
||||
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
||||
|
||||
[s appendFormat: @"<Birthday xmlns=\"Contacts:\">%@</Birthday>",
|
||||
[[o dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: ([userTimeZone secondsFromGMTForDate: o])*-1]
|
||||
activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
if ((o = [self note]))
|
||||
{
|
||||
@@ -217,6 +270,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
CardElement *element;
|
||||
NSMutableArray *addressLines;
|
||||
id o;
|
||||
|
||||
// Contact's note
|
||||
@@ -226,6 +280,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// Categories
|
||||
if ((o = [theValues objectForKey: @"Categories"]) && [o length])
|
||||
[self setCategories: o];
|
||||
else
|
||||
[[self children] removeObjectsInArray: [self childrenWithTag: @"Categories"]];
|
||||
|
||||
// Birthday
|
||||
if ((o = [theValues objectForKey: @"Birthday"]))
|
||||
@@ -233,6 +289,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
o = [o calendarDate];
|
||||
[self setBday: [o descriptionWithCalendarFormat: @"%Y-%m-%d" timeZone: nil locale: nil]];
|
||||
}
|
||||
else if (![self _isGhosted: @"Birthday" inContext: context])
|
||||
{
|
||||
[self setBday: @""];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Business address information
|
||||
@@ -244,18 +305,48 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// BusinessCountry
|
||||
//
|
||||
element = [self elementWithTag: @"adr" ofType: @"work"];
|
||||
[element setSingleValue: @""
|
||||
atIndex: 1 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessStreet"]
|
||||
atIndex: 2 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessCity"]
|
||||
atIndex: 3 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessState"]
|
||||
atIndex: 4 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessPostalCode"]
|
||||
atIndex: 5 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessCountry"]
|
||||
atIndex: 6 forKey: @""];
|
||||
|
||||
if ((o = [theValues objectForKey: @"BusinessStreet"]) || ![self _isGhosted: @"BusinessStreet" inContext: context])
|
||||
{
|
||||
addressLines = [NSMutableArray arrayWithArray: [o componentsSeparatedByString: @"\n"]];
|
||||
|
||||
[element setSingleValue: @""
|
||||
atIndex: 1 forKey: @""];
|
||||
[element setSingleValue: [addressLines count] ? [addressLines objectAtIndex: 0] : @""
|
||||
atIndex: 2 forKey: @""];
|
||||
|
||||
// Extended address line. If there are more than 2 address lines we add them to the extended address line.
|
||||
if ([addressLines count] > 1)
|
||||
{
|
||||
[addressLines removeObjectAtIndex: 0];
|
||||
[element setSingleValue: [addressLines componentsJoinedByString: @" "]
|
||||
atIndex: 1 forKey: @""];
|
||||
}
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"BusinessCity"]) || ![self _isGhosted: @"BusinessCity" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessCity"]
|
||||
atIndex: 3 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"BusinessState"]) || ![self _isGhosted: @"BusinessState" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessState"]
|
||||
atIndex: 4 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"BusinessPostalCode"]) || ![self _isGhosted: @"BusinessPostalCode" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessPostalCode"]
|
||||
atIndex: 5 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"BusinessCountry"]) || ![self _isGhosted: @"BusinessCountry" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessCountry"]
|
||||
atIndex: 6 forKey: @""];
|
||||
}
|
||||
|
||||
//
|
||||
// Home address information
|
||||
@@ -267,35 +358,69 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// HomeCountry
|
||||
//
|
||||
element = [self elementWithTag: @"adr" ofType: @"home"];
|
||||
[element setSingleValue: @""
|
||||
atIndex: 1 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeStreet"]
|
||||
atIndex: 2 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeCity"]
|
||||
atIndex: 3 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeState"]
|
||||
atIndex: 4 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomePostalCode"]
|
||||
atIndex: 5 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeCountry"]
|
||||
atIndex: 6 forKey: @""];
|
||||
|
||||
if ((o = [theValues objectForKey: @"HomeStreet"]) || ![self _isGhosted: @"HomeStreet" inContext: context])
|
||||
{
|
||||
addressLines = [NSMutableArray arrayWithArray: [o componentsSeparatedByString: @"\n"]];
|
||||
|
||||
[element setSingleValue: @""
|
||||
atIndex: 1 forKey: @""];
|
||||
[element setSingleValue: [addressLines count] ? [addressLines objectAtIndex: 0] : @""
|
||||
atIndex: 2 forKey: @""];
|
||||
|
||||
// Extended address line. If there are more then 2 address lines we add them to the extended address line.
|
||||
if ([addressLines count] > 1)
|
||||
{
|
||||
[addressLines removeObjectAtIndex: 0];
|
||||
[element setSingleValue: [addressLines componentsJoinedByString: @" "]
|
||||
atIndex: 1 forKey: @""];
|
||||
}
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"HomeCity"]) || ![self _isGhosted: @"HomeCity" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeCity"]
|
||||
atIndex: 3 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"HomeState"]) || ![self _isGhosted: @"HomeState" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeState"]
|
||||
atIndex: 4 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"HomePostalCode"]) || ![self _isGhosted: @"HomePostalCode" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"HomePostalCode"]
|
||||
atIndex: 5 forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"HomeCountry"]) || ![self _isGhosted: @"HomeCountry" inContext: context])
|
||||
{
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeCountry"]
|
||||
atIndex: 6 forKey: @""];
|
||||
}
|
||||
|
||||
// Company's name
|
||||
if ((o = [theValues objectForKey: @"CompanyName"]))
|
||||
[self setOrg: o units: nil];
|
||||
else if (![self _isGhosted: @"CompanyName" inContext: context])
|
||||
[self setOrg: @"" units: nil];
|
||||
|
||||
// Department
|
||||
if ((o = [theValues objectForKey: @"Department"]))
|
||||
[self setOrg: nil units: [NSArray arrayWithObjects:o,nil]];
|
||||
else if (![self _isGhosted: @"Department" inContext: context])
|
||||
[self setOrg: nil units: [NSArray arrayWithObjects:@"",nil]];
|
||||
|
||||
// Email addresses
|
||||
if ((o = [theValues objectForKey: @"Email1Address"]))
|
||||
if ((o = [theValues objectForKey: @"Email1Address"]) || ![self _isGhosted: @"Email1Address" inContext: context])
|
||||
{
|
||||
element = [self elementWithTag: @"email" ofType: @"work"];
|
||||
[element setSingleValue: [o pureEMailAddress] forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"Email2Address"]))
|
||||
if ((o = [theValues objectForKey: @"Email2Address"]) || ![self _isGhosted: @"Email2Address" inContext: context])
|
||||
{
|
||||
element = [self elementWithTag: @"email" ofType: @"home"];
|
||||
[element setSingleValue: [o pureEMailAddress] forKey: @""];
|
||||
@@ -303,7 +428,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// SOGo currently only supports 2 email addresses ... but AS clients might send 3
|
||||
// FIXME: revise this when the GUI revamp is done in SOGo
|
||||
if ((o = [theValues objectForKey: @"Email3Address"]))
|
||||
if ((o = [theValues objectForKey: @"Email3Address"]) || ![self _isGhosted: @"Email3Address" inContext: context])
|
||||
{
|
||||
element = [self elementWithTag: @"email" ofType: @"three"];
|
||||
[element setSingleValue: [o pureEMailAddress] forKey: @""];
|
||||
@@ -313,45 +438,62 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// MiddleName
|
||||
// Suffix (II)
|
||||
// Title (Mr.)
|
||||
[self setFn: [theValues objectForKey: @"FileAs"]];
|
||||
if ((o = [theValues objectForKey: @"FileAs"]) || ![self _isGhosted: @"FileAs" inContext: context])
|
||||
[self setFn: [theValues objectForKey: @"FileAs"]];
|
||||
|
||||
[self setNWithFamily: [theValues objectForKey: @"LastName"]
|
||||
given: [theValues objectForKey: @"FirstName"]
|
||||
additional: nil prefixes: nil suffixes: nil];
|
||||
|
||||
// IM information
|
||||
[[self uniqueChildWithTag: @"x-aim"]
|
||||
setSingleValue: [theValues objectForKey: @"IMAddress"]
|
||||
forKey: @""];
|
||||
if ((o = [theValues objectForKey: @"IMAddress"]) || ![self _isGhosted: @"IMAddress" inContext: context])
|
||||
[[self uniqueChildWithTag: @"x-aim"]
|
||||
setSingleValue: [theValues objectForKey: @"IMAddress"]
|
||||
forKey: @""];
|
||||
|
||||
//
|
||||
// Phone numbrrs
|
||||
//
|
||||
element = [self elementWithTag: @"tel" ofType: @"work"];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessPhoneNumber"] forKey: @""];
|
||||
if ((o = [theValues objectForKey: @"BusinessPhoneNumber"]) || ![self _isGhosted: @"BusinessPhoneNumber" inContext: context])
|
||||
{
|
||||
element = [self elementWithTag: @"tel" ofType: @"work"];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessPhoneNumber"] forKey: @""];
|
||||
}
|
||||
|
||||
element = [self elementWithTag: @"tel" ofType: @"home"];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomePhoneNumber"] forKey: @""];
|
||||
if ((o = [theValues objectForKey: @"HomePhoneNumber"]) || ![self _isGhosted: @"HomePhoneNumber" inContext: context])
|
||||
{
|
||||
element = [self elementWithTag: @"tel" ofType: @"home"];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomePhoneNumber"] forKey: @""];
|
||||
}
|
||||
|
||||
element = [self elementWithTag: @"tel" ofType: @"cell"];
|
||||
[element setSingleValue: [theValues objectForKey: @"MobilePhoneNumber"] forKey: @""];
|
||||
if ((o = [theValues objectForKey: @"MobilePhoneNumber"]) || ![self _isGhosted: @"MobilePhoneNumber" inContext: context])
|
||||
{
|
||||
element = [self elementWithTag: @"tel" ofType: @"cell"];
|
||||
[element setSingleValue: [theValues objectForKey: @"MobilePhoneNumber"] forKey: @""];
|
||||
}
|
||||
|
||||
element = [self elementWithTag: @"tel" ofType: @"fax"];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessFaxNumber"] forKey: @""];
|
||||
if ((o = [theValues objectForKey: @"BusinessFaxNumber"]) || ![self _isGhosted: @"BusinessFaxNumber" inContext: context])
|
||||
{
|
||||
element = [self elementWithTag: @"tel" ofType: @"fax"];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessFaxNumber"] forKey: @""];
|
||||
}
|
||||
|
||||
element = [self elementWithTag: @"tel" ofType: @"pager"];
|
||||
[element setSingleValue: [theValues objectForKey: @"PagerNumber"] forKey: @""];
|
||||
if ((o = [theValues objectForKey: @"PagerNumber"]) || ![self _isGhosted: @"PagerNumber" inContext: context])
|
||||
{
|
||||
element = [self elementWithTag: @"tel" ofType: @"pager"];
|
||||
[element setSingleValue: [theValues objectForKey: @"PagerNumber"] forKey: @""];
|
||||
}
|
||||
|
||||
// Job's title
|
||||
if ((o = [theValues objectForKey: @"JobTitle"]))
|
||||
if ((o = [theValues objectForKey: @"JobTitle"]) || ![self _isGhosted: @"JobTitle" inContext: context])
|
||||
[self setTitle: o];
|
||||
|
||||
// WebPage (work)
|
||||
if ((o = [theValues objectForKey: @"WebPage"]))
|
||||
if ((o = [theValues objectForKey: @"WebPage"]) || ![self _isGhosted: @"WebPage" inContext: context])
|
||||
[[self elementWithTag: @"url" ofType: @"work"]
|
||||
setSingleValue: o forKey: @""];
|
||||
|
||||
if ((o = [theValues objectForKey: @"NickName"]))
|
||||
if ((o = [theValues objectForKey: @"NickName"]) || ![self _isGhosted: @"NickName" inContext: context])
|
||||
[self setNickname: o];
|
||||
|
||||
if ((o = [theValues objectForKey: @"Picture"]))
|
||||
|
||||
@@ -30,7 +30,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import "NSCalendarDate+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#define ONE_DAY 86400
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import "NSData+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSProcessInfo.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
|
||||
@@ -38,8 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#include <wbxml/wbxml.h>
|
||||
#include <wbxml/wbxml_conv.h>
|
||||
#include <wbxml/wbxml_errors.h>
|
||||
|
||||
#define WBXMLDEBUG 0
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define __NSSTRINGACTIVESYNC_H__
|
||||
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#include "SOGoActiveSyncConstants.h"
|
||||
|
||||
@class NSCalendarDate;
|
||||
|
||||
@@ -31,9 +31,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSCalendarDate.h>
|
||||
#include <Foundation/NSData.h>
|
||||
#include <Foundation/NSDate.h>
|
||||
#include <Foundation/NSTimeZone.h>
|
||||
|
||||
#include <SOGo/NSString+Utilities.h>
|
||||
#include <SOGo/NSData+Crypto.h>
|
||||
@@ -75,7 +72,7 @@ static NSArray *easCommandParameters = nil;
|
||||
escapeCount++;
|
||||
break;
|
||||
default:
|
||||
if (chars[i] > 127)
|
||||
if (chars[i] < 0x20 || chars[i] > 127)
|
||||
escapeCount++;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import "SOGoActiveSyncDispatcher.h"
|
||||
|
||||
#import <DOM/DOMElement.h>
|
||||
#import <DOM/DOMProtocols.h>
|
||||
|
||||
@class WOResponse;
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
Copyright (c) 2014-2015, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -27,19 +27,30 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
#include "SOGoActiveSyncConstants.h"
|
||||
|
||||
@class NSCalendarDate;
|
||||
@class NSException;
|
||||
@class NSMutableDictionary;
|
||||
@class NSURL;
|
||||
@class NSNumber;
|
||||
|
||||
@interface SOGoActiveSyncDispatcher : NSObject
|
||||
{
|
||||
NSURL *folderTableURL;
|
||||
NSDictionary *imapFolderGUIDS;
|
||||
id context;
|
||||
|
||||
NSNumber *syncRequest;
|
||||
|
||||
BOOL debugOn;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) globalMetadataForDevice;
|
||||
|
||||
- (id) collectionFromId: (NSString *) theCollectionId
|
||||
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType;
|
||||
|
||||
|
||||
@@ -27,11 +27,10 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "SOGoActiveSyncDispatcher.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSProcessInfo.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
@@ -40,22 +39,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGObjWeb/SoPermissions.h>
|
||||
#import <NGObjWeb/SoSecurityManager.h>
|
||||
#import <NGObjWeb/SoApplication.h>
|
||||
#import <NGObjWeb/SoObject.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WOCookie.h>
|
||||
#import <NGObjWeb/WODirectAction.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalEntityObject.h>
|
||||
#import <NGCards/iCalEvent.h>
|
||||
#import <NGCards/iCalToDo.h>
|
||||
#import <NGCards/NGVCard.h>
|
||||
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
#import <NGExtensions/NGCalendarDateRange.h>
|
||||
#import <NGExtensions/NGHashMap.h>
|
||||
@@ -72,27 +61,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <NGMime/NGMimeMultipartBody.h>
|
||||
#import <NGMime/NGMimeType.h>
|
||||
#import <NGMail/NGMimeMessageParser.h>
|
||||
#import <NGMail/NGMimeMessage.h>
|
||||
#import <NGMail/NGMimeMessageGenerator.h>
|
||||
|
||||
#import <DOM/DOMElement.h>
|
||||
#import <DOM/DOMProtocols.h>
|
||||
#import <DOM/DOMSaxBuilder.h>
|
||||
|
||||
#import <EOControl/EOQualifier.h>
|
||||
|
||||
#import <SOGo/NSArray+DAV.h>
|
||||
#import <SOGo/NSDictionary+DAV.h>
|
||||
#import <SOGo/SOGoCache.h>
|
||||
#import <SOGo/SOGoCacheGCSObject.h>
|
||||
#import <SOGo/SOGoDAVAuthenticator.h>
|
||||
#import <SOGo/SOGoDomainDefaults.h>
|
||||
#import <SOGo/SOGoMailer.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
#import <SOGo/SOGoUserSettings.h>
|
||||
#import <SOGo/GCSSpecialQueries+SOGoCacheObject.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/WORequest+SOGo.h>
|
||||
@@ -111,12 +94,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <Mailer/SOGoMailAccounts.h>
|
||||
#import <Mailer/SOGoMailBodyPart.h>
|
||||
#import <Mailer/SOGoMailFolder.h>
|
||||
#import <Mailer/SOGoMailObject.h>
|
||||
#import <Mailer/SOGoMailObject+Draft.h>
|
||||
#import <Mailer/SOGoSentFolder.h>
|
||||
#import <Mailer/NSString+Mail.h>
|
||||
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#include "iCalEvent+ActiveSync.h"
|
||||
@@ -127,13 +108,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "NSData+ActiveSync.h"
|
||||
#include "NSDate+ActiveSync.h"
|
||||
#include "NSString+ActiveSync.h"
|
||||
#include "SOGoActiveSyncConstants.h"
|
||||
#include "SOGoMailObject+ActiveSync.h"
|
||||
|
||||
#import <GDLContentStore/GCSChannelManager.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/x509.h>
|
||||
#endif
|
||||
|
||||
@interface SOGoActiveSyncDispatcher (Sync)
|
||||
|
||||
- (NSMutableDictionary *) _folderMetadataForKey: (NSString *) theFolderKey;
|
||||
@@ -143,20 +129,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@implementation SOGoActiveSyncDispatcher
|
||||
|
||||
static BOOL debugOn = NO;
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] easDebugEnabled];
|
||||
folderTableURL = nil;
|
||||
imapFolderGUIDS = nil;
|
||||
syncRequest = nil;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(folderTableURL);
|
||||
RELEASE(imapFolderGUIDS);
|
||||
RELEASE(syncRequest);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -169,16 +157,16 @@ static BOOL debugOn = NO;
|
||||
[o setTableUrl: [self folderTableURL]];
|
||||
[o reloadIfNeeded];
|
||||
|
||||
[[o properties] removeAllObjects];
|
||||
[[o properties] addEntriesFromDictionary: [NSDictionary dictionaryWithObject: theSyncKey forKey: @"FolderSyncKey"]];
|
||||
[[o properties] setObject: theSyncKey
|
||||
forKey: @"FolderSyncKey"];
|
||||
[o save];
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) _globalMetadataForDevice
|
||||
- (NSMutableDictionary *) globalMetadataForDevice
|
||||
{
|
||||
SOGoCacheGCSObject *o;
|
||||
|
||||
o = [SOGoCacheGCSObject objectWithName: [context objectForKey: @"DeviceId"] inContainer: nil];
|
||||
o = [SOGoCacheGCSObject objectWithName: [context objectForKey: @"DeviceId"] inContainer: nil useCache: NO];
|
||||
[o setObjectType: ActiveSyncGlobalCacheObject];
|
||||
[o setTableUrl: [self folderTableURL]];
|
||||
[o reloadIfNeeded];
|
||||
@@ -202,7 +190,7 @@ static BOOL debugOn = NO;
|
||||
if (theFilter)
|
||||
{
|
||||
o = [SOGoCacheGCSObject objectWithName: [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], theCollectionId] inContainer: nil];
|
||||
[o setObjectType: ActiveSyncGlobalCacheObject];
|
||||
[o setObjectType: ActiveSyncFolderCacheObject];
|
||||
[o setTableUrl: [self folderTableURL]];
|
||||
[o reloadIfNeeded];
|
||||
|
||||
@@ -229,23 +217,27 @@ static BOOL debugOn = NO;
|
||||
SOGoMailAccounts *accountsFolder;
|
||||
SOGoMailAccount *accountFolder;
|
||||
SOGoUserFolder *userFolder;
|
||||
NSDictionary *imapGUIDs;
|
||||
|
||||
userFolder = [[context activeUser] homeFolderInContext: context];
|
||||
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
|
||||
accountFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
|
||||
|
||||
// Get the GUID of the IMAP folder
|
||||
imapGUIDs = [accountFolder imapFolderGUIDs];
|
||||
|
||||
//return [[imapGUIDs allKeysForObject: theIdToTranslate] objectAtIndex: 0];
|
||||
return [[[imapGUIDs allKeysForObject: [NSString stringWithFormat: @"folder%@", theIdToTranslate]] objectAtIndex: 0] substringFromIndex: 6] ;
|
||||
if (!imapFolderGUIDS)
|
||||
{
|
||||
userFolder = [[context activeUser] homeFolderInContext: context];
|
||||
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
|
||||
accountFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
|
||||
|
||||
// Get the GUID of the IMAP folder
|
||||
imapFolderGUIDS = [accountFolder imapFolderGUIDs];
|
||||
[imapFolderGUIDS retain];
|
||||
|
||||
}
|
||||
|
||||
return [[[imapFolderGUIDS allKeysForObject: [NSString stringWithFormat: @"folder%@", theIdToTranslate]] objectAtIndex: 0] substringFromIndex: 6] ;
|
||||
}
|
||||
|
||||
return theIdToTranslate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -371,7 +363,7 @@ static BOOL debugOn = NO;
|
||||
[[o properties ] setObject: [[newFolder nameInContainer] substringFromIndex: 6] forKey: @"displayName"];
|
||||
[o save];
|
||||
|
||||
nameInContainer = [[NSString stringWithFormat: @"mail/%@", [nameInContainer substringFromIndex: 6]] stringByEscapingURL];
|
||||
nameInContainer = [NSString stringWithFormat: @"mail/%@", [nameInContainer substringFromIndex: 6]];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -387,17 +379,24 @@ static BOOL debugOn = NO;
|
||||
SOGoAppointmentFolders *appointmentFolders;
|
||||
SOGoCacheGCSObject *o;
|
||||
NSString *key;
|
||||
id newFolder;
|
||||
|
||||
nameInContainer = nil;
|
||||
|
||||
appointmentFolders = [userFolder privateCalendars: @"Calendar" inContext: context];
|
||||
[appointmentFolders newFolderWithName: displayName
|
||||
nameInContainer: &nameInContainer];
|
||||
|
||||
newFolder = [appointmentFolders lookupName: nameInContainer
|
||||
inContext: context
|
||||
acquire: NO];
|
||||
[newFolder setSynchronize: YES];
|
||||
|
||||
if (type == 13)
|
||||
nameInContainer = [NSString stringWithFormat: @"vevent/%@", nameInContainer];
|
||||
else
|
||||
nameInContainer = [NSString stringWithFormat: @"vtodo/%@", nameInContainer];
|
||||
|
||||
|
||||
key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], nameInContainer ];
|
||||
o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
|
||||
[o setObjectType: ActiveSyncFolderCacheObject];
|
||||
@@ -412,12 +411,19 @@ static BOOL debugOn = NO;
|
||||
SOGoContactFolders *contactFolders;
|
||||
SOGoCacheGCSObject *o;
|
||||
NSString *key;
|
||||
id newFolder;
|
||||
|
||||
nameInContainer = nil;
|
||||
|
||||
contactFolders = [userFolder privateContacts: @"Contacts" inContext: context];
|
||||
[contactFolders newFolderWithName: displayName
|
||||
nameInContainer: &nameInContainer];
|
||||
|
||||
newFolder = [contactFolders lookupName: nameInContainer
|
||||
inContext: context
|
||||
acquire: NO];
|
||||
[newFolder setSynchronize: YES];
|
||||
|
||||
nameInContainer = [NSString stringWithFormat: @"vcard/%@", nameInContainer];
|
||||
|
||||
key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], nameInContainer ];
|
||||
@@ -681,6 +687,27 @@ static BOOL debugOn = NO;
|
||||
}
|
||||
|
||||
|
||||
- (void) _flattenFolders: (NSArray *) theFolders
|
||||
into: (NSMutableArray *) theTarget
|
||||
parent: (NSString *) theParent
|
||||
{
|
||||
NSArray *o;
|
||||
int i;
|
||||
|
||||
[theTarget addObjectsFromArray: theFolders];
|
||||
|
||||
for (i = 0; i < [theFolders count]; i++)
|
||||
{
|
||||
if (theParent)
|
||||
[[theFolders objectAtIndex: i] setObject: theParent forKey: @"parent"];
|
||||
|
||||
o = [[theFolders objectAtIndex: i] objectForKey: @"children"];
|
||||
|
||||
if (o)
|
||||
[self _flattenFolders: o into: theTarget parent: [[theFolders objectAtIndex: i] objectForKey: @"path"]];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// <?xml version="1.0"?>
|
||||
// <!DOCTYPE ActiveSync PUBLIC "-//MICROSOFT//DTD ActiveSync//EN" "http://www.microsoft.com/">
|
||||
@@ -691,26 +718,25 @@ static BOOL debugOn = NO;
|
||||
- (void) processFolderSync: (id <DOMElement>) theDocumentElement
|
||||
inResponse: (WOResponse *) theResponse
|
||||
{
|
||||
NSString *key, *cKey, *nkey, *name, *serverId, *parentId, *nameInCache, *personalFolderName, *syncKey, *folderType;
|
||||
NSDictionary *folderMetadata, *imapGUIDs;
|
||||
NSArray *allFoldersMetadata, *allKeys;
|
||||
NSString *key, *cKey, *nkey, *name, *serverId, *parentId, *nameInCache, *personalFolderName, *syncKey, *folderType, *operation;
|
||||
NSMutableArray *folders, *processedFolders, *allFoldersMetadata;
|
||||
NSMutableDictionary *cachedGUIDs, *metadata;
|
||||
NSDictionary *folderMetadata, *imapGUIDs;
|
||||
SOGoMailAccounts *accountsFolder;
|
||||
SOGoMailAccount *accountFolder;
|
||||
NSMutableString *s, *commands;
|
||||
SOGoUserFolder *userFolder;
|
||||
NSMutableArray *folders, *processedFolders;
|
||||
SoSecurityManager *sm;
|
||||
SOGoCacheGCSObject *o;
|
||||
NSArray *allKeys;
|
||||
id currentFolder;
|
||||
NSData *d;
|
||||
|
||||
int status, command_count, i, type, fi, count;
|
||||
|
||||
BOOL first_sync;
|
||||
|
||||
sm = [SoSecurityManager sharedSecurityManager];
|
||||
metadata = [self _globalMetadataForDevice];
|
||||
metadata = [self globalMetadataForDevice];
|
||||
syncKey = [[(id)[theDocumentElement getElementsByTagName: @"SyncKey"] lastObject] textValue];
|
||||
s = [NSMutableString string];
|
||||
|
||||
@@ -744,7 +770,8 @@ static BOOL debugOn = NO;
|
||||
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
|
||||
accountFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
|
||||
|
||||
allFoldersMetadata = [accountFolder allFoldersMetadata];
|
||||
allFoldersMetadata = [NSMutableArray array];
|
||||
[self _flattenFolders: [accountFolder allFoldersMetadata] into: allFoldersMetadata parent: nil];
|
||||
|
||||
// Get GUIDs of folder (IMAP)
|
||||
// e.g. {folderINBOX = folder6b93c528176f1151c7260000aef6df92}
|
||||
@@ -824,46 +851,55 @@ static BOOL debugOn = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([cKey rangeOfString: @"vevent" options: NSCaseInsensitiveSearch].location != NSNotFound ||
|
||||
[cKey rangeOfString: @"vtodo" options: NSCaseInsensitiveSearch].location != NSNotFound)
|
||||
folderType = @"Calendar";
|
||||
else
|
||||
folderType = @"Contacts";
|
||||
if ([cKey rangeOfString: @"vevent" options: NSCaseInsensitiveSearch].location != NSNotFound ||
|
||||
[cKey rangeOfString: @"vtodo" options: NSCaseInsensitiveSearch].location != NSNotFound)
|
||||
folderType = @"Calendar";
|
||||
else
|
||||
folderType = @"Contacts";
|
||||
|
||||
if ([ cKey rangeOfString: @"/"].location != NSNotFound)
|
||||
currentFolder = [[[[context activeUser] homeFolderInContext: context] lookupName: folderType inContext: context acquire: NO]
|
||||
if ([ cKey rangeOfString: @"/"].location != NSNotFound)
|
||||
currentFolder = [[[[context activeUser] homeFolderInContext: context] lookupName: folderType inContext: context acquire: NO]
|
||||
lookupName: [cKey substringFromIndex: [cKey rangeOfString: @"/"].location+1] inContext: context acquire: NO];
|
||||
|
||||
// remove the folder from device if it doesn't exists or it has not the proper permissions
|
||||
if (!currentFolder ||
|
||||
[sm validatePermission: SoPerm_DeleteObjects
|
||||
onObject: currentFolder
|
||||
inContext: context] ||
|
||||
[sm validatePermission: SoPerm_AddDocumentsImagesAndFiles
|
||||
onObject: currentFolder
|
||||
inContext: context])
|
||||
{
|
||||
[commands appendFormat: @"<Delete><ServerId>%@</ServerId></Delete>", [cKey stringByEscapingURL] ];
|
||||
command_count++;
|
||||
[o destroy];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// We skip personal GCS folders - we always want to synchronize these
|
||||
if ([currentFolder isKindOfClass: [SOGoGCSFolder class]] &&
|
||||
[[currentFolder nameInContainer] isEqualToString: @"personal"])
|
||||
continue;
|
||||
|
||||
// Remove the folder from device if it doesn't exist, we don't want to sync it, or it doesn't have the proper permissions
|
||||
if (!currentFolder ||
|
||||
![currentFolder synchronize] ||
|
||||
[sm validatePermission: SoPerm_DeleteObjects
|
||||
onObject: currentFolder
|
||||
inContext: context] ||
|
||||
[sm validatePermission: SoPerm_AddDocumentsImagesAndFiles
|
||||
onObject: currentFolder
|
||||
inContext: context])
|
||||
{
|
||||
[commands appendFormat: @"<Delete><ServerId>%@</ServerId></Delete>", [cKey stringByEscapingURL] ];
|
||||
command_count++;
|
||||
[o destroy];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle addition and changes
|
||||
for (i = 0; i < [allFoldersMetadata count]; i++)
|
||||
{
|
||||
folderMetadata = [allFoldersMetadata objectAtIndex: i];
|
||||
|
||||
nameInCache = [NSString stringWithFormat: @"folder%@", [[folderMetadata objectForKey: @"path"] substringFromIndex: 1]];
|
||||
|
||||
// In v3, the "path" value does not have a '/' at the beginning
|
||||
nameInCache = [NSString stringWithFormat: @"folder%@", [folderMetadata objectForKey: @"path"]];
|
||||
|
||||
// we have no guid - ignore the folder
|
||||
if (![imapGUIDs objectForKey: nameInCache])
|
||||
continue;
|
||||
|
||||
serverId = [NSString stringWithFormat: @"mail/%@", [[imapGUIDs objectForKey: nameInCache] substringFromIndex: 6]];
|
||||
name = [folderMetadata objectForKey: @"displayName"];
|
||||
|
||||
// In v3, we use "name" while in v2, it was "displayName"
|
||||
name = [folderMetadata objectForKey: @"name"];
|
||||
|
||||
// avoid duplicate folders if folder is returned by different imap namespaces
|
||||
if ([processedFolders indexOfObject: serverId] == NSNotFound)
|
||||
@@ -884,7 +920,7 @@ static BOOL debugOn = NO;
|
||||
{
|
||||
// make sure that parent of main-folders is always 0
|
||||
if (type == 12)
|
||||
parentId = [NSString stringWithFormat: @"mail/%@", [[imapGUIDs objectForKey: [NSString stringWithFormat: @"folder%@", [[folderMetadata objectForKey: @"parent"] substringFromIndex: 1]]] substringFromIndex: 6]];
|
||||
parentId = [NSString stringWithFormat: @"mail/%@", [[imapGUIDs objectForKey: [NSString stringWithFormat: @"folder%@", [folderMetadata objectForKey: @"parent"]]] substringFromIndex: 6]];
|
||||
|
||||
name = [[name pathComponents] lastObject];
|
||||
}
|
||||
@@ -937,7 +973,9 @@ static BOOL debugOn = NO;
|
||||
[[o properties] removeObjectForKey: @"DateCache"];
|
||||
[[o properties] removeObjectForKey: @"MoreAvailable"];
|
||||
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
|
||||
[[o properties] removeObjectForKey: @"SupportedElements"];
|
||||
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
|
||||
[[o properties] removeObjectForKey: @"InitialLoadSequence"];
|
||||
[o save];
|
||||
|
||||
command_count++;
|
||||
@@ -946,17 +984,29 @@ static BOOL debugOn = NO;
|
||||
|
||||
personalFolderName = [[[context activeUser] personalCalendarFolderInContext: context] nameInContainer];
|
||||
folders = [[[[[context activeUser] homeFolderInContext: context] lookupName: @"Calendar" inContext: context acquire: NO] subFolders] mutableCopy];
|
||||
[folders autorelease];
|
||||
|
||||
[folders addObjectsFromArray: [[[[context activeUser] homeFolderInContext: context] lookupName: @"Contacts" inContext: context acquire: NO] subFolders]];
|
||||
|
||||
// Inside this loop we remove all the folder without write/delete permissions
|
||||
// We remove all the folders that aren't GCS-ones, that we don't want to synchronize and
|
||||
// the ones without write/delete permissions.
|
||||
count = [folders count]-1;
|
||||
for (; count >= 0; count--)
|
||||
{
|
||||
if ([sm validatePermission: SoPerm_DeleteObjects
|
||||
onObject: [folders objectAtIndex: count]
|
||||
currentFolder = [folders objectAtIndex: count];
|
||||
|
||||
// We skip personal GCS folders - we always want to synchronize these
|
||||
if ([currentFolder isKindOfClass: [SOGoGCSFolder class]] &&
|
||||
[[currentFolder nameInContainer] isEqualToString: @"personal"])
|
||||
continue;
|
||||
|
||||
if (![currentFolder isKindOfClass: [SOGoGCSFolder class]] ||
|
||||
![currentFolder synchronize] ||
|
||||
[sm validatePermission: SoPerm_DeleteObjects
|
||||
onObject: currentFolder
|
||||
inContext: context] ||
|
||||
[sm validatePermission: SoPerm_AddDocumentsImagesAndFiles
|
||||
onObject: [folders objectAtIndex: count]
|
||||
onObject: currentFolder
|
||||
inContext: context])
|
||||
{
|
||||
[folders removeObjectAtIndex: count];
|
||||
@@ -964,7 +1014,6 @@ static BOOL debugOn = NO;
|
||||
}
|
||||
|
||||
count = [folders count]-1;
|
||||
NSString *operation;
|
||||
|
||||
for (fi = 0; fi <= count ; fi++)
|
||||
{
|
||||
@@ -1022,7 +1071,9 @@ static BOOL debugOn = NO;
|
||||
[[o properties] removeObjectForKey: @"DateCache"];
|
||||
[[o properties] removeObjectForKey: @"MoreAvailable"];
|
||||
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
|
||||
[[o properties] removeObjectForKey: @"SupportedElements"];
|
||||
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
|
||||
[[o properties] removeObjectForKey: @"InitialLoadSequence"];
|
||||
}
|
||||
|
||||
[o save];
|
||||
@@ -1045,7 +1096,9 @@ static BOOL debugOn = NO;
|
||||
[[o properties] removeObjectForKey: @"DateCache"];
|
||||
[[o properties] removeObjectForKey: @"MoreAvailable"];
|
||||
[[o properties] removeObjectForKey: @"BodyPreferenceType"];
|
||||
[[o properties] removeObjectForKey: @"SupportedElements"];
|
||||
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
|
||||
[[o properties] removeObjectForKey: @"InitialLoadSequence"];
|
||||
}
|
||||
|
||||
[o save];
|
||||
@@ -1095,17 +1148,18 @@ static BOOL debugOn = NO;
|
||||
SOGoMailAccounts *accountsFolder;
|
||||
SOGoUserFolder *userFolder;
|
||||
SOGoMailObject *mailObject;
|
||||
NSMutableArray *a;
|
||||
NSArray *partKeys;
|
||||
int p;
|
||||
|
||||
NSRange r1, r2;
|
||||
|
||||
r1 = [realCollectionId rangeOfString: @"/"];
|
||||
r2 = [realCollectionId rangeOfString: @"/" options: 0 range: NSMakeRange(NSMaxRange(r1)+1, [realCollectionId length]-NSMaxRange(r1)-1)];
|
||||
|
||||
folderName = [realCollectionId substringToIndex: r1.location];
|
||||
messageName = [realCollectionId substringWithRange: NSMakeRange(NSMaxRange(r1), r2.location-r1.location-1)];
|
||||
pathToPart = [realCollectionId substringFromIndex: r2.location+1];
|
||||
a = [[realCollectionId componentsSeparatedByString: @"/"] mutableCopy];
|
||||
[a autorelease];
|
||||
pathToPart = [a lastObject];
|
||||
[a removeLastObject];
|
||||
messageName = [a lastObject];
|
||||
[a removeLastObject];
|
||||
folderName = [a componentsJoinedByString: @"/"];
|
||||
|
||||
userFolder = [[context activeUser] homeFolderInContext: context];
|
||||
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
|
||||
@@ -1204,7 +1258,7 @@ static BOOL debugOn = NO;
|
||||
filter = [NSCalendarDate dateFromFilterType: [[(id)[[allCollections objectAtIndex: j] getElementsByTagName: @"FilterType"] lastObject] textValue]];
|
||||
syncKey = [[(id)[[allCollections objectAtIndex: j] getElementsByTagName: @"SyncKey"] lastObject] textValue];
|
||||
|
||||
allMessages = [currentCollection syncTokenFieldsWithProperties: nil matchingSyncToken: syncKey fromDate: filter];
|
||||
allMessages = [currentCollection syncTokenFieldsWithProperties: nil matchingSyncToken: syncKey fromDate: filter initialLoad: NO];
|
||||
|
||||
count = [allMessages count];
|
||||
|
||||
@@ -1254,7 +1308,7 @@ static BOOL debugOn = NO;
|
||||
- (void) processItemOperations: (id <DOMElement>) theDocumentElement
|
||||
inResponse: (WOResponse *) theResponse
|
||||
{
|
||||
NSString *fileReference, *realCollectionId, *serverId, *bodyPreferenceType, *collectionId;
|
||||
NSString *fileReference, *realCollectionId, *serverId, *bodyPreferenceType, *mimeSupport, *collectionId;
|
||||
NSMutableString *s;
|
||||
NSArray *fetchRequests;
|
||||
id aFetch;
|
||||
@@ -1302,20 +1356,21 @@ static BOOL debugOn = NO;
|
||||
SOGoMailAccounts *accountsFolder;
|
||||
SOGoUserFolder *userFolder;
|
||||
SOGoMailObject *mailObject;
|
||||
NSMutableArray *a;
|
||||
|
||||
if ([fileReference length])
|
||||
{
|
||||
// fetch attachment
|
||||
NSRange r1, r2;
|
||||
NSArray *partKeys;
|
||||
int p;
|
||||
|
||||
r1 = [realCollectionId rangeOfString: @"/"];
|
||||
r2 = [realCollectionId rangeOfString: @"/" options: 0 range: NSMakeRange(NSMaxRange(r1)+1, [realCollectionId length]-NSMaxRange(r1)-1)];
|
||||
|
||||
folderName = [realCollectionId substringToIndex: r1.location];
|
||||
messageName = [realCollectionId substringWithRange: NSMakeRange(NSMaxRange(r1), r2.location-r1.location-1)];
|
||||
pathToPart = [realCollectionId substringFromIndex: r2.location+1];
|
||||
a = [[realCollectionId componentsSeparatedByString: @"/"] mutableCopy];
|
||||
[a autorelease];
|
||||
pathToPart = [a lastObject];
|
||||
[a removeLastObject];
|
||||
messageName = [a lastObject];
|
||||
[a removeLastObject];
|
||||
folderName = [a componentsJoinedByString: @"/"];
|
||||
|
||||
userFolder = [[context activeUser] homeFolderInContext: context];
|
||||
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
|
||||
@@ -1331,13 +1386,13 @@ static BOOL debugOn = NO;
|
||||
|
||||
currentBodyPart = [mailObject lookupImap4BodyPartKey: [partKeys objectAtIndex:0] inContext: context];
|
||||
for (p = 1; p < [partKeys count]; p++)
|
||||
{
|
||||
currentBodyPart = [currentBodyPart lookupImap4BodyPartKey: [partKeys objectAtIndex:p] inContext: context];
|
||||
}
|
||||
{
|
||||
currentBodyPart = [currentBodyPart lookupImap4BodyPartKey: [partKeys objectAtIndex:p] inContext: context];
|
||||
}
|
||||
|
||||
[s appendString: @"<Fetch>"];
|
||||
[s appendString: @"<Status>1</Status>"];
|
||||
[s appendFormat: @"<FileReference xmlns=\"AirSyncBase:\">%@</FileReference>", [fileReference stringByEscapingURL]];
|
||||
[s appendFormat: @"<FileReference xmlns=\"AirSyncBase:\">mail/%@/%@/%@</FileReference>", [folderName stringByEscapingURL], messageName, pathToPart];
|
||||
[s appendString: @"<Properties>"];
|
||||
|
||||
[s appendFormat: @"<ContentType xmlns=\"AirSyncBase:\">%@/%@</ContentType>", [[currentBodyPart partInfo] objectForKey: @"type"], [[currentBodyPart partInfo] objectForKey: @"subtype"]];
|
||||
@@ -1367,6 +1422,8 @@ static BOOL debugOn = NO;
|
||||
serverId = [[(id)[theDocumentElement getElementsByTagName: @"ServerId"] lastObject] textValue];
|
||||
bodyPreferenceType = [[(id)[[(id)[theDocumentElement getElementsByTagName: @"BodyPreference"] lastObject] getElementsByTagName: @"Type"] lastObject] textValue];
|
||||
[context setObject: bodyPreferenceType forKey: @"BodyPreferenceType"];
|
||||
mimeSupport = [[(id)[theDocumentElement getElementsByTagName: @"MIMESupport"] lastObject] textValue];
|
||||
[context setObject: mimeSupport forKey: @"MIMESupport"];
|
||||
|
||||
currentCollection = [self collectionFromId: realCollectionId type: folderType];
|
||||
|
||||
@@ -1958,6 +2015,9 @@ static BOOL debugOn = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (heartbeatInterval < internalInterval)
|
||||
heartbeatInterval = internalInterval;
|
||||
|
||||
status = 1;
|
||||
}
|
||||
|
||||
@@ -2024,13 +2084,13 @@ static BOOL debugOn = NO;
|
||||
|
||||
if ([foldersWithChanges count])
|
||||
{
|
||||
[self logWithFormat: @"Change detected, we push the content."];
|
||||
[self logWithFormat: @"Change detected using Ping, we let the EAS client know to send a Sync."];
|
||||
status = 2;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self logWithFormat: @"Sleeping %d seconds while detecting changes...", internalInterval];
|
||||
[self logWithFormat: @"Sleeping %d seconds while detecting changes in Ping...", internalInterval];
|
||||
sleep(internalInterval);
|
||||
}
|
||||
}
|
||||
@@ -2094,6 +2154,123 @@ static BOOL debugOn = NO;
|
||||
[theResponse setContent: d];
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
#ifdef HAVE_OPENSSL
|
||||
- (unsigned int) validateCert: (NSString *) theCert
|
||||
{
|
||||
NSData *d;
|
||||
|
||||
const unsigned char *data;
|
||||
X509_STORE_CTX *ctx;
|
||||
X509_LOOKUP *lookup;
|
||||
X509_STORE *store;
|
||||
X509 *cert;
|
||||
|
||||
BOOL success;
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
success = NO;
|
||||
|
||||
d = [theCert dataByDecodingBase64];
|
||||
data = (unsigned char *)[d bytes];
|
||||
len = [d length];
|
||||
|
||||
cert = d2i_X509(NULL, &data, len);
|
||||
if (!cert)
|
||||
{
|
||||
[self logWithFormat: @"EAS - validateCert failed for device %@: d2i_X509 failed", [context objectForKey: @"DeviceId"]];
|
||||
return 17;
|
||||
}
|
||||
|
||||
store = X509_STORE_new();
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
if (store)
|
||||
{
|
||||
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
|
||||
if (lookup)
|
||||
{
|
||||
X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
|
||||
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
|
||||
if (lookup)
|
||||
{
|
||||
X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
|
||||
ERR_clear_error();
|
||||
success = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
if (store)
|
||||
{
|
||||
X509_STORE_free(store);
|
||||
store = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ctx = X509_STORE_CTX_new();
|
||||
if (!ctx)
|
||||
{
|
||||
[self logWithFormat: @"EAS - validateCert failed for device %@: X509_STORE_CTX_new failed", [context objectForKey: @"DeviceId"]];
|
||||
return 17;
|
||||
}
|
||||
|
||||
if (X509_STORE_CTX_init(ctx, store, cert, NULL) != 1)
|
||||
{
|
||||
[self logWithFormat: @"EAS - validateCert failed for device %@: X509_STORE_CTX_init failed", [context objectForKey: @"DeviceId"]];
|
||||
X509_STORE_CTX_free(ctx);
|
||||
return 17;
|
||||
}
|
||||
|
||||
rc = X509_verify_cert(ctx);
|
||||
X509_STORE_CTX_free(ctx);
|
||||
X509_free(cert);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self logWithFormat: @"EAS - validateCert failed for device %@: err=%d", [context objectForKey: @"DeviceId"], X509_STORE_CTX_get_error(ctx)];
|
||||
return 17;
|
||||
}
|
||||
}
|
||||
#else
|
||||
- (unsigned int) validateCert: (NSString *) theCert
|
||||
{
|
||||
return 17;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void) processValidateCert: (id <DOMElement>) theDocumentElement
|
||||
inResponse: (WOResponse *) theResponse
|
||||
{
|
||||
NSMutableString *s;
|
||||
NSString *cert;
|
||||
NSData *d;
|
||||
|
||||
cert = [[(id)[theDocumentElement getElementsByTagName: @"Certificate"] lastObject] textValue];
|
||||
|
||||
s = [NSMutableString string];
|
||||
[s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
|
||||
[s appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
|
||||
[s appendString: @"<ValidateCert xmlns=\"ValidateCert:\">"];
|
||||
[s appendString: @"<Status>1</Status><Certificate>"];
|
||||
[s appendFormat: @"<Status>%d</Status>", [self validateCert: cert]];
|
||||
[s appendString: @"</Certificate></ValidateCert>"];
|
||||
|
||||
d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
|
||||
|
||||
[theResponse setContent: d];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// <?xml version="1.0"?>
|
||||
// <!DOCTYPE ActiveSync PUBLIC "-//MICROSOFT//DTD ActiveSync//EN" "http://www.microsoft.com/">
|
||||
@@ -2410,39 +2587,100 @@ static BOOL debugOn = NO;
|
||||
NGMimeMessageParser *parser;
|
||||
NGMimeMessage *message;
|
||||
NSException *error;
|
||||
NSData *data;
|
||||
NGMutableHashMap *map;
|
||||
NGMimeMessage *messageToSend;
|
||||
NGMimeMessageGenerator *generator;
|
||||
NSMutableData *data;
|
||||
NSData *new_from_header;
|
||||
NSDictionary *identity;
|
||||
NSString *fullName, *email;
|
||||
|
||||
const char *bytes;
|
||||
int i, e, len;
|
||||
BOOL found_header;
|
||||
|
||||
// We get the mail's data
|
||||
data = [[[[(id)[theDocumentElement getElementsByTagName: @"MIME"] lastObject] textValue] stringByDecodingBase64] dataUsingEncoding: NSUTF8StringEncoding];
|
||||
data = [NSMutableData dataWithData: [[[[(id)[theDocumentElement getElementsByTagName: @"MIME"] lastObject] textValue] stringByDecodingBase64] dataUsingEncoding: NSUTF8StringEncoding]];
|
||||
|
||||
// We extract the recipients
|
||||
parser = [[NGMimeMessageParser alloc] init];
|
||||
message = [parser parsePartFromData: data];
|
||||
RELEASE(parser);
|
||||
|
||||
map = [NGHashMap hashMapWithDictionary: [message headers]];
|
||||
|
||||
identity = [[context activeUser] primaryIdentity];
|
||||
|
||||
fullName = [identity objectForKey: @"fullName"];
|
||||
email = [identity objectForKey: @"email"];
|
||||
|
||||
if ([fullName length])
|
||||
[map setObject: [NSString stringWithFormat: @"%@ <%@>", fullName, email] forKey: @"from"];
|
||||
new_from_header = [[NSString stringWithFormat: @"From: %@ <%@>\r\n", [fullName asQPSubjectString: @"utf-8"], email] dataUsingEncoding:NSUTF8StringEncoding];
|
||||
else
|
||||
[map setObject: email forKey: @"from"];
|
||||
new_from_header = [[NSString stringWithFormat: @"From: %@\r\n", email] dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
messageToSend = [[[NGMimeMessage alloc] initWithHeader: map] autorelease];
|
||||
bytes = [data bytes];
|
||||
len = [data length];
|
||||
i = 0;
|
||||
found_header = NO;
|
||||
|
||||
[messageToSend setBody: [message body]];
|
||||
// Search for the from-header
|
||||
while (i < len)
|
||||
{
|
||||
if (i == 0 &&
|
||||
(*bytes == 'f' || *bytes == 'F') &&
|
||||
(*(bytes+1) == 'r' || *(bytes+1) == 'R') &&
|
||||
(*(bytes+2) == 'o' || *(bytes+2) == 'O') &&
|
||||
(*(bytes+3) == 'm' || *(bytes+3) == 'M') &&
|
||||
(*(bytes+4) == ':'))
|
||||
{
|
||||
found_header = YES;
|
||||
break;
|
||||
}
|
||||
|
||||
if (((*bytes == '\r') && (*(bytes+1) == '\n')) &&
|
||||
(*(bytes+2) == 'f' || *(bytes+2) == 'F') &&
|
||||
(*(bytes+3) == 'r' || *(bytes+3) == 'R') &&
|
||||
(*(bytes+4) == 'o' || *(bytes+4) == 'O') &&
|
||||
(*(bytes+5) == 'm' || *(bytes+5) == 'M') &&
|
||||
(*(bytes+6) == ':'))
|
||||
{
|
||||
found_header = YES;
|
||||
i = i + 2; // \r\n
|
||||
bytes = bytes + 2;
|
||||
break;
|
||||
}
|
||||
|
||||
bytes++;
|
||||
i++;
|
||||
}
|
||||
|
||||
// We search for the first \r\n AFTER the From: header to get the length of the string to replace.
|
||||
e = i;
|
||||
while (e < len)
|
||||
{
|
||||
if ((*bytes == '\r') && (*(bytes+1) == '\n'))
|
||||
{
|
||||
e = e + 2;
|
||||
break;
|
||||
}
|
||||
|
||||
bytes++;
|
||||
e++;
|
||||
}
|
||||
|
||||
// Update/Add the From header in the MIMEBody of the SendMail request.
|
||||
// Any other way to modify the mail body would break s/mime emails.
|
||||
if (found_header)
|
||||
{
|
||||
// Change the From header
|
||||
[data replaceBytesInRange: NSMakeRange(i, (NSUInteger)(e-i))
|
||||
withBytes: [new_from_header bytes]
|
||||
length: [new_from_header length]];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add a From header
|
||||
[data replaceBytesInRange: NSMakeRange(0, 0)
|
||||
withBytes: [new_from_header bytes]
|
||||
length: [new_from_header length]];
|
||||
}
|
||||
|
||||
generator = [[[NGMimeMessageGenerator alloc] init] autorelease];
|
||||
data = [generator generateMimeFromPart: messageToSend];
|
||||
|
||||
error = [self _sendMail: data
|
||||
recipients: [message allRecipients]
|
||||
saveInSentItems: ([(id)[theDocumentElement getElementsByTagName: @"SaveInSentItems"] count] ? YES : NO)];
|
||||
@@ -2619,6 +2857,11 @@ static BOOL debugOn = NO;
|
||||
[map setObject: [mailObject messageId] forKey: @"in-reply-to"];
|
||||
|
||||
references = [[[[[mailObject mailHeaders] objectForKey: @"references"] componentsSeparatedByString: @" "] mutableCopy] autorelease];
|
||||
|
||||
// If there is no References: header, initialize it with In-Reply-To.
|
||||
if ([mailObject inReplyTo] && ![references count])
|
||||
references = [NSMutableArray arrayWithObject: [mailObject inReplyTo]];
|
||||
|
||||
if ([references count] > 0)
|
||||
{
|
||||
// If there are more than ten identifiers listed, we eliminate the second one.
|
||||
@@ -2934,9 +3177,25 @@ static BOOL debugOn = NO;
|
||||
options: NSCaseInsensitiveSearch].location == NSNotFound)
|
||||
{
|
||||
NSString *value;
|
||||
|
||||
value = [[NSDate date] descriptionWithCalendarFormat: @"%a, %d %b %Y %H:%M:%S %z" timeZone: [NSTimeZone timeZoneWithName: @"GMT"] locale: nil];
|
||||
s = [NSString stringWithFormat: @"Date: %@\n%@", value, [theRequest contentAsString]];
|
||||
#if GNUSTEP_BASE_MINOR_VERSION < 21
|
||||
value = [[NSDate date] descriptionWithCalendarFormat: @"%a, %d %b %Y %H:%M:%S %z"
|
||||
timeZone: [NSTimeZone timeZoneWithName: @"GMT"]
|
||||
locale: nil];
|
||||
#else
|
||||
value = [[NSDate date] descriptionWithCalendarFormat: @"%a, %d %b %Y %H:%M:%S %z"
|
||||
timeZone: [NSTimeZone timeZoneWithName: @"GMT"]
|
||||
locale: [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSArray arrayWithObjects: @"Jan", @"Feb", @"Mar", @"Apr",
|
||||
@"May", @"Jun", @"Jul", @"Aug",
|
||||
@"Sep", @"Oct", @"Nov", @"Dec", nil],
|
||||
@"NSShortMonthNameArray",
|
||||
[NSArray arrayWithObjects: @"Sun", @"Mon", @"Tue", @"Wed", @"Thu",
|
||||
@"Fri", @"Sat", nil],
|
||||
@"NSShortWeekDayNameArray",
|
||||
nil]];
|
||||
|
||||
#endif
|
||||
s = [NSString stringWithFormat: @"Date: %@\r\n%@", value, [theRequest contentAsString]];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3002,7 +3261,7 @@ static BOOL debugOn = NO;
|
||||
[theResponse setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
|
||||
[theResponse setHeader: @"2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
|
||||
|
||||
if (debugOn && [[theResponse content] length])
|
||||
if (debugOn && [[theResponse headerForKey: @"Content-Type"] isEqualToString:@"application/vnd.ms-sync.wbxml"] && [[theResponse content] length])
|
||||
[self logWithFormat: @"EAS - response for device %@: %@", [context objectForKey: @"DeviceId"], [[[NSString alloc] initWithData: [[theResponse content] wbxml2xml] encoding: NSUTF8StringEncoding] autorelease]];
|
||||
|
||||
RELEASE(context);
|
||||
@@ -3026,8 +3285,7 @@ static BOOL debugOn = NO;
|
||||
return nil;
|
||||
|
||||
urlString = [[user domainDefaults] folderInfoURL];
|
||||
parts = [[urlString componentsSeparatedByString: @"/"]
|
||||
mutableCopy];
|
||||
parts = [[urlString componentsSeparatedByString: @"/"] mutableCopy];
|
||||
[parts autorelease];
|
||||
if ([parts count] == 5)
|
||||
{
|
||||
|
||||
@@ -29,20 +29,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "SOGoMailObject+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSException.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalEvent.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
#import <NGExtensions/NGQuotedPrintableCoding.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGExtensions/NSString+Encoding.h>
|
||||
#import <NGImap4/NGImap4Envelope.h>
|
||||
@@ -50,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <NGImap4/NSString+Imap4.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WOApplication.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
|
||||
#import <NGMime/NGMimeBodyPart.h>
|
||||
#import <NGMime/NGMimeFileData.h>
|
||||
@@ -59,8 +57,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import <NGMail/NGMimeMessage.h>
|
||||
#import <NGMail/NGMimeMessageGenerator.h>
|
||||
|
||||
#import <Mailer/SOGoMailLabel.h>
|
||||
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
|
||||
#include "iCalTimeZone+ActiveSync.h"
|
||||
@@ -70,13 +66,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <Appointments/iCalEntityObject+SOGo.h>
|
||||
#include <Appointments/iCalPerson+SOGo.h>
|
||||
#include <Mailer/NSString+Mail.h>
|
||||
#include <Mailer/SOGoMailBodyPart.h>
|
||||
#include <Mailer/NSString+Mail.h>
|
||||
|
||||
#include <SOGo/SOGoUser.h>
|
||||
#include <SOGo/NSString+Utilities.h>
|
||||
|
||||
#import <Appointments/SOGoAptMailNotification.h>
|
||||
|
||||
|
||||
|
||||
unsigned char strToChar(char a, char b) {
|
||||
char encoder[3] = {'\0','\0','\0'};
|
||||
encoder[0] = a;
|
||||
@@ -423,7 +422,7 @@ struct GlobalObjectId {
|
||||
mimeType = [NGMimeType mimeType: [[thePart contentType] type]
|
||||
subType: [[thePart contentType] subType]
|
||||
parameters: [NSDictionary dictionaryWithObject: @"utf-8" forKey: @"charset"]];
|
||||
[thePart setHeader: mimeType forKey: @"content-type"];
|
||||
[(NGMimeBodyPart *)thePart setHeader: mimeType forKey: @"content-type"];
|
||||
|
||||
fdata = [[NGMimeFileData alloc] initWithBytes: [body bytes]
|
||||
length: [body length]];
|
||||
@@ -472,18 +471,46 @@ struct GlobalObjectId {
|
||||
return d;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (BOOL) _sanitinizeNeeded: (NSArray *) theParts
|
||||
{
|
||||
NSString *encoding, *charset;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < [theParts count]; i++)
|
||||
{
|
||||
encoding = [[theParts objectAtIndex: i ] objectForKey: @"encoding"];
|
||||
charset = [[[theParts objectAtIndex: i ] objectForKey: @"parameterList"] objectForKey: @"charset"];
|
||||
if (encoding && [encoding caseInsensitiveCompare: @"8bit"] == NSOrderedSame &&
|
||||
charset && ![charset caseInsensitiveCompare: @"utf-8"] == NSOrderedSame
|
||||
&& ![charset caseInsensitiveCompare: @"us-ascii"] == NSOrderedSame)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
if ([self _sanitinizeNeeded: [[theParts objectAtIndex: i ] objectForKey: @"parts"]])
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (NSData *) _preferredBodyDataUsingType: (int) theType
|
||||
mimeSupport: (int) theMimeSupport
|
||||
nativeType: (int *) theNativeType
|
||||
{
|
||||
NSString *type, *subtype, *encoding;
|
||||
NSData *d;
|
||||
BOOL isSMIME, sanitinizeNeeded;
|
||||
|
||||
type = [[[self bodyStructure] valueForKey: @"type"] lowercaseString];
|
||||
subtype = [[[self bodyStructure] valueForKey: @"subtype"] lowercaseString];
|
||||
|
||||
isSMIME = NO;
|
||||
d = nil;
|
||||
|
||||
// We determine the native type
|
||||
@@ -494,8 +521,14 @@ struct GlobalObjectId {
|
||||
else if ([type isEqualToString: @"multipart"])
|
||||
*theNativeType = 4;
|
||||
|
||||
if (([subtype isEqualToString: @"signed"] || [subtype isEqualToString: @"pkcs7-mime"] ) && theMimeSupport > 0)
|
||||
{
|
||||
*theNativeType = 4;
|
||||
isSMIME = YES;
|
||||
}
|
||||
|
||||
// We get the right part based on the preference
|
||||
if (theType == 1 || theType == 2)
|
||||
if ((theType == 1 || theType == 2) && !isSMIME)
|
||||
{
|
||||
if ([type isEqualToString: @"text"] && ![subtype isEqualToString: @"calendar"])
|
||||
{
|
||||
@@ -536,12 +569,12 @@ struct GlobalObjectId {
|
||||
d = [self _preferredBodyDataInMultipartUsingType: theType nativeTypeFound: theNativeType];
|
||||
}
|
||||
}
|
||||
else if (theType == 4)
|
||||
else if (theType == 4 || isSMIME)
|
||||
{
|
||||
// We sanitize the content *ONLY* for Outlook clients and if the content-transfer-encoding is 8bit. Outlook has strange issues
|
||||
// with quoted-printable/base64 encoded text parts. It just doesn't decode them.
|
||||
encoding = [[self lookupInfoForBodyPart: @""] objectForKey: @"encoding"];
|
||||
if ([[context objectForKey: @"DeviceType"] isEqualToString: @"WindowsOutlook15"] || ([encoding caseInsensitiveCompare: @"8bit"] == NSOrderedSame))
|
||||
// We sanitize the content if the content-transfer-encoding is 8bit and charset is not utf-8 or us-ascii.
|
||||
sanitinizeNeeded = [self _sanitinizeNeeded: [NSArray arrayWithObject: [self bodyStructure]]];
|
||||
|
||||
if (sanitinizeNeeded && !isSMIME)
|
||||
d = [self _sanitizedMIMEMessage];
|
||||
else
|
||||
d = [self content];
|
||||
@@ -572,6 +605,35 @@ struct GlobalObjectId {
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) _truncateContent: (NSString *) theContent
|
||||
limit: (int) theLimit
|
||||
truncated: (int *) wasTruncated
|
||||
{
|
||||
if ([theContent length] > theLimit)
|
||||
{
|
||||
int i, len;
|
||||
|
||||
theContent = [theContent substringToIndex: theLimit];
|
||||
*wasTruncated = 1;
|
||||
|
||||
// We search for the first "space" character starting from the
|
||||
// end and we truncate the string once more. We do this to avoid
|
||||
// truncating the content in the middle of a XML entity
|
||||
len = theLimit-1;
|
||||
|
||||
for (i = len; i >= 0; i--)
|
||||
{
|
||||
if (isspace([theContent characterAtIndex: i]))
|
||||
break;
|
||||
}
|
||||
|
||||
return [theContent substringToIndex: i];
|
||||
}
|
||||
|
||||
*wasTruncated = 0;
|
||||
return theContent;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -656,16 +718,19 @@ struct GlobalObjectId {
|
||||
{
|
||||
NSData *d, *globalObjId;
|
||||
NSArray *attachmentKeys;
|
||||
NSMutableString *s;
|
||||
|
||||
uint32_t v;
|
||||
NSString *p;
|
||||
|
||||
id value;
|
||||
|
||||
iCalCalendar *calendar;
|
||||
NSString *p, *subtype;
|
||||
NSMutableString *s;
|
||||
id value;
|
||||
|
||||
int preferredBodyType, nativeBodyType;
|
||||
int preferredBodyType, mimeSupport, mimeTruncation, nativeBodyType;
|
||||
uint32_t v;
|
||||
|
||||
subtype = [[[self bodyStructure] valueForKey: @"subtype"] lowercaseString];
|
||||
|
||||
preferredBodyType = [[context objectForKey: @"BodyPreferenceType"] intValue];
|
||||
mimeSupport = [[context objectForKey: @"MIMESupport"] intValue];
|
||||
mimeTruncation = [[context objectForKey: @"MIMETruncation"] intValue];
|
||||
|
||||
s = [NSMutableString string];
|
||||
|
||||
@@ -862,7 +927,12 @@ struct GlobalObjectId {
|
||||
else
|
||||
{
|
||||
// MesssageClass and ContentClass
|
||||
[s appendFormat: @"<MessageClass xmlns=\"Email:\">%@</MessageClass>", @"IPM.Note"];
|
||||
if ([subtype isEqualToString: @"signed"])
|
||||
[s appendFormat: @"<MessageClass xmlns=\"Email:\">%@</MessageClass>", @"IPM.Note.SMIME.MultipartSigned"];
|
||||
else if ([subtype isEqualToString: @"pkcs7-mime"])
|
||||
[s appendFormat: @"<MessageClass xmlns=\"Email:\">%@</MessageClass>", @"IPM.Note.SMIME"];
|
||||
else
|
||||
[s appendFormat: @"<MessageClass xmlns=\"Email:\">%@</MessageClass>", @"IPM.Note"];
|
||||
[s appendFormat: @"<ContentClass xmlns=\"Email:\">%@</ContentClass>", @"urn:content-classes:message"];
|
||||
}
|
||||
|
||||
@@ -876,10 +946,8 @@ struct GlobalObjectId {
|
||||
[s appendFormat: @"<InternetCPID xmlns=\"Email:\">%@</InternetCPID>", @"65001"];
|
||||
|
||||
// Body - namespace 17
|
||||
preferredBodyType = [[context objectForKey: @"BodyPreferenceType"] intValue];
|
||||
|
||||
nativeBodyType = 1;
|
||||
d = [self _preferredBodyDataUsingType: preferredBodyType nativeType: &nativeBodyType];
|
||||
d = [self _preferredBodyDataUsingType: preferredBodyType mimeSupport: mimeSupport nativeType: &nativeBodyType];
|
||||
|
||||
if (calendar && !d)
|
||||
{
|
||||
@@ -968,9 +1036,50 @@ struct GlobalObjectId {
|
||||
AUTORELEASE(content);
|
||||
|
||||
content = [content activeSyncRepresentationInContext: context];
|
||||
len = [content length];
|
||||
truncated = 0;
|
||||
|
||||
len = [content length];
|
||||
// We handle MIMETruncation
|
||||
switch (mimeTruncation)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
content = @"";
|
||||
len = 0; truncated = 1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
content = [self _truncateContent: content limit: 4096 truncated: &truncated];
|
||||
len = [content length];
|
||||
break;
|
||||
case 2:
|
||||
content = [self _truncateContent: content limit: 5120 truncated: &truncated];
|
||||
len = [content length];
|
||||
break;
|
||||
case 3:
|
||||
content = [self _truncateContent: content limit: 7168 truncated: &truncated];
|
||||
len = [content length];
|
||||
break;
|
||||
case 4:
|
||||
content = [self _truncateContent: content limit: 10240 truncated: &truncated];
|
||||
len = [content length];
|
||||
break;
|
||||
case 5:
|
||||
content = [self _truncateContent: content limit: 20480 truncated: &truncated];
|
||||
len = [content length];
|
||||
break;
|
||||
case 6:
|
||||
content = [self _truncateContent: content limit: 51200 truncated: &truncated];
|
||||
len = [content length];
|
||||
break;
|
||||
case 7:
|
||||
content = [self _truncateContent: content limit: 102400 truncated: &truncated];
|
||||
len = [content length];
|
||||
break;
|
||||
case 8:
|
||||
default:
|
||||
truncated = 0;
|
||||
}
|
||||
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
@@ -978,30 +1087,30 @@ struct GlobalObjectId {
|
||||
[s appendFormat: @"<BodyTruncated xmlns=\"Email:\">%d</BodyTruncated>", truncated];
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
|
||||
// Set the correct type if client requested text/html but we got text/plain
|
||||
// Set the correct type if client requested text/html but we got text/plain.
|
||||
// For s/mime mails type is always 4 if mimeSupport is 1 or 2.
|
||||
if (preferredBodyType == 2 && nativeBodyType == 1)
|
||||
[s appendString: @"<Type>1</Type>"];
|
||||
else if (([subtype isEqualToString: @"signed"] || [subtype isEqualToString: @"pkcs7-mime"] ) && mimeSupport > 0)
|
||||
[s appendString: @"<Type>4</Type>"];
|
||||
else
|
||||
[s appendFormat: @"<Type>%d</Type>", preferredBodyType];
|
||||
|
||||
[s appendFormat: @"<Truncated>%d</Truncated>", truncated];
|
||||
[s appendFormat: @"<Preview></Preview>"];
|
||||
|
||||
if (!truncated)
|
||||
{
|
||||
[s appendFormat: @"<Data>%@</Data>", content];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", len];
|
||||
}
|
||||
[s appendFormat: @"<Data>%@</Data>", content];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", len];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Attachments -namespace 16
|
||||
attachmentKeys = [self fetchFileAttachmentKeys];
|
||||
if ([attachmentKeys count])
|
||||
|
||||
if ([attachmentKeys count] && !([subtype isEqualToString: @"signed"]))
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -1071,15 +1180,21 @@ struct GlobalObjectId {
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"14.0"] ||
|
||||
[[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"14.1"])
|
||||
{
|
||||
id value;
|
||||
NSString *reference;
|
||||
|
||||
reference = [[[[self mailHeaders] objectForKey: @"references"] componentsSeparatedByString: @" "] objectAtIndex: 0];
|
||||
value = [[self mailHeaders] objectForKey: @"references"];
|
||||
|
||||
if ([value isKindOfClass: [NSArray class]])
|
||||
reference = [[[value objectAtIndex: 0] componentsSeparatedByString: @" "] objectAtIndex: 0];
|
||||
else
|
||||
reference = [[value componentsSeparatedByString: @" "] objectAtIndex: 0];
|
||||
|
||||
if ([reference length] > 0)
|
||||
[s appendFormat: @"<ConversationId xmlns=\"Email2:\">%@</ConversationId>", [[reference dataUsingEncoding: NSUTF8StringEncoding] activeSyncRepresentationInContext: context]];
|
||||
else if ([self inReplyTo])
|
||||
else if ([[self inReplyTo] length] > 0)
|
||||
[s appendFormat: @"<ConversationId xmlns=\"Email2:\">%@</ConversationId>", [[[self inReplyTo] dataUsingEncoding: NSUTF8StringEncoding] activeSyncRepresentationInContext: context]];
|
||||
else if ([self messageId])
|
||||
else if ([[self messageId] length] > 0)
|
||||
[s appendFormat: @"<ConversationId xmlns=\"Email2:\">%@</ConversationId>", [[[self messageId] dataUsingEncoding: NSUTF8StringEncoding] activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@interface SOGoSyncCacheObject : NSObject
|
||||
{
|
||||
@public
|
||||
id _uid;
|
||||
id _sequence;
|
||||
}
|
||||
|
||||
@@ -32,9 +32,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import <Foundation/NSNull.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
static Class NSNullK;
|
||||
|
||||
@implementation SOGoSyncCacheObject
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
NSNullK = [NSNull class];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
@@ -46,14 +54,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id) syncCacheObjectWithUID: (id) theUID sequence: (id) theSequence;
|
||||
+ (id) syncCacheObjectWithUID: (id) theUID sequence: (id) theSequence
|
||||
{
|
||||
id o;
|
||||
|
||||
o = [[self alloc] init];
|
||||
|
||||
[o setUID: theUID];
|
||||
[o setSequence: theSequence];
|
||||
|
||||
[o setUID: [NSNumber numberWithInt: [theUID intValue]]];
|
||||
[o setSequence: ([theSequence isKindOfClass: NSNullK] ? theSequence : [NSNumber numberWithInt: [theSequence intValue]])];
|
||||
|
||||
return [o autorelease];
|
||||
}
|
||||
@@ -67,7 +75,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
- (id) uid
|
||||
{
|
||||
return _uid;
|
||||
return [_uid description];
|
||||
}
|
||||
|
||||
- (void) setUID: (id) theUID
|
||||
@@ -77,7 +85,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
- (id) sequence
|
||||
{
|
||||
return _sequence;
|
||||
return ([_sequence isKindOfClass: NSNullK] ? _sequence : [_sequence description]);
|
||||
}
|
||||
|
||||
- (void) setSequence: (id) theSequence
|
||||
@@ -88,7 +96,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
- (NSComparisonResult) compareUID: (SOGoSyncCacheObject *) theSyncCacheObject
|
||||
{
|
||||
return [[self uid] compare: [theSyncCacheObject uid]];
|
||||
return [self->_uid compare: theSyncCacheObject->_uid];
|
||||
}
|
||||
|
||||
//
|
||||
@@ -97,21 +105,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
- (NSComparisonResult) compareSequence: (SOGoSyncCacheObject *) theSyncCacheObject
|
||||
{
|
||||
if ([[self sequence] isEqual: [NSNull null]] &&
|
||||
[[theSyncCacheObject sequence] isEqual: [NSNull null]])
|
||||
if ([self->_sequence isEqual: [NSNull null]] &&
|
||||
[theSyncCacheObject->_sequence isEqual: [NSNull null]])
|
||||
return [self compareUID: theSyncCacheObject];
|
||||
|
||||
if (![[self sequence] isEqual: [NSNull null]] && [[theSyncCacheObject sequence] isEqual: [NSNull null]])
|
||||
if (![self->_sequence isEqual: [NSNull null]] && [theSyncCacheObject->_sequence isEqual: [NSNull null]])
|
||||
return NSOrderedDescending;
|
||||
|
||||
if ([[self sequence] isEqual: [NSNull null]] && ![[theSyncCacheObject sequence] isEqual: [NSNull null]])
|
||||
if ([self->_sequence isEqual: [NSNull null]] && ![theSyncCacheObject->_sequence isEqual: [NSNull null]])
|
||||
return NSOrderedAscending;
|
||||
|
||||
// Must check this here, to avoid comparing NSNull objects
|
||||
if ([[self sequence] compare: [theSyncCacheObject sequence]] == NSOrderedSame)
|
||||
if ([self->_sequence compare: theSyncCacheObject->_sequence] == NSOrderedSame)
|
||||
return [self compareUID: theSyncCacheObject];
|
||||
|
||||
return [[self sequence] compare: [theSyncCacheObject sequence]];
|
||||
return [self->_sequence compare: theSyncCacheObject->_sequence];
|
||||
}
|
||||
|
||||
- (NSString *) description
|
||||
@@ -120,3 +128,4 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -27,9 +27,11 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#import <NGObjWeb/SoObjectWebDAVDispatcher.h>
|
||||
|
||||
#include <NGObjWeb/SoObject+SoDAV.h>
|
||||
|
||||
#include <NGObjWeb/WEClientCapabilities.h>
|
||||
#include <NGObjWeb/WOContext.h>
|
||||
#include <NGObjWeb/WORequest.h>
|
||||
@@ -37,6 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
|
||||
|
||||
@interface SoObjectWebDAVDispatcher (ActiveSync)
|
||||
|
||||
- (id)_callObjectMethod:(NSString *)_method inContext:(WOContext *)_ctx;
|
||||
|
||||
@@ -30,12 +30,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import "iCalAlarm+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
|
||||
#import <NGCards/iCalAlarm.h>
|
||||
#import <NGCards/iCalEvent.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
@@ -58,7 +55,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// don't send negative reminder - not supported
|
||||
if (delta > 0)
|
||||
[s appendFormat: @"<Reminder xmlns=\"Calendar:\">%d</Reminder>", delta];
|
||||
[s appendFormat: @"<Reminder xmlns=\"Calendar:\">%d</Reminder>", (int)delta];
|
||||
}
|
||||
|
||||
return s;
|
||||
|
||||
@@ -41,7 +41,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context;
|
||||
|
||||
- (void) changeParticipationStatus: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context
|
||||
component: (id) component;
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -30,26 +30,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import "iCalEvent+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/NSCalendarDate+NGCards.h>
|
||||
#import <NGCards/NSString+NGCards.h>
|
||||
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
#import <SOGo/WORequest+SOGo.h>
|
||||
|
||||
#import <Appointments/iCalEntityObject+SOGo.h>
|
||||
#import <Appointments/iCalRepeatableEntityObject+SOGo.h>
|
||||
#import <Appointments/SOGoAppointmentObject.h>
|
||||
|
||||
#include "iCalAlarm+ActiveSync.h"
|
||||
#include "iCalRecurrenceRule+ActiveSync.h"
|
||||
@@ -98,10 +99,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
else if ([self created])
|
||||
[s appendFormat: @"<DTStamp xmlns=\"Calendar:\">%@</DTStamp>", [[self created] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
|
||||
// Timezone
|
||||
tz = [(iCalDateTime *)[self firstChildWithTag: @"dtstart"] timeZone];
|
||||
|
||||
// StartTime -- http://msdn.microsoft.com/en-us/library/ee157132(v=exchg.80).aspx
|
||||
if ([self startDate])
|
||||
{
|
||||
if ([self isAllDay])
|
||||
if ([self isAllDay] && !tz)
|
||||
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>",
|
||||
[[[self startDate] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
@@ -114,7 +118,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// EndTime -- http://msdn.microsoft.com/en-us/library/ee157945(v=exchg.80).aspx
|
||||
if ([self endDate])
|
||||
{
|
||||
if ([self isAllDay])
|
||||
if ([self isAllDay] && !tz)
|
||||
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>",
|
||||
[[[self endDate] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
@@ -124,20 +128,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>", [[self endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
|
||||
// Timezone
|
||||
tz = [(iCalDateTime *)[self firstChildWithTag: @"dtstart"] timeZone];
|
||||
|
||||
if (!tz)
|
||||
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
|
||||
|
||||
[s appendFormat: @"<TimeZone xmlns=\"Calendar:\">%@</TimeZone>", [tz activeSyncRepresentationInContext: context]];
|
||||
if (![self recurrenceId])
|
||||
[s appendFormat: @"<TimeZone xmlns=\"Calendar:\">%@</TimeZone>", [tz activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Organizer and other invitations related properties
|
||||
if ((organizer = [self organizer]))
|
||||
{
|
||||
meetingStatus = 1; // meeting and the user is the meeting organizer.
|
||||
o = [organizer rfc822Email];
|
||||
if ([o length])
|
||||
if (![self recurrenceId] && [o length])
|
||||
{
|
||||
[s appendFormat: @"<Organizer_Email xmlns=\"Calendar:\">%@</Organizer_Email>", o];
|
||||
|
||||
@@ -226,9 +228,37 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//[s appendFormat: @"<Importance xmlns=\"Calendar:\">%d</Importance>", v];
|
||||
|
||||
// UID -- http://msdn.microsoft.com/en-us/library/ee159919(v=exchg.80).aspx
|
||||
if ([[self uid] length])
|
||||
[s appendFormat: @"<UID xmlns=\"Calendar:\">%@</UID>", [self uid]];
|
||||
|
||||
if (![self recurrenceId] && [[self uid] length])
|
||||
[s appendFormat: @"<UID xmlns=\"Calendar:\">%@</UID>", [[self uid] activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Recurrence rules
|
||||
if ([self isRecurrent])
|
||||
[s appendString: [[[self recurrenceRules] lastObject] activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Comment
|
||||
o = [self comment];
|
||||
//if (![self recurrenceId] && [o length])
|
||||
if ([o length])
|
||||
{
|
||||
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
|
||||
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
|
||||
o = [o activeSyncRepresentationInContext: context];
|
||||
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
[s appendFormat: @"<Body xmlns=\"Calendar:\">%@</Body>", o];
|
||||
[s appendString: @"<BodyTruncated xmlns=\"Calendar:\">0</BodyTruncated>"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", 1];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", (int)[o length]];
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
}
|
||||
|
||||
// Sensitivity
|
||||
if ([[self accessClass] isEqualToString: @"PRIVATE"])
|
||||
v = 2;
|
||||
@@ -251,7 +281,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendFormat: @"</Categories>"];
|
||||
}
|
||||
|
||||
|
||||
// Reminder -- http://msdn.microsoft.com/en-us/library/ee219691(v=exchg.80).aspx
|
||||
// TODO: improve this to handle more alarm types
|
||||
if ([self hasAlarms])
|
||||
@@ -262,36 +291,79 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendString: [alarm activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
// Recurrence rules
|
||||
// Exceptions
|
||||
if ([self isRecurrent])
|
||||
{
|
||||
[s appendString: [[[self recurrenceRules] lastObject] activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
NSMutableArray *components, *exdates;
|
||||
iCalEvent *current_component;
|
||||
NSString *recurrence_id;
|
||||
|
||||
// Comment
|
||||
o = [self comment];
|
||||
if ([o length])
|
||||
{
|
||||
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
|
||||
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
|
||||
o = [o activeSyncRepresentationInContext: context];
|
||||
unsigned int count, max, i;
|
||||
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
components = [NSMutableArray arrayWithArray: [[self parent] events]];
|
||||
max = [components count];
|
||||
|
||||
if (max > 1 || [self hasExceptionDates])
|
||||
{
|
||||
[s appendFormat: @"<Body xmlns=\"Calendar:\">%@</Body>", o];
|
||||
[s appendString: @"<BodyTruncated xmlns=\"Calendar:\">0</BodyTruncated>"];
|
||||
exdates = [NSMutableArray arrayWithArray: [self exceptionDates]];
|
||||
|
||||
[s appendString: @"<Exceptions xmlns=\"Calendar:\">"];
|
||||
|
||||
for (count = 1; count < max; count++)
|
||||
{
|
||||
current_component = [components objectAtIndex: count] ;
|
||||
|
||||
if ([self isAllDay])
|
||||
{
|
||||
recurrence_id = [NSString stringWithFormat: @"%@",
|
||||
[[[current_component recurrenceId] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: -[userTimeZone secondsFromGMTForDate:
|
||||
[current_component recurrenceId]]]
|
||||
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
else
|
||||
{
|
||||
recurrence_id = [NSString stringWithFormat: @"%@", [[current_component recurrenceId]
|
||||
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
|
||||
[s appendString: @"<Exception>"];
|
||||
[s appendFormat: @"<Exception_StartTime xmlns=\"Calendar:\">%@</Exception_StartTime>", recurrence_id];
|
||||
[s appendFormat: @"%@", [current_component activeSyncRepresentationInContext: context]];
|
||||
[s appendString: @"</Exception>"];
|
||||
}
|
||||
|
||||
for (i = 0; i < [exdates count]; i++)
|
||||
{
|
||||
[s appendString: @"<Exception>"];
|
||||
[s appendString: @"<Exception_Deleted>1</Exception_Deleted>"];
|
||||
|
||||
if ([self isAllDay])
|
||||
{
|
||||
recurrence_id = [NSString stringWithFormat: @"%@",
|
||||
[[[[exdates objectAtIndex: i] asCalendarDate] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: -[userTimeZone secondsFromGMTForDate:
|
||||
[[exdates objectAtIndex: i] asCalendarDate]]]
|
||||
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
else
|
||||
{
|
||||
recurrence_id = [NSString stringWithFormat: @"%@", [[[exdates objectAtIndex: i] asCalendarDate]
|
||||
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
|
||||
[s appendFormat: @"<Exception_StartTime xmlns=\"Calendar:\">%@</Exception_StartTime>", recurrence_id];
|
||||
[s appendString: @"</Exception>"];
|
||||
}
|
||||
|
||||
[s appendString: @"</Exceptions>"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", 1];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
}
|
||||
|
||||
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
|
||||
if (![self recurrenceId])
|
||||
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -337,13 +409,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
iCalDateTime *start, *end;
|
||||
iCalDateTime *start, *end; //, *oldstart;
|
||||
NSCalendarDate *oldstart;
|
||||
NSTimeZone *userTimeZone;
|
||||
iCalTimeZone *tz;
|
||||
id o;
|
||||
int deltasecs;
|
||||
|
||||
BOOL isAllDay;
|
||||
|
||||
|
||||
NSMutableArray *occurences;
|
||||
|
||||
occurences = [NSMutableArray arrayWithArray: [[self parent] events]];
|
||||
|
||||
if ((o = [theValues objectForKey: @"UID"]))
|
||||
[self setUid: o];
|
||||
|
||||
@@ -356,6 +434,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
isAllDay = YES;
|
||||
}
|
||||
else if ([occurences count] && !([theValues objectForKey: @"AllDayEvent"]))
|
||||
{
|
||||
// If the occurence has no AllDay tag use it from master.
|
||||
isAllDay = [[occurences objectAtIndex: 0] isAllDay];
|
||||
}
|
||||
|
||||
//
|
||||
// 0- free, 1- tentative, 2- busy and 3- out of office
|
||||
@@ -422,6 +505,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
o = [o calendarDate];
|
||||
start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
|
||||
oldstart = [start dateTime];
|
||||
[start setTimeZone: tz];
|
||||
|
||||
if (isAllDay)
|
||||
@@ -433,6 +517,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
[start setDateTime: o];
|
||||
}
|
||||
|
||||
// Calculate delta if start date has been changed.
|
||||
if (oldstart)
|
||||
deltasecs = [[start dateTime ] timeIntervalSinceDate: oldstart] * -1;
|
||||
else
|
||||
deltasecs = 0;
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"EndTime"]))
|
||||
@@ -491,6 +581,177 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
RELEASE(rule);
|
||||
|
||||
[rule takeActiveSyncValues: o inContext: context];
|
||||
|
||||
// Exceptions
|
||||
if ((o = [theValues objectForKey: @"Exceptions"]) && [o isKindOfClass: [NSArray class]])
|
||||
{
|
||||
NSCalendarDate *recurrenceId, *adjustedRecurrenceId, *currentId;
|
||||
NSMutableArray *exdates, *exceptionstouched;
|
||||
iCalEvent *currentOccurence;
|
||||
NSDictionary *exception;
|
||||
|
||||
unsigned int i, count, max;
|
||||
|
||||
[self removeAllExceptionDates];
|
||||
|
||||
exdates = [NSMutableArray array];
|
||||
exceptionstouched = [NSMutableArray array];
|
||||
|
||||
for (i = 0; i < [o count]; i++)
|
||||
{
|
||||
exception = [o objectAtIndex: i];
|
||||
|
||||
if (![[exception objectForKey: @"Exception_Deleted"] intValue])
|
||||
{
|
||||
recurrenceId = [[exception objectForKey: @"Exception_StartTime"] asCalendarDate];
|
||||
|
||||
if (isAllDay)
|
||||
recurrenceId = [recurrenceId dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: [userTimeZone secondsFromGMTForDate:recurrenceId]];
|
||||
|
||||
// When moving the calendar entry (i.e. changing the startDate) iOS and Android sometimes send a value for
|
||||
// Exception_StartTime which is not what we expect.
|
||||
// With this we make sure the recurrenceId is always correct.
|
||||
//
|
||||
// iOS problem - If the master is a no-allday-event but the exception is, an invalid Exception_StartTime is in the request.
|
||||
// e.g. it sends 20150409T040000Z instead of 20150409T060000Z;
|
||||
// This might be a special case since iPhone doesn't allow an allday-exception on a non-allday-event.
|
||||
if (!([[start dateTime] compare: [[start dateTime] hour:[recurrenceId hourOfDay] minute:[recurrenceId minuteOfHour]]] == NSOrderedSame))
|
||||
recurrenceId = [recurrenceId hour:[[start dateTime] hourOfDay] minute:[[start dateTime] minuteOfHour]];
|
||||
|
||||
// We need to store the recurrenceIds and exception dates adjusted by deltasecs.
|
||||
// This ensures that the adjustment in SOGoCalendarComponent->updateComponent->_updateRecurrenceIDsWithEvent gives the correct dates.
|
||||
adjustedRecurrenceId = [recurrenceId dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0 seconds: deltasecs];
|
||||
|
||||
// search for an existing occurence and update it
|
||||
max = [occurences count];
|
||||
currentOccurence = nil;
|
||||
count = 1;
|
||||
while (count < max)
|
||||
{
|
||||
currentOccurence = [occurences objectAtIndex: count] ;
|
||||
currentId = [currentOccurence recurrenceId];
|
||||
|
||||
if ([currentId compare: adjustedRecurrenceId] == NSOrderedSame)
|
||||
{
|
||||
[exceptionstouched addObject: adjustedRecurrenceId];
|
||||
[currentOccurence takeActiveSyncValues: exception inContext: context];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
currentOccurence = nil;
|
||||
}
|
||||
|
||||
// Create a new occurence if we found none to update.
|
||||
if (!currentOccurence)
|
||||
{
|
||||
iCalDateTime *recid;
|
||||
|
||||
currentOccurence = [self mutableCopy];
|
||||
[currentOccurence removeAllRecurrenceRules];
|
||||
[currentOccurence removeAllExceptionRules];
|
||||
[currentOccurence removeAllExceptionDates];
|
||||
|
||||
[[self parent] addToEvents: currentOccurence];
|
||||
[currentOccurence takeActiveSyncValues: exception inContext: context];
|
||||
|
||||
recid = (iCalDateTime *)[currentOccurence uniqueChildWithTag: @"recurrence-id"];
|
||||
if (isAllDay)
|
||||
[recid setDate: adjustedRecurrenceId];
|
||||
else
|
||||
[recid setDateTime: adjustedRecurrenceId];
|
||||
|
||||
[exceptionstouched addObject: [recid dateTime]];
|
||||
}
|
||||
}
|
||||
else if ([[exception objectForKey: @"Exception_Deleted"] intValue])
|
||||
{
|
||||
recurrenceId = [[exception objectForKey: @"Exception_StartTime"] asCalendarDate];
|
||||
|
||||
if (isAllDay)
|
||||
recurrenceId = [recurrenceId dateByAddingYears: 0 months: 0
|
||||
days: 0 hours: 0 minutes: 0
|
||||
seconds: [userTimeZone secondsFromGMTForDate:recurrenceId]];
|
||||
|
||||
// We add only valid exception dates.
|
||||
if ([self doesOccurOnDate: recurrenceId] &&
|
||||
([[start dateTime] compare: [[start dateTime] hour:[recurrenceId hourOfDay]
|
||||
minute:[recurrenceId minuteOfHour]]] == NSOrderedSame))
|
||||
{
|
||||
// We need to store the recurrenceIds and exception dates adjusted by deltasecs.
|
||||
// This ensures that the adjustment in SOGoCalendarComponent->updateComponent->_updateRecurrenceIDsWithEvent gives the correct dates.
|
||||
[exdates addObject: [recurrenceId dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: deltasecs]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update exception dates in master event.
|
||||
max = [exdates count];
|
||||
if (max > 0)
|
||||
{
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
if (([exceptionstouched indexOfObject: [exdates objectAtIndex: count]] == NSNotFound))
|
||||
[self addToExceptionDates: [exdates objectAtIndex: count]];
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all exceptions included in the request.
|
||||
max = [occurences count];
|
||||
count = 1; // skip the master event
|
||||
while (count < max)
|
||||
{
|
||||
currentOccurence = [occurences objectAtIndex: count] ;
|
||||
currentId = [currentOccurence recurrenceId];
|
||||
|
||||
// Delete all occurences which are not touched (modified/added).
|
||||
if (([exceptionstouched indexOfObject: currentId] == NSNotFound))
|
||||
[[[self parent] children] removeObject: currentOccurence];
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else if ([self isRecurrent])
|
||||
{
|
||||
// We have no exceptions in request but there is a recurrence rule.
|
||||
// Remove all excpetions and exception dates.
|
||||
iCalEvent *currentOccurence;
|
||||
unsigned int count, max;
|
||||
|
||||
[self removeAllExceptionDates];
|
||||
max = [occurences count];
|
||||
count = 1; // skip the master event
|
||||
while (count < max)
|
||||
{
|
||||
currentOccurence = [occurences objectAtIndex: count];
|
||||
[[[self parent] children] removeObject: currentOccurence];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ([self isRecurrent])
|
||||
{
|
||||
// We have no recurrence rule in request.
|
||||
// Remove all exceptions, exception dates and recurrence rules.
|
||||
iCalEvent *currentOccurence;
|
||||
unsigned int count, max;
|
||||
|
||||
[self removeAllRecurrenceRules];
|
||||
[self removeAllExceptionRules];
|
||||
[self removeAllExceptionDates];
|
||||
|
||||
max = [occurences count];
|
||||
count = 1; // skip the master event
|
||||
while (count < max)
|
||||
{
|
||||
currentOccurence = [occurences objectAtIndex: count];
|
||||
[[[self parent] children] removeObject: currentOccurence];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Organizer - we don't touch the value unless we're the organizer
|
||||
@@ -498,7 +759,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
([self userIsOrganizer: [context activeUser]] || [[context activeUser] hasEmail: o]))
|
||||
{
|
||||
iCalPerson *person;
|
||||
|
||||
|
||||
person = [iCalPerson elementWithTag: @"organizer"];
|
||||
[person setEmail: o];
|
||||
[person setCn: [theValues objectForKey: @"Organizer_Name"]];
|
||||
@@ -546,7 +807,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
// Windows phones sens sometimes an empty Attendees tag.
|
||||
// We check it's an array before processing it.
|
||||
if ((o = [theValues objectForKey: @"Attendees"])&& [o isKindOfClass: [NSArray class]])
|
||||
if ((o = [theValues objectForKey: @"Attendees"]) && [o isKindOfClass: [NSArray class]])
|
||||
{
|
||||
NSMutableArray *attendees;
|
||||
NSDictionary *attendee;
|
||||
@@ -595,4 +856,36 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
}
|
||||
}
|
||||
|
||||
- (void) changeParticipationStatus: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context
|
||||
component: (id) component
|
||||
{
|
||||
NSString *status;
|
||||
id o;
|
||||
|
||||
// See: https://msdn.microsoft.com/en-us/library/ee202290(v=exchg.80).aspx
|
||||
//
|
||||
// 0 == Free
|
||||
// 1 == Tentative
|
||||
// 2 == Busy
|
||||
// 3 == Out of Office
|
||||
// 4 == Working elsehwere
|
||||
//
|
||||
if ((o = [theValues objectForKey: @"BusyStatus"]))
|
||||
{
|
||||
// We translate >= 2 into ACCEPTED
|
||||
if ([o intValue] == 0)
|
||||
status = @"NEEDS-ACTION";
|
||||
else if ([o intValue] >= 2)
|
||||
status = @"ACCEPTED";
|
||||
else
|
||||
status = @"TENTATIVE";
|
||||
|
||||
// There's no delegate in EAS
|
||||
[(SOGoAppointmentObject *) component changeParticipationStatus: status
|
||||
withDelegate: nil
|
||||
alarm: nil];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -140,7 +140,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// Simple reccurrence rule of type "Monthly"
|
||||
type = 2;
|
||||
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"Calendar:\">%d</Recurrence_DayOfMonth>",
|
||||
[[[self parent] startDate] dayOfMonth]];
|
||||
(int)[[[self parent] startDate] dayOfMonth]];
|
||||
}
|
||||
}
|
||||
else if ([self frequency] == iCalRecurrenceFrequenceYearly)
|
||||
|
||||
@@ -31,15 +31,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSCalendarDate.h>
|
||||
#include <Foundation/NSData.h>
|
||||
#include <Foundation/NSDate.h>
|
||||
#include <Foundation/NSString.h>
|
||||
|
||||
#import <NGCards/iCalByDayMask.h>
|
||||
#import <NGCards/iCalTimeZonePeriod.h>
|
||||
#import <NGCards/iCalRecurrenceRule.h>
|
||||
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
|
||||
#include "NSData+ActiveSync.h"
|
||||
|
||||
|
||||
@@ -29,14 +29,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#import "iCalToDo+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
|
||||
@@ -140,7 +136,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", 1];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", (int)[o length]];
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
|
||||
+5
-4
@@ -57,8 +57,6 @@ ProxyPreserveHost On
|
||||
# Allow from your-cas-host-addr
|
||||
# </Proxy>
|
||||
|
||||
ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
|
||||
|
||||
# Enable to use Microsoft ActiveSync support
|
||||
# Note that you MUST have many sogod workers to use ActiveSync.
|
||||
# See the SOGo Installation and Configuration guide for more details.
|
||||
@@ -67,11 +65,13 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
|
||||
# http://127.0.0.1:20000/SOGo/Microsoft-Server-ActiveSync \
|
||||
# retry=60 connectiontimeout=5 timeout=360
|
||||
|
||||
ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
|
||||
|
||||
<Proxy http://127.0.0.1:20000/SOGo>
|
||||
## adjust the following to your configuration
|
||||
RequestHeader set "x-webobjects-server-port" "443"
|
||||
RequestHeader set "x-webobjects-server-name" "yourhostname"
|
||||
RequestHeader set "x-webobjects-server-url" "https://yourhostname"
|
||||
# RequestHeader set "x-webobjects-server-name" "yourhostname"
|
||||
# RequestHeader set "x-webobjects-server-url" "https://yourhostname"
|
||||
|
||||
## When using proxy-side autentication, you need to uncomment and
|
||||
## adjust the following line:
|
||||
@@ -90,5 +90,6 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
|
||||
<IfModule rewrite_module>
|
||||
RewriteEngine On
|
||||
RewriteRule ^/.well-known/caldav/?$ /SOGo/dav [R=301]
|
||||
RewriteRule ^/.well-known/carddav/?$ /SOGo/dav [R=301]
|
||||
</IfModule>
|
||||
|
||||
@@ -43,23 +43,14 @@ GNUstep
|
||||
SOPE
|
||||
~~~~
|
||||
|
||||
AngularJS
|
||||
~~~~~~~~~
|
||||
JavaScript libraries
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* https://angularjs.org/
|
||||
* http://angular-ui.github.io/ui-router/
|
||||
* https://www.airpair.com/angularjs/posts/angularjs-tutorial
|
||||
|
||||
Angular Material
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
* https://material.angularjs.org/
|
||||
|
||||
Lo-Dash
|
||||
~~~~~~~
|
||||
|
||||
* http://lodash.com/
|
||||
* http://underscorejs.org/
|
||||
* https://github.com/nervgh/angular-file-upload
|
||||
|
||||
Code Style
|
||||
----------
|
||||
@@ -71,6 +62,11 @@ Objective-C
|
||||
|
||||
apidoc -f ".*\\.m" -i UI -o Documentation/JSON-API
|
||||
|
||||
* When returning JSON from an object extending UIxComponent, use the following method:
|
||||
|
||||
- (WOResponse *) responseWithStatus: (unsigned int) status
|
||||
andJSONRepresentation: (NSObject *) contentObject;
|
||||
|
||||
HTML
|
||||
~~~~
|
||||
|
||||
@@ -90,6 +86,8 @@ JavaScript
|
||||
* http://eslint.org/
|
||||
* https://github.com/toddmotto/angularjs-styleguide
|
||||
* https://github.com/angular/material/blob/master/docs/guides/CODING.md
|
||||
* http://jshint.com/
|
||||
* https://github.com/angular/material/tree/master/docs/guides
|
||||
|
||||
* We conform to https://github.com/airbnb/javascript[Airbnb coding standards]. Use https://github.com/jscs-dev/node-jscs[jscs] with the 'airbnb' preset to validate your code style:
|
||||
|
||||
@@ -97,7 +95,7 @@ JavaScript
|
||||
|
||||
* For documentation, we follow the http://usejsdoc.org/[JSDoc3] standards:
|
||||
|
||||
jsdoc UI/WebServerResources/js/{Appointments,Common,Contacts,Mailer}/*.js -d Documentation/JavaScript-API
|
||||
jsdoc UI/WebServerResources/js/{Common,Contacts,Mailer,Preferences,Scheduler}/*.js -d Documentation/JavaScript-API
|
||||
|
||||
Models (facades)
|
||||
^^^^^^^^^^^^^^^^
|
||||
@@ -114,6 +112,12 @@ SASS/CSS
|
||||
* http://componentcss.com/
|
||||
* https://github.com/styleguide/css
|
||||
* https://smacss.com/
|
||||
* http://cssguidelin.es/
|
||||
* http://sixrevisions.com/css/css-methodologies/
|
||||
* https://css-tricks.com/what-a-css-code-review-might-look-like/
|
||||
* http://una.im/classy-css/
|
||||
|
||||
A `@mixin` is like a stamp: it creates a duplicated version of the property block (optionally) with arguments provided. An `@extend` appends the element you are extending to the property block. It is your "yes, and ___" statement.
|
||||
|
||||
* For documentation, we follow http://sassdoc.com/[SassDoc] annotations.
|
||||
* We need the SASS files of Angular Material to build our CSS. The git repository of Angular Material is included as a submodule of SOGo:
|
||||
@@ -126,14 +130,14 @@ SASS/CSS
|
||||
Fonts
|
||||
^^^^^
|
||||
|
||||
* We build a custom icons font using the online app https://icomoon.io/app/#/select[icomoon].
|
||||
* http://www.carrois.com/fira-4-0/
|
||||
* Material Design Iconic Font http://zavoloklom.github.io/material-design-iconic-font/icons.html
|
||||
* [Mozilla Fira](http://mozilla.github.io/Fira/)
|
||||
* [Material icons](https://www.google.com/design/icons/)
|
||||
|
||||
Version Control
|
||||
---------------
|
||||
|
||||
* https://devcharm.com/articles/46/improve-your-git-workflow/
|
||||
* https://github.com/angular/material/blob/master/docs/guides/CONTRIBUTING.md#-commit-message-format
|
||||
* Each commit should cover only one thing;
|
||||
* Begin the commit message with a single short (less than 50 characters) line summarizing the change, followed by a blank line and then a more thorough description;
|
||||
* When fixing a bug, commit to the devel branch as well as the maintenance branch of the latest release version (named maintenance/x.y). When a ticket is associated to the bug, add to the description a line saying *Fixes #1234*.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
Installation and Configuration Guide
|
||||
====================================
|
||||
:toc: left
|
||||
:icons: font
|
||||
|
||||
////
|
||||
|
||||
@@ -16,13 +18,13 @@ About this Guide
|
||||
|
||||
This guide will walk you through the installation and configuration of
|
||||
the SOGo solution. It also covers the installation and configuration of
|
||||
SOGo ActiveSync support – the solution used to synchronize mobile
|
||||
SOGo ActiveSync support - the solution used to synchronize mobile
|
||||
devices with SOGo.
|
||||
|
||||
The instructions are based on version {release_version} of SOGo.
|
||||
|
||||
The latest version of this guide is available
|
||||
at http://www.sogo.nu/downloads/documentation.html.
|
||||
at http://sogo.nu/downloads/documentation.html.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
@@ -48,13 +50,12 @@ the SOGo Connector and the SOGo Integrator
|
||||
device, or Outlook 2013
|
||||
|
||||
SOGo is developed by a community of developers located mainly in North
|
||||
America and Europe. More information can be found
|
||||
at http://www.sogo.nu/
|
||||
America and Europe. More information can be found at http://sogo.nu/
|
||||
|
||||
Architecture and Compatibility
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
image::images/architecture.png[System Architecture]
|
||||
image::images/architecture.png[System Architecture, 400, 964]
|
||||
|
||||
Standard protocols such as CalDAV, CardDAV, GroupDAV, HTTP, IMAP and
|
||||
SMTP are used to communicate with the SOGo platform or its
|
||||
@@ -170,20 +171,20 @@ supported by SOGo:
|
||||
* Red Hat Enterprise Linux (RHEL) Server 5, 6 and 7
|
||||
* Community ENTerprise Operating System (CentOS) 5, 6 and 7
|
||||
* Debian GNU/Linux 6.0 (Squeeze) to 8.0 (Jessie)
|
||||
* Ubuntu 10.04 (Lucid) to 14.04 (Trusty)
|
||||
* Ubuntu 12.04 (Precise) to 14.04 (Trusty)
|
||||
|
||||
Make sure the required components are started automatically at boot time
|
||||
and that they are running before proceeding with the SOGo configuration.
|
||||
Also make sure that you can install additional packages from your
|
||||
standard distribution. For example, if you are using Red Hat Enterprise
|
||||
Linux 5, you have to be subscribed to the Red Hat Network before
|
||||
Linux 7, you have to be subscribed to the Red Hat Network before
|
||||
continuing with the SOGo software installation.
|
||||
|
||||
This document covers the installation of SOGo under RHEL 6.
|
||||
NOTE: This document covers the installation of SOGo under RHEL 7.
|
||||
|
||||
For installation instructions on Debian and Ubuntu, please refer
|
||||
directly to the SOGo website at http://www.sogo.nu/.
|
||||
Under the downloads section, you will find links for installation steps
|
||||
directly to the SOGo website at http://sogo.nu/.
|
||||
Under the _Support_ section, you will find links for installation steps
|
||||
for Debian and Ubuntu.
|
||||
|
||||
Note that once the SOGo packages are installed under Debian and Ubuntu,
|
||||
@@ -194,7 +195,7 @@ Installation
|
||||
|
||||
This section will guide you through the installation of SOGo together
|
||||
with its dependencies. The steps described here apply to an RPM-based
|
||||
installation for a Red Hat or CentOS 6 distribution. Most of these steps
|
||||
installation for a Red Hat or CentOS 7 distribution. Most of these steps
|
||||
should apply to all supported operating systems.
|
||||
|
||||
Software Downloads
|
||||
@@ -207,7 +208,7 @@ content:
|
||||
----
|
||||
[SOGo]
|
||||
name=Inverse SOGo Repository
|
||||
baseurl=http://inverse.ca/downloads/SOGo/RHEL6/$basearch
|
||||
baseurl=http://inverse.ca/rhel-v3/7/$basearch
|
||||
gpgcheck=0
|
||||
----
|
||||
|
||||
@@ -294,7 +295,7 @@ associated to a domain is limited to access only the users data from the
|
||||
same domain. Consequently, the configuration parameters of SOGo are
|
||||
defined on three levels:
|
||||
|
||||
image::images/preferences-hierarchy.png[Preferences Hierarchy]
|
||||
image::images/preferences-hierarchy.png[Preferences Hierarchy, 400, 400]
|
||||
|
||||
Each level inherits the preferences of the parent level. Therefore,
|
||||
domain preferences define the defaults values of the user preferences,
|
||||
@@ -497,8 +498,8 @@ In our example, we set the default domain to `acme.com`.
|
||||
meeting participants. Possible values are:
|
||||
|
||||
[options="compact"]
|
||||
* `YES` – to send notifications
|
||||
* `NO` – to not send notifications
|
||||
* `YES` - to send notifications
|
||||
* `NO` - to not send notifications
|
||||
|
||||
Defaults to `NO` when unset.
|
||||
|
||||
@@ -597,8 +598,8 @@ for SOGo. Possible values are:
|
||||
someone changes his/her own calendar. Possible values are:
|
||||
|
||||
[options="compact"]
|
||||
- `YES` – to send notifications
|
||||
- `NO` – to not send notifications
|
||||
- `YES` - to send notifications
|
||||
- `NO` - to not send notifications
|
||||
|
||||
Defaults to `NO` when unset. User can overwrite this from the calendar
|
||||
properties window.
|
||||
@@ -609,8 +610,8 @@ modification is being done to his/her own calendar by someone else.
|
||||
Possible values are:
|
||||
|
||||
[options="compact"]
|
||||
* `YES` – to send notifications
|
||||
* `NO` – to not send notifications
|
||||
* `YES` - to send notifications
|
||||
* `NO` - to not send notifications
|
||||
|
||||
Defaults to `NO` when unset. User can overwrite this from the calendar
|
||||
properties window.
|
||||
@@ -633,8 +634,8 @@ requiring not authentication) their calendars and address books.
|
||||
Possible values are:
|
||||
|
||||
[options="compact"]
|
||||
* `YES` – to allow them
|
||||
* `NO` – to prevent them from doing so
|
||||
* `YES` - to allow them
|
||||
* `NO` - to prevent them from doing so
|
||||
|
||||
Defaults to `NO` when unset.
|
||||
|
||||
@@ -645,8 +646,8 @@ SOGo.
|
||||
Possible values are:
|
||||
|
||||
[options="compact"]
|
||||
* `YES` – to allow them
|
||||
* `NO` – to prevent them from doing so
|
||||
* `YES` - to allow them
|
||||
* `NO` - to prevent them from doing so
|
||||
|
||||
Defaults to `NO` when unset.
|
||||
|
||||
@@ -676,7 +677,7 @@ Defaults to `NO` when unset.
|
||||
string (attendee completion, address book search, etc.) prior triggering
|
||||
the server-side search operation.
|
||||
|
||||
Defaults to `2` when unset – which means a search operation will be
|
||||
Defaults to `2` when unset - which means a search operation will be
|
||||
triggered on the 3rd typed character.
|
||||
|
||||
|S |SOGoMaximumFailedLoginCount
|
||||
@@ -866,7 +867,7 @@ source can contain the following values:
|
||||
|The type of this user source, set to ldap` for an LDAP source.
|
||||
|
||||
|id
|
||||
|The identification name of the LDAP repository. This must be unique –
|
||||
|The identification name of the LDAP repository. This must be unique -
|
||||
even when using multiple domains.
|
||||
|
||||
|CNFieldName
|
||||
@@ -932,8 +933,8 @@ be marked as busy the first time it is booked.
|
||||
EOQualifier. The following operators are supported:
|
||||
|
||||
[options="compact"]
|
||||
* `<>` – inequality operator
|
||||
* `=` – equality operator
|
||||
* `<>` - inequality operator
|
||||
* `=` - equality operator
|
||||
|
||||
Multiple qualifiers can be joined by using `OR` and `AND`, they can also
|
||||
be grouped together by using parenthesis. Attribute values should be
|
||||
@@ -1033,6 +1034,10 @@ not work for entries in this source and thus, freebusy lookups.
|
||||
|If set as an address book, the human identification name of the LDAP
|
||||
repository
|
||||
|
||||
|listRequiresDot (optional)
|
||||
|If set to `YES`, listing of this LDAP source is only possible when performing a search (respecting the SOGoSearchMinimumWordLength parameter) or when explicitely typing a single dot.
|
||||
Defaults to `YES` when unset.
|
||||
|
||||
|ModulesConstraints (optional)
|
||||
|Limits the access of any module through a constraint based on an LDAP
|
||||
attribute; must be a dictionary with keys `Mail`, and/or `Calendar`,
|
||||
@@ -1105,6 +1110,7 @@ LDAP Attributes Indexing
|
||||
To ensure proper performance of the SOGo application, the following LDAP
|
||||
attributes must be fully indexed:
|
||||
|
||||
[options="compact"]
|
||||
* givenName
|
||||
* cn
|
||||
* mail
|
||||
@@ -1125,7 +1131,7 @@ fax number, one could map it to the _facsimiletelephonenumber_ attribute
|
||||
like this:
|
||||
|
||||
----
|
||||
mapping = \{
|
||||
mapping = {
|
||||
facsimiletelephonenumber = ("fax", "facsimiletelephonenumber");
|
||||
};
|
||||
----
|
||||
@@ -1300,7 +1306,7 @@ If you want to test the IdP-initiated logout using SimpleSAMLphp, you can do so
|
||||
the following URL:
|
||||
|
||||
----
|
||||
https://idp.example.org/simplesaml/saml2/idp/SingleLogoutService.php?ReturnTo=www.sogo.nu
|
||||
https://idp.example.org/simplesaml/saml2/idp/SingleLogoutService.php?ReturnTo=sogo.nu
|
||||
----
|
||||
|
||||
In order to relay authentication information to your IMAP server and if
|
||||
@@ -1325,9 +1331,9 @@ support enabled.
|
||||
Create the database user and schema using the following commands:
|
||||
|
||||
----
|
||||
su – postgres
|
||||
createuser --no-superuser --no-createdb –-no-createrole \
|
||||
–-encrypted --pwprompt sogo
|
||||
su - postgres
|
||||
createuser --no-superuser --no-createdb --no-createrole \
|
||||
--encrypted --pwprompt sogo
|
||||
(specify “sogo” as password)
|
||||
createdb -O sogo sogo
|
||||
----
|
||||
@@ -1421,7 +1427,7 @@ source can contain the following values:
|
||||
|The type of this user source, set to `sql` for a SQL source.
|
||||
|
||||
|id
|
||||
|The identification name of the SQL repository. This must be unique –
|
||||
|The identification name of the SQL repository. This must be unique -
|
||||
even when using multiple domains.
|
||||
|
||||
|viewURL
|
||||
@@ -1429,14 +1435,14 @@ even when using multiple domains.
|
||||
present. Required columns are:
|
||||
|
||||
[options="compact"]
|
||||
* `c_uid`: will be used for authentication – it's a username or
|
||||
* `c_uid`: will be used for authentication - it's a username or
|
||||
username@domain.tld
|
||||
* `c_name`: will be used to uniquely identify entries – which can be
|
||||
* `c_name`: will be used to uniquely identify entries - which can be
|
||||
identical to `c_uid`
|
||||
* `c_password`: password of the user, plain text, crypt, md5 or sha
|
||||
encoded
|
||||
* `c_cn`: the user's common name
|
||||
* mail : the user's email address
|
||||
* `mail`: the user's email address
|
||||
|
||||
Other columns can exist and will actually be mapped automatically if
|
||||
they have the same name as popular LDAP attributes (such as `givenName`,
|
||||
@@ -1537,14 +1543,14 @@ SOGoUserSources =
|
||||
|
||||
Certain database columns must be present in the view/table, such as:
|
||||
|
||||
* `c_uid` – will be used for authentication – it's the username
|
||||
* `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
|
||||
* `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
|
||||
* `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
|
||||
* `c_cn` - the user's common name - such as "John Doe"
|
||||
* `mail` - the user's mail address
|
||||
|
||||
Note that groups are currently not supported for SQL-based
|
||||
authentication sources.
|
||||
@@ -1564,8 +1570,8 @@ The following table describes the related parameters.
|
||||
are:
|
||||
|
||||
[options="compact"]
|
||||
* `sendmail` – to use the sendmail binary
|
||||
* `smtp` – to use the SMTP protocol
|
||||
* `sendmail` - to use the sendmail binary
|
||||
* `smtp` - to use the SMTP protocol
|
||||
|
||||
|D |SOGoSMTPServer
|
||||
|The DNS name or IP address of the SMTP server used when
|
||||
@@ -1628,6 +1634,16 @@ Defaults to `Trash` when unset.
|
||||
Use a `/` as a hierarchy separator if referring to an IMAP subfolder.
|
||||
For example: `INBOX/Trash`.
|
||||
|
||||
|U |SOGoJunkFolderName
|
||||
|Parameter used to set the IMAP folder name used to store junk
|
||||
messages.
|
||||
|
||||
Defaults to `Junk` when unset.
|
||||
|
||||
Use a `/` as a hierarchy separator if referring to an IMAP subfolder.
|
||||
For example: `INBOX/Junk`. Also see the SOGoMailJunkSettings for
|
||||
more options regarding junk/not-junk actions.
|
||||
|
||||
|D |SOGoIMAPCASServiceName
|
||||
|Parameter used to set the CAS service name (URL) of the imap service.
|
||||
This is useful if SOGo is connecting to the IMAP service through a
|
||||
@@ -1793,7 +1809,7 @@ interface)
|
||||
|Parameter used to specify the default order of the columns from the
|
||||
SOGo webmail interface. The parameter is an array, for example:
|
||||
|
||||
SOGoMailListViewColumnsOrder = (Flagged, Attachment, Priority, From, Subject, Unread, Date, Size);
|
||||
`SOGoMailListViewColumnsOrder = (Flagged, Attachment, Priority, From, Subject, Unread, Date, Size);`
|
||||
|
||||
|D |SOGoVacationEnabled
|
||||
|Parameter used to activate the edition from the preferences window of a
|
||||
@@ -2082,7 +2098,21 @@ Defaults to `%{FolderName} (%{UserName} <%{Email}>)` when unset.
|
||||
the template named `UIxAdditionalPreferences.wox`. This template should
|
||||
be put under `~sogo/GNUstep/Library/SOGo/Templates/PreferencesUI/`.
|
||||
|
||||
Defaults to `NO` when unset.
|
||||
|D |SOGoMailJunkSettings
|
||||
|Parameter used to enable email junk settings. The value is a dictionary
|
||||
and the follow keys are supported: `vendor` (which must be set to "generic"
|
||||
for now), `junkEmailAddress` which sets the email address to whom SOGo will
|
||||
send junk mails to, `notJunkEmailAddress` which sets the email address to
|
||||
whome SOGo will send non-junk mails to and `limit`, which is an integer value
|
||||
and sets the maximum number of mails that will be attached to a
|
||||
junk/not junk report sent by SOGo. Example: `SOGoMailJunkSettings = {
|
||||
vendor = "generic"; junkEmailAddress = "spam@foo.com";
|
||||
notJunkEmailAddress = "ham@foo.com"; limit = 10;
|
||||
};`
|
||||
|
||||
|D |SOGoMailKeepDraftsAfterSend
|
||||
|Parameter used to keep mails in the drafts folder once they have been
|
||||
sent by SOGo. Defaults to `NO` when unset.
|
||||
|=======================================================================
|
||||
|
||||
SOGo Configuration Summary
|
||||
@@ -2111,6 +2141,7 @@ like this:
|
||||
SOGoDraftsFolderName = Drafts;
|
||||
SOGoSentFolderName = Sent;
|
||||
SOGoTrashFolderName = Trash;
|
||||
SOGoJunkFolderName = Junk;
|
||||
SOGoMailingMechanism = smtp;
|
||||
SOGoSMTPServer = 127.0.0.1;
|
||||
SOGoUserSources = (
|
||||
@@ -2251,7 +2282,7 @@ RequestHeader set "x-webobjects-server-url" "http://yourhostname"
|
||||
You may consider enabling SSL on top of this current installation to
|
||||
secure access to your SOGo installation.
|
||||
|
||||
See http://httpd.apache.org/docs/2.2/ssl/ for details.
|
||||
See http://httpd.apache.org/docs/2.4/ssl/ for details.
|
||||
|
||||
You might also have to adjust the configuration if you have SELinux
|
||||
enabled.
|
||||
@@ -2266,13 +2297,13 @@ Starting Services
|
||||
Once SOGo if fully installed and configured, start the services using
|
||||
the following command:
|
||||
|
||||
service sogod start
|
||||
systemctl start sogod.service
|
||||
|
||||
You may verify using thechkconfigcommand that the SOGo service is
|
||||
automatically started at boot time. Restart the Apache service since
|
||||
You may verify using the `systemctl is-enabled sogod` command that the SOGo
|
||||
service is automatically started at boot time. Restart the Apache service since
|
||||
modules and configuration files were added:
|
||||
|
||||
service httpd restart
|
||||
systemctl restart httpd.service
|
||||
|
||||
Finally, you should also make sure that the `memcached` service is
|
||||
started and that it is also automatically started at boot time.
|
||||
@@ -2616,7 +2647,7 @@ your site. However, be aware that in order to use the SOGo Integrator
|
||||
plug in, you will need to repackage it with specific modifications.
|
||||
Please refer to the documentation published online:
|
||||
|
||||
http://www.sogo.nu/downloads/documentation.html
|
||||
http://sogo.nu/downloads/documentation.html
|
||||
|
||||
If you only use the SOGo Connector plug in, you can still easily access
|
||||
your data.
|
||||
|
||||
@@ -88,7 +88,7 @@ fixes from the current development version of Mozilla Lightning. For
|
||||
Thunderbird 2, it is based on release version 0.9 of Lightning. For
|
||||
Thunderbird 3.1, it is based on 1.0b2.
|
||||
|
||||
In order to download and install Mozilla Lightning – Inverse Edition for
|
||||
In order to download and install Mozilla Lightning - Inverse Edition for
|
||||
Thunderbird 2 or 3.1, please visit:
|
||||
|
||||
http://www.sogo.nu/downloads/frontends.html
|
||||
@@ -136,7 +136,7 @@ extensions, please visit:
|
||||
http://www.sogo.nu/downloads/frontends.html
|
||||
|
||||
Prior to installing the SOGo Integrator extension, you should read the
|
||||
following chapter – _SOGo Integrator Customization_.
|
||||
following chapter - _SOGo Integrator Customization_.
|
||||
|
||||
SOGo Integrator Customization
|
||||
-----------------------------
|
||||
@@ -195,7 +195,7 @@ if the SOGo server is accessible from the following URL:
|
||||
|
||||
Note that if you changed the `x-webobjects-server-url` configuration
|
||||
setting from your HTTP server configuration file for SOGo, the
|
||||
value *must* match the one you specify in `isi:updateURL` – even the
|
||||
value *must* match the one you specify in `isi:updateURL` - even the
|
||||
port number.
|
||||
|
||||
Moreover, you *must* change the value of the
|
||||
@@ -216,7 +216,7 @@ In this section, you will learn how to install and configure the SOGo
|
||||
Update Server.
|
||||
|
||||
The SOGo Update Server can be used to automatically install or uninstall
|
||||
Mozilla Thunderbird extensions, push user settings and more – all from a
|
||||
Mozilla Thunderbird extensions, push user settings and more - all from a
|
||||
central place managed by system administrators.
|
||||
|
||||
Installation
|
||||
|
||||
@@ -142,7 +142,7 @@ to authenticate users. A SOGoUserSources entry to achieve this wold look
|
||||
like this:
|
||||
|
||||
----
|
||||
su – sogo
|
||||
su - sogo
|
||||
defaults write sogod SOGoUserSources '(
|
||||
{
|
||||
CNFieldName = displayName;
|
||||
@@ -233,6 +233,7 @@ Installation
|
||||
This section will guide you through the installation of the native
|
||||
Microsoft Outlook compatibility layer SOGo offers.
|
||||
|
||||
////
|
||||
Red Hat Enterprise Linux v6 x86_64
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -244,7 +245,7 @@ http://www.sogo.nu/english/downloads/backend.html.
|
||||
In order to satisfy certain dependencies, you should also add the EPEL
|
||||
source corresponding to your distribution and architecture. More
|
||||
information on this is available here:
|
||||
http://fedoraproject.org/wiki/EPEL – or more specifically,
|
||||
http://fedoraproject.org/wiki/EPEL - or more specifically,
|
||||
http://fedoraproject.org/wiki/EPEL/FAQ#How_can_I_install_the_packages_from_the_EPEL_software_repository.3F.
|
||||
|
||||
Once ready, install the OpenChange packages on top of an existing SOGo
|
||||
@@ -316,7 +317,7 @@ from this guide.
|
||||
On Ubuntu 12.04, the Samba init scripts need to be modified to
|
||||
disable the upstart check. For more details, refer to:
|
||||
https://wiki.samba.org/index.php/Samba4/InitScript
|
||||
|
||||
////
|
||||
|
||||
Debian 8 (Jessie) and Ubuntu 14.04 (Trusty Tahr)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -387,7 +388,7 @@ Run the following commands as root:
|
||||
|
||||
----
|
||||
samba-tool domain provision --realm=example.com \
|
||||
--domain=OPENCHANGE \
|
||||
--domain=EXAMPLE \
|
||||
--adminpass='%1OpenChange' \
|
||||
--server-role='domain controller'
|
||||
|
||||
@@ -395,7 +396,7 @@ samba-tool user setexpiry administrator --noexpiry
|
||||
----
|
||||
|
||||
You might consider changing the realm and domain used, to suit your
|
||||
enviroment.
|
||||
environment.
|
||||
|
||||
You might also have to
|
||||
remove `/etc/samba/smb.conf` prior running this command.
|
||||
@@ -441,7 +442,7 @@ Your Samba 4 configuration file should look like this:
|
||||
OpenChange Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
OpenChange 2.2 stores its metadata in MySQL so you need to have it installed.
|
||||
Since v2.2, OpenChange stores its metadata in MySQL so you need to have it installed.
|
||||
|
||||
First, create the OpenChange MySQL user:
|
||||
|
||||
@@ -512,9 +513,11 @@ mapistore:indexing_backend = mysql://openchange-user:openchange$123@localhost/op
|
||||
mapiproxy:openchangedb = mysql://openchange-user:openchange$123@localhost/openchange
|
||||
----
|
||||
|
||||
////
|
||||
On RHEL, make sure SELinux is disabled:
|
||||
|
||||
setenforce 0
|
||||
////
|
||||
|
||||
Next, you can start Samba using the usual command:
|
||||
|
||||
@@ -545,9 +548,11 @@ This service runs as a WSGI application under apache (mod_wsgi).
|
||||
While HTTPS is not required to access this service, it is strongly
|
||||
recommended.
|
||||
|
||||
////
|
||||
On RHEL-based distributions, the apache configuration required by these
|
||||
services can be found in `/etc/httpd/conf.d/ocsmanager.conf` and
|
||||
`/etc/httpd/conf.d/rpcproxy.conf`.
|
||||
////
|
||||
|
||||
For Debian-based distributions, these files can be found
|
||||
in `/etc/apache2/conf.d/` or `/etc/apache2/conf-available`.
|
||||
@@ -563,8 +568,10 @@ The OCS Manager and RPC Proxy configuration module can be enabled using:
|
||||
a2enconf ocsmanager
|
||||
a2enconf rpcproxy
|
||||
|
||||
////
|
||||
On RHEL-based distributions, make sure the `LoadModule` directive is
|
||||
uncommented in `/etc/httpd/conf.d/wsgi.conf`.
|
||||
////
|
||||
|
||||
The _reqtimeout_ apache module is known to cause problems when using the
|
||||
default configuration shipped with Debian-based systems. On such
|
||||
@@ -580,10 +587,12 @@ To avoid this problem, use a much higher timeout or disable the module:
|
||||
a2dismod reqtimeout
|
||||
|
||||
You should now restart the Apache service and make sure it will start on
|
||||
boot. On RHEL-based distributions, do:
|
||||
boot.
|
||||
////
|
||||
On RHEL-based distributions, do:
|
||||
|
||||
chkconfig httpd on && /etc/init.d/httpd restart
|
||||
|
||||
////
|
||||
On Debian-based distributions, do:
|
||||
|
||||
update-rc.d apache2 defaults && /etc/init.d/apache2 restart
|
||||
@@ -711,7 +720,7 @@ Adding Users
|
||||
------------
|
||||
|
||||
Users that wish to connect natively to SOGo must be provisioned in
|
||||
Samba 4 and in OpenChange – even if they already exist in your current
|
||||
Samba 4 and in OpenChange - even if they already exist in your current
|
||||
LDAP or Microsoft Active Directory server.
|
||||
|
||||
To add a user, execute the following commands:
|
||||
@@ -809,11 +818,10 @@ can be ignored for now. This feature is currently not supported.
|
||||
remove any data associated with the user from the SOGo server and
|
||||
recreate a Microsoft Outlook profile.
|
||||
To remove any data associated to a user, use
|
||||
the `openchange_user_cleanup` script distributed with SOGo. The script
|
||||
can be found in `/usr/share/doc/sogo/` (`/usr/share/sogo-VERSION/` on
|
||||
RHEL).
|
||||
the `openchange_user_cleanup` script distributed with OpenChange. The script
|
||||
can be found in `/usr/share/openchange/`.
|
||||
To reset a user, run the script as root:
|
||||
`python openchange_user_cleanup username`. See the usage output for additional options.
|
||||
`openchange_user_cleanup username`. See the usage output for additional options.
|
||||
* The "Out of Office Assistant" will not currently work. This feature
|
||||
has not been implemented.
|
||||
* Creating folders below INBOX (when not normally permitted by the IMAP
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- TODO have the build system take care of this -->
|
||||
<releaseinfo>Version 2.3.1 - July 2015</releaseinfo>
|
||||
<subtitle>for version 2.3.1</subtitle>
|
||||
<date>2015-07-23</date>
|
||||
<releaseinfo>Version 3.0.2 - March 2016</releaseinfo>
|
||||
<subtitle>for version 3.0.2</subtitle>
|
||||
<date>2016-03-04</date>
|
||||
|
||||
<legalnotice>
|
||||
<para>Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".</para>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Authors:
|
||||
- Inverse inc. <info@inverse.ca>
|
||||
|
||||
Copyright (C) 2008-2014 Inverse inc.
|
||||
Copyright (C) 2008-2016 Inverse inc.
|
||||
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
|
||||
|
||||
////
|
||||
@@ -17,7 +17,7 @@ Additional Information
|
||||
For more information, please consult the online FAQs (Frequently Asked
|
||||
Questions) :
|
||||
|
||||
http://www.sogo.nu/english/support/faq.html
|
||||
http://sogo.nu/support/faq.html
|
||||
|
||||
You can also read the mailing archives or post your questions to it. For
|
||||
details, see :
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
Authors:
|
||||
- Inverse inc. <info@inverse.ca>
|
||||
|
||||
Copyright (C) 2008-2015 Inverse inc.
|
||||
Copyright (C) 2008-2016 Inverse inc.
|
||||
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
|
||||
|
||||
////
|
||||
|
||||
// TODO have the build system take care of this
|
||||
|
||||
:release_version: 2.3.1
|
||||
:release_version: 3.0.2
|
||||
|
||||
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:
|
||||
@@ -19,7 +19,6 @@
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@interface MainUIProduct : NSObject
|
||||
{
|
||||
@@ -27,7 +26,6 @@
|
||||
|
||||
@end
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@implementation MainUIProduct
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSException.h>
|
||||
|
||||
@interface NSException (SOGoExtensions)
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#include <execinfo.h>
|
||||
|
||||
#import "NSException+Stacktrace.h"
|
||||
|
||||
|
||||
+1
-7
@@ -18,18 +18,12 @@
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGObjWeb/SoObject+SoDAV.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import <DOM/DOMDocument.h>
|
||||
#import <DOM/DOMNode.h>
|
||||
#import <DOM/DOMProtocols.h>
|
||||
#import <SaxObjC/XMLNamespaces.h>
|
||||
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
@@ -267,7 +261,7 @@
|
||||
NSObject <DOMNodeList> *list;
|
||||
NSObject <DOMNode> *valueNode;
|
||||
NSArray *elements;
|
||||
NSString *property, *match;
|
||||
NSString *property=nil, *match=nil;
|
||||
|
||||
list = [searchElement getElementsByTagName: @"prop"];
|
||||
if ([list length])
|
||||
|
||||
@@ -20,14 +20,6 @@
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSDebug.h>
|
||||
#import <Foundation/NSData.h>
|
||||
#import <Foundation/NSDate.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSProcessInfo.h>
|
||||
#import <Foundation/NSRunLoop.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
|
||||
#import <GDLAccess/EOAdaptorChannel.h>
|
||||
#import <GDLContentStore/GCSChannelManager.h>
|
||||
@@ -58,7 +50,6 @@
|
||||
#import <SOGo/SOGoPublicBaseFolder.h>
|
||||
#import <SOGo/SOGoProductLoader.h>
|
||||
#import <SOGo/SOGoProxyAuthenticator.h>
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoWebAuthenticator.h>
|
||||
|
||||
@@ -21,10 +21,8 @@
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGObjWeb/SoApplication.h>
|
||||
|
||||
@@ -1,12 +1,237 @@
|
||||
2.3.x (2015-MM-DD)
|
||||
3.0.2 (2016-03-04)
|
||||
------------------
|
||||
|
||||
New features
|
||||
- [web] show all/only this calendar
|
||||
- [web] convert a message to an appointment or a task (#1722)
|
||||
- [web] customizable base font size for HTML messages
|
||||
- [web you can now limit the file upload size using the WOMaxUploadSize
|
||||
configuration parameter (integer value in kilobytes) (#3510, #3135)
|
||||
|
||||
Enhancements
|
||||
- [web] added Junk handling feature from v2
|
||||
- [web] updated Material Icons font to version 2.1.3
|
||||
- [web] don't offer forward/vacation options in filters if not enabled
|
||||
- [web] mail filters are now sortable
|
||||
- [web] now supports RFC6154 and NoInferiors IMAP flag
|
||||
- [web] improved confirm dialogs for deletions
|
||||
- [web] allow resources to prevent invitations (#3410)
|
||||
- [web] warn when double-booking attendees and offer force save option
|
||||
- [web] list search now displays a warning regarding the minlength constraint
|
||||
- [web] loading an LDAP-based addressbook is now instantaneous when listRequiresDot is disabled (#438, #3464)
|
||||
- [web] improve display of messages with many recipients
|
||||
- [web] colorize categories chips in event and task viewers
|
||||
- [web] initial stylesheet for printing
|
||||
- [web] updated lodash to version 4.6.1
|
||||
- [i18n] updated French and Finnish translations
|
||||
- [eas] now support EAS MIME truncation
|
||||
|
||||
Bug fixes
|
||||
- [web] handle birthday dates before 1970
|
||||
- [web] safe-guarding against bogus value coming from the quick tables
|
||||
- [web] apply search filters when automatically reloading current mailbox (#3507)
|
||||
- [web] fixed virtual repeater when moving up in messages list
|
||||
- [web] really delete mailboxes being deleted from the Trash folder (#595, #1189, #641)
|
||||
- [web] fixed address autocompletion of mail editor affecting cards list of active addressbook
|
||||
- [web] fixed batched delete of components (#3516)
|
||||
- [web] fixed mail draft autosave in preferences (#3519)
|
||||
- [web] fixed password change (#3496)
|
||||
- [web] fixed saving of notification email for calendar changes (#3522)
|
||||
- [web] fixed ACL editor for authenticated users in Mail module
|
||||
- [web] fixed fab button position in Calendar module (#3462)
|
||||
- [web] fixed default priority of sent messages (#3542)
|
||||
- [web] removed double-quotes from Chinese (Taiwan) translations that were breaking templates
|
||||
- [web] fixed unseen count retrieval of nested IMAP folders
|
||||
- [web] properly extract the mail column values from an SQL contacts source (#3544)
|
||||
- [web] fixed incorrect date formatting when timezone was after UTC+0 (#3481, #3494)
|
||||
- [web] replaced checkboxes in menu by a custom checkmark (#3557)
|
||||
- [web] fixed attachments display when forwarding a message (#3560)
|
||||
- [web] activate new calendar subscriptions by default
|
||||
- [web] keep specified task status when not completed (#3499)
|
||||
- [eas] allow EAS attachments get on 2nd-level mailboxes (#3505)
|
||||
- [eas] fix EAS bday shift (#3518)
|
||||
|
||||
3.0.1 (2016-02-05)
|
||||
------------------
|
||||
|
||||
Enhancements
|
||||
- [web] improved scrolling behavior when deleting a single message (#3489)
|
||||
- [web] added "Move To" option for selected messages (#3477)
|
||||
- [web] updated CKEditor to version 4.5.7
|
||||
- [web] updated Angular Material to 1.0.5
|
||||
- [web/eas] add shared/public namespaces in the list or returned folders
|
||||
|
||||
Bug fixes
|
||||
- [web] safeguard against mailboxes with no quota (#3468)
|
||||
- [web] fixed blank calendar view when selecting "Descending Order" in the sort menu
|
||||
- [web] show active user's default email address instead of system email address (#3473)
|
||||
- [web] fixed display of HTML tags when viewing a message raw source (#3490)
|
||||
- [web] fixed IMIP accept/decline when there is only one MIME part
|
||||
- [web] improved handling of IMAP connection problem in Web interface
|
||||
- [web] fixed frequency parsing of recurrence rule when saving new appointment (#3472)
|
||||
- [web] added support for %p in date formatting (#3480)
|
||||
- [web] make sure an email is defined before trying to use it (#3488)
|
||||
- [web] handle broken messages that have no date (#3498)
|
||||
- [web] fixed virtual-repeater display in Webmail when a search is performed (#3500)
|
||||
- [web] fixed drag'n'drop of all-day events in multicolumn view
|
||||
- [eas] correctly encode filename of attachments over EAS (#3491)
|
||||
|
||||
3.0.0 (2016-01-27)
|
||||
------------------
|
||||
|
||||
New features
|
||||
- complete rewrite of the JavaScript frontend using Angular and AngularMaterial
|
||||
- responsive design and accessible options focused on mobile devices
|
||||
- horizontal 3-pane view for a better experience on large desktop screens
|
||||
- new color palette and better contrast ratio as recommended by the W3C
|
||||
- improved accessibility to persons with disabilities by enabling common ARIA attributes
|
||||
- use of Mozilla's Fira Sans typeface
|
||||
- and many more!
|
||||
|
||||
2.3.7 (2016-01-25)
|
||||
------------------
|
||||
|
||||
New features
|
||||
- new junk/not junk capability with generic SMTP integration
|
||||
|
||||
Enhancements
|
||||
- newly created folders using EAS are always sync'ed by default (#3454)
|
||||
- added Croatian (hr_HR) translation - thanks to Jens Riecken
|
||||
|
||||
Bug fixes
|
||||
- now always generate invitation updates when using EAS
|
||||
- rewrote the string sanitization to be 32-bit Unicode safe
|
||||
- do not try to decode non-wbxml responses for debug output (#3444)
|
||||
|
||||
2.3.6 (2016-01-18)
|
||||
------------------
|
||||
|
||||
New features
|
||||
- now able to sync only default mail folders when using EAS
|
||||
|
||||
Enhancements
|
||||
- Unit testing for RTFHandler
|
||||
- JUnit output for sogo-tests
|
||||
|
||||
Bug fixes
|
||||
- don't unescape twice mail folder names (#3423)
|
||||
- don't consider mobile Outlook EAS clients as DAV ones (#3431)
|
||||
- we now follow 301 redirects when fetching ICS calendars
|
||||
- when deleting an event using EAS, properly invoke the auto-scheduling code
|
||||
- do not include failure attachments (really long filenames)
|
||||
- fix encoding of email subjects with non-ASCII characters
|
||||
- fix appointment notification mails using SOGoEnableDomainBasedUID configuration
|
||||
- fix shifts in event times on Outlook
|
||||
|
||||
2.3.5 (2016-01-05)
|
||||
------------------
|
||||
|
||||
Enhancements
|
||||
- return an error to openchange if mail message delivery fails
|
||||
- return the requested elements on complex requests from Outlook when downloading changes
|
||||
- user sources can be loaded dynamically
|
||||
- unify user sources API
|
||||
- updated Russian translation (#3383)
|
||||
|
||||
Bug fixes
|
||||
- properly compute the last week number for the year (#1010)
|
||||
- share calendar, tasks and contacts folders in Outlook 2013 with editor permissions
|
||||
- priorize filename in Content-Disposition against name in Content-Type to get the filename of an attachment in mail
|
||||
- request all contacts when there is no filter in Contacts menu in Webmail
|
||||
- personal contacts working properly on Outlook
|
||||
- fixes on RTF parsing used by event/contact description and mail as RTF to read non-ASCII characters:
|
||||
better parsing of font table, when using a font, switch to its character set, correct parsing of
|
||||
escaped characters and Unicode character command word support for unicode characters greater than 32767
|
||||
- no crash resolving recipients after reconnecting LDAP connection
|
||||
- avoid creation of phantom contacts in SOGo from distribution list synced from Outlook.
|
||||
- accepted & updated event names are now shown correctly in Outlook
|
||||
- provide safe guards in mail and calendar to avoid exceptions while syncing
|
||||
|
||||
2.3.4 (2015-12-15)
|
||||
------------------
|
||||
|
||||
New features
|
||||
- initial support for EAS calendar exceptions
|
||||
|
||||
Enhancements
|
||||
- limit the maximum width of toolbar buttons (#3381)
|
||||
- updated CKEditor to version 4.5.6
|
||||
|
||||
Bug fixes
|
||||
- JavaScript exception when printing events from calendars with no assigned color (#3203)
|
||||
- EAS fix for wrong charset being used (#3392)
|
||||
- EAS fix on qp-encoded subjects (#3390)
|
||||
- correctly handle all-day event exceptions when the master event changes
|
||||
- prevent characters in calendar component UID causing issues during import process
|
||||
- avoid duplicating attendees when accepting event using a different identity over CalDAV
|
||||
|
||||
2.3.3a (2015-11-18)
|
||||
-------------------
|
||||
|
||||
Bug fixes
|
||||
- expanded mail folders list is not saved (#3386)
|
||||
- cleanup translations
|
||||
|
||||
2.3.3 (2015-11-11)
|
||||
------------------
|
||||
|
||||
New features
|
||||
- initial S/MIME support for EAS (#3327)
|
||||
- now possible to choose which folders to sync over EAS
|
||||
|
||||
Enhancements
|
||||
- we no longer always entirely rewrite messages for Outlook 2013 when using EAS
|
||||
- support for ghosted elements on contacts over EAS
|
||||
- added Macedonian (mk_MK) translation - thanks to Miroslav Jovanovic
|
||||
- added Portuguese (pt) translation - thanks to Eduardo Crispim
|
||||
|
||||
Bug fixes
|
||||
- numerous EAS fixes when connections are dropped before the EAS client receives the response (#3058, #2849)
|
||||
- correctly handle the References header over EAS (#3365)
|
||||
- make sure English is always used when generating Date headers using EAS (#3356)
|
||||
- don't escape quoted strings during versit generation
|
||||
- we now return all cards when we receive an empty addressbook-query REPORT
|
||||
- avoid crash when replying to a mail with no recipients (#3359)
|
||||
- inline images sent from SOGo webmail are not displayed in Mozilla Thunderbird (#3271)
|
||||
- prevent postal address showing on single line over EAS (#2614)
|
||||
- display missing events when printing working hours only
|
||||
- fix corner case making server crash when syncing hard deleted messages when clear offline items was set up (Zentyal)
|
||||
- avoid infinite Outlook client loops trying to set read flag when it is already set (Zentyal)
|
||||
- avoid crashing when calendar metadata is missing in the cache (Zentyal)
|
||||
- fix recurrence pattern event corner case created by Mozilla Thunderbird which made server crash (Zentyal)
|
||||
- fix corner case that removes attachments on sending messages from Outlook (Zentyal)
|
||||
- freebusy on web interface works again in multidomain environments (Zentyal)
|
||||
- fix double creation of folders in Outlook when the folder name starts with a digit (Zentyal)
|
||||
- avoid crashing Outlook after setting a custom view in a calendar folder (Zentyal)
|
||||
- handle emails having an attachment as their content
|
||||
- fixed JavaScript syntax error in attendees editor
|
||||
- fixed wrong comparison of meta vs. META tag in HTML mails
|
||||
- fixed popup menu position when moved to the left (#3381)
|
||||
- fixed dialog position when at the bottom of the window (#2646, #3378)
|
||||
|
||||
2.3.2 (2015-09-16)
|
||||
------------------
|
||||
|
||||
Enhancements
|
||||
- improved EAS speed and memory usage, avoiding many IMAP LIST commands (#3294)
|
||||
- improved EAS speed during initial syncing of large mailboxes (#3293)
|
||||
- updated CKEditor to version 4.5.3
|
||||
|
||||
Bug fixes
|
||||
- fixed display of whitelisted attendees in Preferences window on Firefox (#3285)
|
||||
- Non-latin subfolder names are displayed correctly on Outlook (Zentyal)
|
||||
- Fixed several sync issues on environments with multiple users (Zentyal)
|
||||
- Folders from other users will no longer appear on your Outlook (Zentyal)
|
||||
- Use right auth in multidomain environments in contacts and calendar from Outlook (Zentyal)
|
||||
- non-latin subfolder names are displayed correctly on Outlook (Zentyal)
|
||||
- fixed several sync issues on environments with multiple users (Zentyal)
|
||||
- folders from other users will no longer appear on your Outlook (Zentyal)
|
||||
- use right auth in multidomain environments in contacts and calendar from Outlook (Zentyal)
|
||||
- session fix when SOGoEnableDomainBasedUID is enabled but logins are domain-less
|
||||
- less sync issues when setting read flag (Zentyal)
|
||||
- attachments with non-latin filenames sent by Outlook are now received (Zentyal)
|
||||
- support attachments from more mail clients (Zentyal)
|
||||
- avoid conflicting message on saving a draft mail (Zentyal)
|
||||
- less conflicting messages in Outlook while moving messages between folders (Zentyal)
|
||||
- start/end shifting by 1 hour due to timezone change on last Sunday of October 2015 (#3344)
|
||||
- fixed localization of calendar categories with empty profile (#3295)
|
||||
- fixed options availability in contextual menu of Contacts module (#3342)
|
||||
|
||||
2.3.1 (2015-07-23)
|
||||
------------------
|
||||
@@ -19,6 +244,7 @@ Enhancements
|
||||
- added create-folder subcommand to sogo-tool to create contact and calendar folders
|
||||
- group mail addresses can be used as recipient in Outlook
|
||||
- added 'ActiveSync' module constraints
|
||||
- updated CKEditor to version 4.5.1
|
||||
- added Slovenian translation - thanks to Jens Riecken
|
||||
- added Chinese (Taiwan) translation
|
||||
|
||||
|
||||
@@ -145,7 +145,8 @@ $(DBMSGREADER_TOOL)_LIB_DIRS += \
|
||||
-L../SoObjects/SOGo/SOGo.framework/sogo -lSOGo \
|
||||
-L../SOPE/GDLContentStore/obj/ -lGDLContentStore \
|
||||
-L../SOPE/NGCards/obj/ -lNGCards \
|
||||
-lNGObjWeb
|
||||
-lNGObjWeb \
|
||||
$(LIBMAPI_LIBS)
|
||||
|
||||
TEST_TOOL_NAME += $(PLREADER_TOOL) $(DBMSGREADER_TOOL)
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#define MAPISTORECALENDARWRAPPER_H
|
||||
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
#import <Appointments/iCalEntityObject+SOGo.h>
|
||||
|
||||
#import "MAPIStoreObjectProxy.h"
|
||||
@@ -42,7 +43,7 @@
|
||||
iCalCalendar *calendar;
|
||||
iCalEvent *firstEvent;
|
||||
iCalEvent *event;
|
||||
NSTimeZone *timeZone;
|
||||
iCalTimeZone *timeZone;
|
||||
SOGoUser *user;
|
||||
NSString *senderEmail;
|
||||
NSData *globalObjectId;
|
||||
@@ -57,12 +58,10 @@
|
||||
+ (id) wrapperWithICalEvent: (iCalEvent *) newEvent
|
||||
andUser: (SOGoUser *) newUser
|
||||
andSenderEmail: (NSString *) newSenderEmail
|
||||
inTimeZone: (NSTimeZone *) newTimeZone
|
||||
withConnectionInfo: (struct mapistore_connection_info *) newConnInfo;
|
||||
- (id) initWithICalEvent: (iCalEvent *) newEvent
|
||||
andUser: (SOGoUser *) newUser
|
||||
andSenderEmail: (NSString *) newSenderEmail
|
||||
inTimeZone: (NSTimeZone *) newTimeZone
|
||||
withConnectionInfo: (struct mapistore_connection_info *) newConnInfo;
|
||||
|
||||
/* getters */
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
#import <NGCards/iCalEventChanges.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
#import <NGCards/iCalTimeZonePeriod.h>
|
||||
#import <NGCards/NSString+NGCards.h>
|
||||
#import <SOGo/SOGoDomainDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
|
||||
@@ -80,7 +82,6 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
+ (id) wrapperWithICalEvent: (iCalEvent *) newEvent
|
||||
andUser: (SOGoUser *) newUser
|
||||
andSenderEmail: (NSString *) newSenderEmail
|
||||
inTimeZone: (NSTimeZone *) newTimeZone
|
||||
withConnectionInfo: (struct mapistore_connection_info *) newConnInfo
|
||||
{
|
||||
MAPIStoreAppointmentWrapper *wrapper;
|
||||
@@ -88,7 +89,6 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
wrapper = [[self alloc] initWithICalEvent: newEvent
|
||||
andUser: newUser
|
||||
andSenderEmail: newSenderEmail
|
||||
inTimeZone: newTimeZone
|
||||
withConnectionInfo: newConnInfo];
|
||||
[wrapper autorelease];
|
||||
|
||||
@@ -182,10 +182,10 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
- (id) initWithICalEvent: (iCalEvent *) newEvent
|
||||
andUser: (SOGoUser *) newUser
|
||||
andSenderEmail: (NSString *) newSenderEmail
|
||||
inTimeZone: (NSTimeZone *) newTimeZone
|
||||
withConnectionInfo: (struct mapistore_connection_info *) newConnInfo
|
||||
{
|
||||
NSArray *events;
|
||||
iCalTimeZone *tz;
|
||||
|
||||
if ((self = [self init]))
|
||||
{
|
||||
@@ -194,9 +194,20 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
event = newEvent;
|
||||
events = [calendar events];
|
||||
firstEvent = [events objectAtIndex: 0];
|
||||
ASSIGN (timeZone, newTimeZone);
|
||||
ASSIGN (user, newUser);
|
||||
ASSIGN (senderEmail, newSenderEmail);
|
||||
/* If newEvent comes from the client, we set its time zone in
|
||||
updateFromMAPIProperties. If it is not present, we use the
|
||||
time zone of the user */
|
||||
tz = (iCalTimeZone *) [calendar firstChildWithTag: @"vtimezone"];
|
||||
if (!tz)
|
||||
{
|
||||
tz = [iCalTimeZone timeZoneForName: [[[user userDefaults] timeZone] name]];
|
||||
if (!tz)
|
||||
[self logWithFormat: @"no time zone could be set"];
|
||||
}
|
||||
ASSIGN (timeZone, tz);
|
||||
|
||||
[self _setupITIPContext];
|
||||
}
|
||||
|
||||
@@ -266,7 +277,7 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
{
|
||||
username = [contactInfos objectForKey: @"sAMAccountName"];
|
||||
recipient->username = [username asUnicodeInMemCtx: msgData];
|
||||
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username);
|
||||
entryId = MAPIStoreInternalEntryId (connInfo, username);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -367,7 +378,7 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
{
|
||||
username = [contactInfos objectForKey: @"sAMAccountName"];
|
||||
recipient->username = [username asUnicodeInMemCtx: msgData];
|
||||
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username);
|
||||
entryId = MAPIStoreInternalEntryId (connInfo, username);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -721,22 +732,15 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
NSCalendarDate *dateValue;
|
||||
NSInteger offset;
|
||||
|
||||
// if ([event isRecurrent])
|
||||
// dateValue = [event firstRecurrenceStartDate];
|
||||
// else
|
||||
dateValue = [event startDate];
|
||||
if ([event isAllDay])
|
||||
{
|
||||
offset = -[timeZone secondsFromGMTForDate: dateValue];
|
||||
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: offset];
|
||||
}
|
||||
[dateValue setTimeZone: utcTZ];
|
||||
dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
|
||||
*data = [dateValue asFileTimeInMemCtx: memCtx];
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -749,22 +753,14 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
exceptions, where it is the normal start date for the day of the
|
||||
exception. */
|
||||
NSCalendarDate *dateValue;
|
||||
NSInteger offset;
|
||||
|
||||
dateValue = [event recurrenceId];
|
||||
if (!dateValue)
|
||||
dateValue = [event startDate];
|
||||
[dateValue setTimeZone: timeZone];
|
||||
if ([event isAllDay])
|
||||
{
|
||||
offset = -[timeZone secondsFromGMTForDate: dateValue];
|
||||
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: offset];
|
||||
}
|
||||
[dateValue setTimeZone: utcTZ];
|
||||
dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
|
||||
*data = [dateValue asFileTimeInMemCtx: memCtx];
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -772,19 +768,12 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
NSCalendarDate *dateValue;
|
||||
NSInteger offset;
|
||||
|
||||
dateValue = [firstEvent startDate];
|
||||
if ([firstEvent isAllDay])
|
||||
{
|
||||
offset = -[timeZone secondsFromGMTForDate: dateValue];
|
||||
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: offset];
|
||||
}
|
||||
[dateValue setTimeZone: utcTZ];
|
||||
dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
|
||||
*data = [dateValue asFileTimeInMemCtx: memCtx];
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -804,8 +793,8 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
month: [start monthOfYear]
|
||||
day: [start dayOfMonth]
|
||||
hour: 0 minute: 0 second: 0
|
||||
timeZone: timeZone];
|
||||
[dateValue setTimeZone: utcTZ];
|
||||
timeZone: utcTZ];
|
||||
dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
|
||||
*data = [dateValue asFileTimeInMemCtx: memCtx];
|
||||
rc = MAPISTORE_SUCCESS;
|
||||
}
|
||||
@@ -829,7 +818,7 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
dateValue = [event startDate];
|
||||
offset = [event durationAsTimeInterval];
|
||||
if ([event isAllDay])
|
||||
offset -= [timeZone secondsFromGMTForDate: dateValue];
|
||||
offset -= [[timeZone periodForDate: dateValue] secondsOffsetFromGMT];
|
||||
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: offset];
|
||||
@@ -847,15 +836,14 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
dateValue = [event recurrenceId];
|
||||
if (!dateValue)
|
||||
dateValue = [event startDate];
|
||||
[dateValue setTimeZone: timeZone];
|
||||
offset = [firstEvent durationAsTimeInterval];
|
||||
if ([firstEvent isAllDay])
|
||||
offset -= [timeZone secondsFromGMTForDate: dateValue];
|
||||
offset -= [[timeZone periodForDate: dateValue] secondsOffsetFromGMT];
|
||||
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: offset];
|
||||
*data = [dateValue asFileTimeInMemCtx: memCtx];
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -871,7 +859,7 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
dateValue = [firstEvent startDate];
|
||||
offset = [firstEvent durationAsTimeInterval];
|
||||
if ([event isAllDay])
|
||||
offset -= [timeZone secondsFromGMTForDate: dateValue];
|
||||
offset -= [[timeZone periodForDate: dateValue] secondsOffsetFromGMT];
|
||||
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: offset];
|
||||
@@ -885,23 +873,14 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
{
|
||||
enum mapistore_error rc;
|
||||
NSCalendarDate *dateValue;
|
||||
NSInteger offset;
|
||||
iCalRecurrenceRule *rrule;
|
||||
|
||||
if ([event isRecurrent])
|
||||
{
|
||||
rrule = [[event recurrenceRules] objectAtIndex: 0];
|
||||
dateValue = [rrule untilDate];
|
||||
if (dateValue)
|
||||
{
|
||||
if ([event isAllDay])
|
||||
offset = -[timeZone secondsFromGMTForDate: dateValue];
|
||||
else
|
||||
offset = 0;
|
||||
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: offset];
|
||||
}
|
||||
if (dateValue && [event isAllDay])
|
||||
dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
|
||||
else
|
||||
dateValue = [NSCalendarDate dateWithYear: 4500 month: 8 day: 31
|
||||
hour: 23 minute: 59 second: 00
|
||||
@@ -932,7 +911,7 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
if (contactInfos)
|
||||
{
|
||||
username = [contactInfos objectForKey: @"sAMAccountName"];
|
||||
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, username);
|
||||
entryId = MAPIStoreInternalEntryId (connInfo, username);
|
||||
}
|
||||
else
|
||||
entryId = MAPIStoreExternalEntryId (cn, email);
|
||||
@@ -1338,21 +1317,14 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
{
|
||||
enum mapistore_error rc;
|
||||
NSCalendarDate *dateValue;
|
||||
NSInteger offset;
|
||||
|
||||
dateValue = [event recurrenceId];
|
||||
if (dateValue)
|
||||
{
|
||||
rc = MAPISTORE_SUCCESS;
|
||||
|
||||
|
||||
if ([event isAllDay])
|
||||
{
|
||||
offset = -[timeZone secondsFromGMTForDate: dateValue];
|
||||
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: offset];
|
||||
}
|
||||
[dateValue setTimeZone: utcTZ];
|
||||
dateValue = [timeZone shiftedCalendarDateForDate: dateValue];
|
||||
*data = [dateValue asFileTimeInMemCtx: memCtx];
|
||||
}
|
||||
else
|
||||
@@ -1377,7 +1349,6 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
iCalEventChanges *changes;
|
||||
NSArray *changedProperties;
|
||||
NSCalendarDate *dateValue;
|
||||
NSInteger offset;
|
||||
|
||||
changes = [iCalEventChanges changesFromEvent: event toEvent: exceptionEvent];
|
||||
|
||||
@@ -1385,28 +1356,17 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
memset (extendedException, 0, sizeof (struct ExtendedException));
|
||||
extendedException->ChangeHighlight.Size = sizeof (uint32_t);
|
||||
|
||||
dateValue = [exceptionEvent startDate];
|
||||
offset = [timeZone secondsFromGMTForDate: dateValue];
|
||||
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: offset];
|
||||
dateValue = [timeZone computedDateForDate: [exceptionEvent startDate]];
|
||||
exceptionInfo->StartDateTime = [dateValue asMinutesSince1601];
|
||||
extendedException->ChangeHighlight.Value = BIT_CH_START;
|
||||
extendedException->StartDateTime = exceptionInfo->StartDateTime;
|
||||
|
||||
dateValue = [exceptionEvent endDate];
|
||||
offset = [timeZone secondsFromGMTForDate: dateValue];
|
||||
dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: offset];
|
||||
dateValue = [timeZone computedDateForDate: [exceptionEvent endDate]];
|
||||
exceptionInfo->EndDateTime = [dateValue asMinutesSince1601];
|
||||
extendedException->ChangeHighlight.Value |= BIT_CH_END;
|
||||
extendedException->EndDateTime = exceptionInfo->EndDateTime;
|
||||
|
||||
dateValue = [[exceptionEvent recurrenceId]
|
||||
dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: offset];
|
||||
dateValue = [timeZone computedDateForDate: [exceptionEvent recurrenceId]];
|
||||
exceptionInfo->OriginalStartDate = [dateValue asMinutesSince1601];
|
||||
extendedException->OriginalStartDate = exceptionInfo->OriginalStartDate;
|
||||
|
||||
@@ -1464,7 +1424,6 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
arp = talloc_zero (NULL, struct AppointmentRecurrencePattern);
|
||||
[rule fillRecurrencePattern: &arp->RecurrencePattern
|
||||
withEvent: event
|
||||
inTimeZone: timeZone
|
||||
inMemCtx: arp];
|
||||
arp->ReaderVersion2 = 0x00003006;
|
||||
arp->WriterVersion2 = 0x00003008; /* 0x3008 for compatibility with
|
||||
@@ -1475,7 +1434,7 @@ static NSCharacterSet *hexCharacterSet = nil;
|
||||
fields are relative to midnight of those days ([MS-OXOCAL] 2.2.1.44.5),
|
||||
so no time zone adjustment is needed */
|
||||
if (![event isAllDay])
|
||||
[firstStartDate setTimeZone: timeZone];
|
||||
firstStartDate = [timeZone computedDateForDate: firstStartDate];
|
||||
startMinutes = ([firstStartDate hourOfDay] * 60
|
||||
+ [firstStartDate minuteOfHour]);
|
||||
arp->StartTimeOffset = startMinutes;
|
||||
@@ -1701,15 +1660,16 @@ ReservedBlockEE2Size: 00 00 00 00
|
||||
fromDate: (NSCalendarDate *) instanceDate;
|
||||
{
|
||||
uint16_t year;
|
||||
NSCalendarDate *dateValue;
|
||||
|
||||
if (instanceDate)
|
||||
{
|
||||
[instanceDate setTimeZone: timeZone];
|
||||
year = [instanceDate yearOfCommonEra];
|
||||
dateValue = [timeZone computedDateForDate: instanceDate];
|
||||
year = [dateValue yearOfCommonEra];
|
||||
newGlobalId->YH = year >> 8;
|
||||
newGlobalId->YL = year & 0xff;
|
||||
newGlobalId->Month = [instanceDate monthOfYear];
|
||||
newGlobalId->D = [instanceDate dayOfMonth];
|
||||
newGlobalId->Month = [dateValue monthOfYear];
|
||||
newGlobalId->D = [dateValue dayOfMonth];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1974,7 +1934,6 @@ ReservedBlockEE2Size: 00 00 00 00
|
||||
if (alarm)
|
||||
{
|
||||
alarmDate = [alarm nextAlarmDate];
|
||||
[alarmDate setTimeZone: utcTZ];
|
||||
*data = [alarmDate asFileTimeInMemCtx: memCtx];
|
||||
}
|
||||
else
|
||||
@@ -2036,8 +1995,7 @@ ReservedBlockEE2Size: 00 00 00 00
|
||||
enum mapistore_error rc;
|
||||
NSString *tzid;
|
||||
|
||||
tzid = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"]
|
||||
value: 0 ofAttribute: @"tzid"];
|
||||
tzid = [timeZone tzId];
|
||||
if ([tzid length] > 0)
|
||||
{
|
||||
*data = [tzid asUnicodeInMemCtx: memCtx];
|
||||
@@ -2053,16 +2011,9 @@ ReservedBlockEE2Size: 00 00 00 00
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
enum mapistore_error rc;
|
||||
iCalTimeZone *icalTZ;
|
||||
|
||||
icalTZ = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] timeZone];
|
||||
if (icalTZ)
|
||||
{
|
||||
*data = [icalTZ asTimeZoneStructInMemCtx: memCtx];
|
||||
rc = MAPISTORE_SUCCESS;
|
||||
}
|
||||
else
|
||||
rc = MAPISTORE_ERR_NOT_FOUND;
|
||||
*data = [timeZone asTimeZoneStructInMemCtx: memCtx];
|
||||
rc = MAPISTORE_SUCCESS;
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -2071,24 +2022,16 @@ ReservedBlockEE2Size: 00 00 00 00
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
enum mapistore_error rc;
|
||||
iCalTimeZone *icalTZ;
|
||||
|
||||
/* [MS-OXOCAL] 3.1.5.5.1: This property is used in floating (all-day) events,
|
||||
specified in floating time, to convert the start date from UTC to the user's
|
||||
time zone */
|
||||
if ([event isAllDay])
|
||||
icalTZ = [iCalTimeZone timeZoneForName: [timeZone timeZoneName]];
|
||||
else if ([event isRecurrent])
|
||||
icalTZ = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] timeZone];
|
||||
else
|
||||
icalTZ = nil;
|
||||
|
||||
if (icalTZ)
|
||||
if ([event isAllDay] | [event isRecurrent])
|
||||
{
|
||||
/* [MS-OXOCAL] 2.2.1.42: This property can only have the E flag set in the
|
||||
TimeZoneDefinition struct */
|
||||
*data = [icalTZ asZoneTimeDefinitionWithFlags: TZRULE_FLAG_EFFECTIVE_TZREG
|
||||
inMemCtx: memCtx];
|
||||
*data = [timeZone asZoneTimeDefinitionWithFlags: TZRULE_FLAG_EFFECTIVE_TZREG
|
||||
inMemCtx: memCtx];
|
||||
rc = MAPISTORE_SUCCESS;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
forURL: (NSURL *) server
|
||||
forceRenew: (BOOL) renew;
|
||||
|
||||
- (NSString *) passwordInContext: (WOContext *) context;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
#endif /* MAPISTOREAUTHENTICATOR_H */
|
||||
@@ -72,4 +72,8 @@
|
||||
return imapPassword;
|
||||
}
|
||||
|
||||
- (NSString *) passwordInContext: (WOContext *) context
|
||||
{
|
||||
return password;
|
||||
}
|
||||
@end
|
||||
@@ -58,7 +58,6 @@
|
||||
wrapperWithICalEvent: [newContainer event]
|
||||
andUser: [userContext sogoUser]
|
||||
andSenderEmail: nil
|
||||
inTimeZone: [userContext timeZone]
|
||||
withConnectionInfo: [context connectionInfo]];
|
||||
[self addProxy: appointmentWrapper];
|
||||
}
|
||||
|
||||
@@ -77,6 +77,17 @@
|
||||
|
||||
- (NSArray *) rolesForExchangeRights: (uint32_t) rights
|
||||
{
|
||||
/* Limitations
|
||||
|
||||
Following rights are not supported by SOGo specifically:
|
||||
|
||||
- DeleteOwned : Delete only own objects
|
||||
- EditOwned : Edit only own objects
|
||||
- CreateSubfolders: No calendar subfolders
|
||||
- FolderOwner: No sharing folder ownership?
|
||||
- FolderContact: No support to store this information
|
||||
- FolderVisible: It is inferred by other rights when extracting
|
||||
*/
|
||||
NSMutableArray *roles;
|
||||
|
||||
roles = [NSMutableArray arrayWithCapacity: 6];
|
||||
@@ -117,11 +128,11 @@
|
||||
if ([roles containsObject: SOGoRole_ObjectCreator])
|
||||
rights |= RightsCreateItems;
|
||||
if ([roles containsObject: SOGoRole_ObjectEraser])
|
||||
rights |= RightsDeleteAll;
|
||||
rights |= RightsDeleteAll | RightsDeleteOwn;
|
||||
if ([roles containsObject: SOGoCalendarRole_PublicModifier]
|
||||
&& [roles containsObject: SOGoCalendarRole_PrivateModifier]
|
||||
&& [roles containsObject: SOGoCalendarRole_ConfidentialModifier])
|
||||
rights |= RightsReadItems | RightsEditAll;
|
||||
rights |= RightsReadItems | RightsEditAll | RightsEditOwn | RightsFreeBusySimple | RightsFreeBusyDetailed;
|
||||
else if ([roles containsObject: SOGoCalendarRole_PublicViewer]
|
||||
&& [roles containsObject: SOGoCalendarRole_PrivateViewer]
|
||||
&& [roles containsObject: SOGoCalendarRole_ConfidentialViewer])
|
||||
@@ -135,7 +146,7 @@
|
||||
if ([roles containsObject: SOGoCalendarRole_ConfidentialDAndTViewer])
|
||||
rights |= RightsFreeBusyDetailed;
|
||||
|
||||
if (rights != 0)
|
||||
if ((rights & RightsReadItems) != 0 || (rights & RightsCreateItems) != 0 || (rights & RightsDeleteAll) != 0)
|
||||
rights |= RoleNone; /* actually "folder visible" */
|
||||
|
||||
// [self logWithFormat: @"rights for roles (%@) = %.8x", roles, rights];
|
||||
|
||||
@@ -197,7 +197,6 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
|
||||
= [MAPIStoreAppointmentWrapper wrapperWithICalEvent: masterEvent
|
||||
andUser: [userContext sogoUser]
|
||||
andSenderEmail: nil
|
||||
inTimeZone: [userContext timeZone]
|
||||
withConnectionInfo: [context connectionInfo]];
|
||||
[self addProxy: appointmentWrapper];
|
||||
}
|
||||
@@ -671,7 +670,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
|
||||
return newAttachment;
|
||||
}
|
||||
|
||||
- (int) setReadFlag: (uint8_t) flag
|
||||
- (enum mapistore_error) setReadFlag: (uint8_t) flag
|
||||
{
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -96,9 +96,9 @@
|
||||
if ([roles containsObject: SOGoRole_ObjectCreator])
|
||||
rights |= RightsCreateItems;
|
||||
if ([roles containsObject: SOGoRole_ObjectEraser])
|
||||
rights |= RightsDeleteAll;
|
||||
rights |= RightsDeleteAll | RightsDeleteOwn;
|
||||
if ([roles containsObject: SOGoRole_ObjectEditor])
|
||||
rights |= RightsEditAll;
|
||||
rights |= RightsEditAll | RightsEditOwn;
|
||||
if ([roles containsObject: SOGoRole_ObjectViewer])
|
||||
rights |= RightsReadItems;
|
||||
if (rights != 0)
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -102,7 +102,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
{
|
||||
value = get_SPropValue_SRow (aRow, PidTagDisplayName_string8);
|
||||
if (value)
|
||||
folderName = [NSString stringWithUTF8String: value->value.lpszA];
|
||||
folderName = [NSString stringWithUTF8String: (const char *) value->value.lpszA];
|
||||
else
|
||||
folderName = nil;
|
||||
}
|
||||
@@ -321,9 +321,9 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
|
||||
if ([roles containsObject: MAPIStoreRightDeleteOwn])
|
||||
rights |= RightsDeleteOwn;
|
||||
if ([roles containsObject: MAPIStoreRightEditAll])
|
||||
rights |= RightsEditAll;
|
||||
rights |= RightsEditAll | RightsEditOwn;
|
||||
if ([roles containsObject: MAPIStoreRightDeleteAll])
|
||||
rights |= RightsDeleteAll;
|
||||
rights |= RightsDeleteAll | RightsDeleteOwn;
|
||||
if ([roles containsObject: MAPIStoreRightCreateSubfolders])
|
||||
rights |= RightsCreateSubfolders;
|
||||
if ([roles containsObject: MAPIStoreRightFolderOwner])
|
||||
|
||||
+228
-15
@@ -22,6 +22,7 @@
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSData.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
@@ -34,6 +35,7 @@
|
||||
#import "MAPIStoreDBFolder.h"
|
||||
#import "MAPIStoreDBMessage.h"
|
||||
#import "MAPIStoreTypes.h"
|
||||
#import "NSData+MAPIStore.h"
|
||||
#import "NSObject+MAPIStore.h"
|
||||
#import "NSString+MAPIStore.h"
|
||||
|
||||
@@ -43,16 +45,28 @@
|
||||
|
||||
@implementation MAPIStoreDBMessage
|
||||
|
||||
+ (int) getAvailableProperties: (struct SPropTagArray **) propertiesP
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
+ (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
struct SPropTagArray *properties;
|
||||
NSUInteger count;
|
||||
enum MAPITAGS faiProperties[] = { 0x68350102, 0x683c0102, 0x683e0102,
|
||||
0x683f0102, 0x68410003, 0x68420102,
|
||||
0x68450102, 0x68460003,
|
||||
// PR_VD_NAME_W, PR_VD_FLAGS, PR_VD_VERSION, PR_VIEW_CLSID
|
||||
0x7006001F, 0x70030003, 0x70070003, 0x68330048 };
|
||||
|
||||
enum MAPITAGS faiProperties[] = {
|
||||
0x68330048, /* PR_VIEW_CLSID */
|
||||
0x68350102, /* PR_VIEW_STATE */
|
||||
0x683c0102,
|
||||
0x683d0040,
|
||||
0x683e0102,
|
||||
0x683f0102, /* PR_VIEW_VIEWTYPE_KEY */
|
||||
0x68410003,
|
||||
0x68420102,
|
||||
0x68450102,
|
||||
0x68460003,
|
||||
0x7006001F, /* PR_VD_NAME_W */
|
||||
0x70030003, /* PR_VD_FLAGS */
|
||||
0x70070003 /* PR_VD_VERSION */
|
||||
};
|
||||
|
||||
size_t faiSize = sizeof(faiProperties) / sizeof(enum MAPITAGS);
|
||||
|
||||
properties = talloc_zero (memCtx, struct SPropTagArray);
|
||||
@@ -74,6 +88,13 @@
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
- (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
return [[self class] getAvailableProperties: propertiesP
|
||||
inMemCtx: memCtx];
|
||||
}
|
||||
|
||||
- (id) initWithSOGoObject: (id) newSOGoObject
|
||||
inContainer: (MAPIStoreObject *) newContainer
|
||||
{
|
||||
@@ -88,22 +109,173 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *) description
|
||||
{
|
||||
id key, value;
|
||||
NSEnumerator *propEnumerator;
|
||||
NSMutableString *description;
|
||||
|
||||
description = [NSMutableString stringWithFormat: @"%@ %@. Properties: {", NSStringFromClass ([self class]),
|
||||
[self url]];
|
||||
|
||||
propEnumerator = [properties keyEnumerator];
|
||||
while ((key = [propEnumerator nextObject]))
|
||||
{
|
||||
uint32_t proptag = 0;
|
||||
if ([key isKindOfClass: [NSString class]] && [(NSString *)key intValue] > 0)
|
||||
proptag = [(NSString *)key intValue];
|
||||
else if ([key isKindOfClass: [NSNumber class]])
|
||||
proptag = [key unsignedLongValue];
|
||||
|
||||
if (proptag > 0)
|
||||
{
|
||||
const char *propTagName = get_proptag_name ([key unsignedLongValue]);
|
||||
NSString *propName;
|
||||
|
||||
if (propTagName)
|
||||
propName = [NSString stringWithCString: propTagName
|
||||
encoding: NSUTF8StringEncoding];
|
||||
else
|
||||
propName = [NSString stringWithFormat: @"0x%.4x", [key unsignedLongValue]];
|
||||
|
||||
[description appendFormat: @"'%@': ", propName];
|
||||
}
|
||||
else
|
||||
[description appendFormat: @"'%@': ", key];
|
||||
|
||||
value = [properties objectForKey: key];
|
||||
[description appendFormat: @"%@ (%@), ", value, NSStringFromClass ([value class])];
|
||||
}
|
||||
|
||||
[description appendString: @"}\n"];
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
- (uint64_t) objectVersion
|
||||
{
|
||||
NSNumber *versionNbr;
|
||||
/* Return the global counter from CN structure.
|
||||
See [MS-OXCFXICS] Section 2.2.2.1 */
|
||||
NSNumber *versionNbr, *cn;
|
||||
uint64_t objectVersion;
|
||||
|
||||
[(SOGoMAPIDBMessage *) sogoObject reloadIfNeeded];
|
||||
versionNbr = [properties objectForKey: @"version"];
|
||||
versionNbr = [properties objectForKey: @"version_number"];
|
||||
if (versionNbr)
|
||||
objectVersion = (([versionNbr unsignedLongLongValue] >> 16)
|
||||
& 0x0000ffffffffffffLL);
|
||||
objectVersion = exchange_globcnt ([versionNbr unsignedLongLongValue]);
|
||||
else
|
||||
objectVersion = ULLONG_MAX;
|
||||
{
|
||||
/* Old version which stored the CN structure not useful for searching */
|
||||
cn = [properties objectForKey: @"version"];
|
||||
if (cn)
|
||||
objectVersion = (([cn unsignedLongLongValue] >> 16)
|
||||
& 0x0000ffffffffffffLL);
|
||||
else
|
||||
objectVersion = ULLONG_MAX;
|
||||
}
|
||||
|
||||
return objectVersion;
|
||||
}
|
||||
|
||||
- (void) _updatePredecessorChangeList
|
||||
{
|
||||
BOOL updated;
|
||||
enum mapistore_error rc;
|
||||
NSData *currentChangeList, *changeKey;
|
||||
NSMutableArray *changeKeys;
|
||||
NSMutableData *newChangeList;
|
||||
NSUInteger count, len;
|
||||
struct SizedXid *changes;
|
||||
struct SPropValue property;
|
||||
struct SRow aRow;
|
||||
struct XID *currentChangeKey;
|
||||
TALLOC_CTX *localMemCtx;
|
||||
uint32_t nChanges;
|
||||
|
||||
localMemCtx = talloc_new (NULL);
|
||||
if (!localMemCtx)
|
||||
{
|
||||
[self errorWithFormat: @"No more memory"];
|
||||
return;
|
||||
}
|
||||
|
||||
changeKey = [self getReplicaKeyFromGlobCnt: [self objectVersion]];
|
||||
|
||||
currentChangeList = [properties objectForKey: MAPIPropertyKey (PidTagPredecessorChangeList)];
|
||||
if (!currentChangeList)
|
||||
{
|
||||
/* Create a new PredecessorChangeList */
|
||||
len = [changeKey length];
|
||||
newChangeList = [NSMutableData dataWithCapacity: len + 1];
|
||||
[newChangeList appendUInt8: len];
|
||||
[newChangeList appendData: changeKey];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Update current predecessor change list with new change key */
|
||||
changes = [currentChangeList asSizedXidArrayInMemCtx: localMemCtx
|
||||
with: &nChanges];
|
||||
|
||||
updated = NO;
|
||||
currentChangeKey = [changeKey asXIDInMemCtx: localMemCtx];
|
||||
for (count = 0; count < nChanges && !updated; count++)
|
||||
{
|
||||
if (GUID_equal(&changes[count].XID.NameSpaceGuid, ¤tChangeKey->NameSpaceGuid))
|
||||
{
|
||||
NSData *globCnt, *oldGlobCnt;
|
||||
oldGlobCnt = [NSData dataWithBytes: changes[count].XID.LocalId.data length: changes[count].XID.LocalId.length];
|
||||
globCnt = [NSData dataWithBytes: currentChangeKey->LocalId.data length: currentChangeKey->LocalId.length];
|
||||
if ([globCnt compare: oldGlobCnt] == NSOrderedDescending)
|
||||
{
|
||||
if ([globCnt length] != [oldGlobCnt length])
|
||||
{
|
||||
[self errorWithFormat: @"Cannot compare globcnt with different length: %@ and %@", globCnt, oldGlobCnt];
|
||||
abort();
|
||||
}
|
||||
memcpy (changes[count].XID.LocalId.data, currentChangeKey->LocalId.data, currentChangeKey->LocalId.length);
|
||||
updated = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Serialise it */
|
||||
changeKeys = [NSMutableArray array];
|
||||
|
||||
if (!updated)
|
||||
[changeKeys addObject: changeKey];
|
||||
|
||||
for (count = 0; count < nChanges; count++)
|
||||
{
|
||||
changeKey = [NSData dataWithXID: &changes[count].XID];
|
||||
[changeKeys addObject: changeKey];
|
||||
}
|
||||
|
||||
[changeKeys sortUsingFunction: MAPIChangeKeyGUIDCompare context: localMemCtx];
|
||||
|
||||
newChangeList = [NSMutableData data];
|
||||
len = [changeKeys count];
|
||||
for (count = 0; count < len; count++)
|
||||
{
|
||||
changeKey = [changeKeys objectAtIndex: count];
|
||||
[newChangeList appendUInt8: [changeKey length]];
|
||||
[newChangeList appendData: changeKey];
|
||||
}
|
||||
}
|
||||
|
||||
if ([newChangeList length] > 0)
|
||||
{
|
||||
property.ulPropTag = PidTagPredecessorChangeList;
|
||||
property.value.bin = *[newChangeList asBinaryInMemCtx: localMemCtx];
|
||||
aRow.cValues = 1;
|
||||
aRow.lpProps = &property;
|
||||
rc = [self addPropertiesFromRow: &aRow];
|
||||
if (rc != MAPISTORE_SUCCESS)
|
||||
[self errorWithFormat: @"Impossible to add a new predecessor change list: %d", rc];
|
||||
}
|
||||
|
||||
talloc_free (localMemCtx);
|
||||
}
|
||||
|
||||
//
|
||||
// FIXME: how this can happen?
|
||||
//
|
||||
@@ -163,10 +335,19 @@
|
||||
[properties setObject: attachmentParts forKey: @"attachments"];
|
||||
|
||||
newVersion = [[self context] getNewChangeNumber];
|
||||
[properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion]
|
||||
forKey: @"version"];
|
||||
newVersion = exchange_globcnt ((newVersion >> 16) & 0x0000ffffffffffffLL);
|
||||
|
||||
[self logWithFormat: @"%d props in dict", [properties count]];
|
||||
[properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion]
|
||||
forKey: @"version_number"];
|
||||
|
||||
/* Remove old version */
|
||||
[properties removeObjectForKey: @"version"];
|
||||
|
||||
/* Update PredecessorChangeList accordingly */
|
||||
[self _updatePredecessorChangeList];
|
||||
|
||||
// [self logWithFormat: @"Saving %@", [self description]];
|
||||
// [self logWithFormat: @"%d props in dict", [properties count]];
|
||||
|
||||
[sogoObject save];
|
||||
}
|
||||
@@ -209,4 +390,36 @@
|
||||
return [sogoObject lastModified];
|
||||
}
|
||||
|
||||
- (enum mapistore_error) setReadFlag: (uint8_t) flag
|
||||
{
|
||||
/* Modify PidTagMessageFlags from SetMessageReadFlag and
|
||||
SyncImportReadStateChanges ROPs */
|
||||
NSNumber *flags;
|
||||
uint32_t newFlag;
|
||||
|
||||
flags = [properties objectForKey: MAPIPropertyKey (PR_MESSAGE_FLAGS)];
|
||||
if (flags)
|
||||
{
|
||||
newFlag = [flags unsignedLongValue];
|
||||
if (flag & SUPPRESS_RECEIPT)
|
||||
newFlag |= MSGFLAG_READ;
|
||||
if (flag & CLEAR_RN_PENDING)
|
||||
newFlag &= ~MSGFLAG_RN_PENDING;
|
||||
if (flag & CLEAR_READ_FLAG)
|
||||
newFlag &= ~MSGFLAG_READ;
|
||||
if (flag & CLEAR_NRN_PENDING)
|
||||
newFlag &= ~MSGFLAG_NRN_PENDING;
|
||||
}
|
||||
else
|
||||
{
|
||||
newFlag = MSGFLAG_READ;
|
||||
if (flag & CLEAR_READ_FLAG)
|
||||
newFlag = 0x0;
|
||||
}
|
||||
[properties setObject: [NSNumber numberWithUnsignedLong: newFlag]
|
||||
forKey: MAPIPropertyKey (PR_MESSAGE_FLAGS)];
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -61,14 +61,15 @@ static Class MAPIStoreDBMessageK = Nil;
|
||||
|
||||
if ((uint32_t) res->ulPropTag == PidTagChangeNumber)
|
||||
{
|
||||
SEL operator;
|
||||
|
||||
value = NSObjectFromMAPISPropValue (&res->lpProp);
|
||||
cVersion = exchange_globcnt (([value unsignedLongLongValue] >> 16)
|
||||
& 0x0000ffffffffffffLL);
|
||||
version = [NSNumber numberWithUnsignedLongLong: cVersion];
|
||||
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
|
||||
[self logWithFormat: @" version: %.16lx", cVersion];
|
||||
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"version"
|
||||
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
|
||||
operator = [self operatorFromRestrictionOperator: res->relop];
|
||||
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"version_number"
|
||||
operatorSelector: operator
|
||||
value: version];
|
||||
[*qualifier autorelease];
|
||||
rc = MAPIRestrictionStateNeedsEval;
|
||||
|
||||
@@ -121,6 +121,7 @@
|
||||
fromFolder: (MAPIStoreFolder *) sourceFolder
|
||||
withMIDs: (uint64_t *) targetMids
|
||||
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
||||
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
|
||||
wantCopy: (uint8_t) want_copy
|
||||
inMemCtx: (TALLOC_CTX *) memCtx;
|
||||
|
||||
|
||||
@@ -642,6 +642,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
fromFolder: (MAPIStoreFolder *) sourceFolder
|
||||
withMID: (uint64_t) targetMid
|
||||
andChangeKey: (struct Binary_r *) targetChangeKey
|
||||
andPredecessorChangeList: (struct Binary_r *) targetPredecessorChangeList
|
||||
wantCopy: (uint8_t) wantCopy
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
@@ -669,15 +670,18 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
|
||||
[sourceMsg copyToMessage: destMsg inMemCtx: memCtx];
|
||||
|
||||
if (targetChangeKey)
|
||||
if (targetPredecessorChangeList)
|
||||
{
|
||||
property.ulPropTag = PidTagChangeKey;
|
||||
property.value.bin = *targetChangeKey;
|
||||
property.ulPropTag = PidTagPredecessorChangeList;
|
||||
property.value.bin = *targetPredecessorChangeList;
|
||||
aRow.cValues = 1;
|
||||
aRow.lpProps = &property;
|
||||
rc = [destMsg addPropertiesFromRow: &aRow];
|
||||
if (rc != MAPISTORE_SUCCESS)
|
||||
goto end;
|
||||
{
|
||||
[self errorWithFormat: @"Cannot add PredecessorChangeList on move"];
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
[destMsg save: memCtx];
|
||||
if (!wantCopy)
|
||||
@@ -696,6 +700,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
fromFolder: (MAPIStoreFolder *) sourceFolder
|
||||
withMIDs: (uint64_t *) targetMids
|
||||
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
||||
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
|
||||
wantCopy: (uint8_t) wantCopy
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
@@ -705,7 +710,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
NSString *oldMessageURL;
|
||||
MAPIStoreMapping *mapping;
|
||||
SOGoUser *ownerUser;
|
||||
struct Binary_r *targetChangeKey;
|
||||
struct Binary_r *targetChangeKey, *targetPredecessorChangeList;
|
||||
//TALLOC_CTX *memCtx;
|
||||
|
||||
//memCtx = talloc_zero (NULL, TALLOC_CTX);
|
||||
@@ -726,14 +731,21 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
if (oldMessageURL)
|
||||
{
|
||||
[oldMessageURLs addObject: oldMessageURL];
|
||||
if (targetChangeKeys)
|
||||
targetChangeKey = targetChangeKeys[count];
|
||||
if (targetChangeKeys && targetPredecessorChangeList)
|
||||
{
|
||||
targetChangeKey = targetChangeKeys[count];
|
||||
targetPredecessorChangeList = targetPredecessorChangeLists[count];
|
||||
}
|
||||
else
|
||||
targetChangeKey = NULL;
|
||||
{
|
||||
targetChangeKey = NULL;
|
||||
targetPredecessorChangeList = NULL;
|
||||
}
|
||||
rc = [self _moveCopyMessageWithMID: srcMids[count]
|
||||
fromFolder: sourceFolder
|
||||
withMID: targetMids[count]
|
||||
andChangeKey: targetChangeKey
|
||||
andPredecessorChangeList: targetPredecessorChangeList
|
||||
wantCopy: wantCopy
|
||||
inMemCtx: memCtx];
|
||||
}
|
||||
@@ -1537,7 +1549,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
struct Binary_r bin32;
|
||||
struct AddressBookEntryId *entryId;
|
||||
NSString *username;
|
||||
struct ldb_context *samCtx;
|
||||
|
||||
if (bin && bin->cb)
|
||||
{
|
||||
@@ -1547,8 +1558,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
|
||||
entryId = get_AddressBookEntryId (NULL, &bin32);
|
||||
if (entryId)
|
||||
{
|
||||
samCtx = [[self context] connectionInfo]->sam_ctx;
|
||||
username = MAPIStoreSamDBUserAttribute (samCtx, @"legacyExchangeDN",
|
||||
username = MAPIStoreSamDBUserAttribute ([[self context] connectionInfo],
|
||||
@"legacyExchangeDN",
|
||||
[NSString stringWithUTF8String: entryId->X500DN],
|
||||
@"sAMAccountName");
|
||||
}
|
||||
|
||||
@@ -41,8 +41,10 @@
|
||||
|
||||
/* synchronisation */
|
||||
- (BOOL) synchroniseCache;
|
||||
- (BOOL) synchroniseCacheFor: (NSString *) nameInContainer;
|
||||
- (void) updateVersionsForMessageWithKey: (NSString *) messageKey
|
||||
withChangeKey: (NSData *) newChangeKey;
|
||||
withChangeKey: (NSData *) oldChangeKey
|
||||
andPredecessorChangeList: (NSData *) pcl;
|
||||
- (NSNumber *) lastModifiedFromMessageChangeNumber: (NSString *) changeNumber;
|
||||
- (NSString *) changeNumberForMessageWithKey: (NSString *) messageKey;
|
||||
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey;
|
||||
|
||||
+197
-21
@@ -75,6 +75,7 @@ static Class NSNumberK;
|
||||
[SOGoMAPIDBMessage objectWithName: @"versions.plist"
|
||||
inContainer: dbFolder]);
|
||||
[versionsMessage setObjectType: MAPIInternalCacheObject];
|
||||
[versionsMessage reloadIfNeeded];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
@@ -261,7 +262,6 @@ static Class NSNumberK;
|
||||
*/
|
||||
- (void) _setChangeKey: (NSData *) changeKey
|
||||
forMessageEntry: (NSMutableDictionary *) messageEntry
|
||||
inChangeListOnly: (BOOL) inChangeListOnly
|
||||
{
|
||||
struct XID *xid;
|
||||
NSString *guid;
|
||||
@@ -270,19 +270,15 @@ static Class NSNumberK;
|
||||
NSMutableDictionary *changeList;
|
||||
|
||||
xid = [changeKey asXIDInMemCtx: NULL];
|
||||
guid = [NSString stringWithGUID: &xid->GUID];
|
||||
globCnt = [NSData dataWithBytes: xid->Data length: xid->Size];
|
||||
guid = [NSString stringWithGUID: &xid->NameSpaceGuid];
|
||||
globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length];
|
||||
talloc_free (xid);
|
||||
|
||||
if (!inChangeListOnly)
|
||||
{
|
||||
/* 1. set change key association */
|
||||
changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
guid, @"GUID",
|
||||
globCnt, @"LocalId",
|
||||
nil];
|
||||
[messageEntry setObject: changeKeyDict forKey: @"ChangeKey"];
|
||||
}
|
||||
/* 1. set change key association */
|
||||
changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys: guid, @"GUID",
|
||||
globCnt, @"LocalId",
|
||||
nil];
|
||||
[messageEntry setObject: changeKeyDict forKey: @"ChangeKey"];
|
||||
|
||||
/* 2. append/update predecessor change list */
|
||||
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
|
||||
@@ -296,6 +292,77 @@ static Class NSNumberK;
|
||||
[changeList setObject: globCnt forKey: guid];
|
||||
}
|
||||
|
||||
- (void) _updatePredecessorChangeList: (NSData *) predecessorChangeList
|
||||
forMessageEntry: (NSMutableDictionary *) messageEntry
|
||||
withOldChangeKey: (NSData *) oldChangeKey
|
||||
{
|
||||
NSData *globCnt, *oldGlobCnt;
|
||||
NSDictionary *changeKeyDict;
|
||||
NSString *guid;
|
||||
NSMutableDictionary *changeList;
|
||||
struct SizedXid *sizedXIDList;
|
||||
struct XID xid, *givenChangeKey;
|
||||
TALLOC_CTX *localMemCtx;
|
||||
uint32_t i, length;
|
||||
|
||||
localMemCtx = talloc_new (NULL);
|
||||
if (!localMemCtx)
|
||||
{
|
||||
[self errorWithFormat: @"No more memory"];
|
||||
return;
|
||||
}
|
||||
|
||||
if (predecessorChangeList)
|
||||
{
|
||||
sizedXIDList = [predecessorChangeList asSizedXidArrayInMemCtx: localMemCtx with: &length];
|
||||
|
||||
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
|
||||
if (!changeList)
|
||||
{
|
||||
changeList = [NSMutableDictionary new];
|
||||
[messageEntry setObject: changeList
|
||||
forKey: @"PredecessorChangeList"];
|
||||
[changeList release];
|
||||
}
|
||||
|
||||
if (sizedXIDList) {
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
xid = sizedXIDList[i].XID;
|
||||
guid = [NSString stringWithGUID: &xid.NameSpaceGuid];
|
||||
globCnt = [NSData dataWithBytes: xid.LocalId.data length: xid.LocalId.length];
|
||||
oldGlobCnt = [changeList objectForKey: guid];
|
||||
if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending))
|
||||
[changeList setObject: globCnt forKey: guid];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oldChangeKey)
|
||||
{
|
||||
givenChangeKey = [oldChangeKey asXIDInMemCtx: localMemCtx];
|
||||
if (givenChangeKey) {
|
||||
guid = [NSString stringWithGUID: &givenChangeKey->NameSpaceGuid];
|
||||
globCnt = [NSData dataWithBytes: givenChangeKey->LocalId.data length: givenChangeKey->LocalId.length];
|
||||
|
||||
changeKeyDict = [messageEntry objectForKey: @"ChangeKey"];
|
||||
if (!changeKeyDict ||
|
||||
([guid isEqualToString: [changeKeyDict objectForKey: @"GUID"]]
|
||||
&& ([globCnt compare: [changeKeyDict objectForKey: @"LocalId"]] == NSOrderedDescending)))
|
||||
{
|
||||
/* The given change key is greater than current one stored in
|
||||
metadata or it does not exist */
|
||||
[messageEntry setObject: [NSDictionary dictionaryWithObjectsAndKeys: guid, @"GUID",
|
||||
globCnt, @"LocalId",
|
||||
nil]
|
||||
forKey: @"ChangeKey"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
talloc_free (localMemCtx);
|
||||
}
|
||||
|
||||
- (EOQualifier *) componentQualifier
|
||||
{
|
||||
if (!componentQualifier)
|
||||
@@ -465,8 +532,7 @@ static Class NSNumberK;
|
||||
// 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];
|
||||
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
|
||||
}
|
||||
|
||||
now = [NSCalendarDate date];
|
||||
@@ -482,13 +548,123 @@ static Class NSNumberK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
- (BOOL) synchroniseCacheFor: (NSString *) nameInContainer
|
||||
{
|
||||
/* Try to synchronise old messages in versions.plist cache using an
|
||||
specific c_name. It returns a boolean indicating if the
|
||||
synchronisation was carried out succesfully.
|
||||
|
||||
It should be used as last resort, keeping synchroniseCache as the
|
||||
main sync entry point. */
|
||||
|
||||
uint64_t changeNumber;
|
||||
NSString *changeNumberStr;
|
||||
NSData *changeKey;
|
||||
NSNumber *cLastModified, *cDeleted, *cVersion;
|
||||
EOFetchSpecification *fs;
|
||||
EOQualifier *searchQualifier, *fetchQualifier;
|
||||
NSArray *fetchResults;
|
||||
NSDictionary *result;
|
||||
NSMutableDictionary *currentProperties, *messages, *mapping, *messageEntry;
|
||||
GCSFolder *ocsFolder;
|
||||
static NSArray *fields;
|
||||
|
||||
[versionsMessage reloadIfNeeded];
|
||||
currentProperties = [versionsMessage properties];
|
||||
|
||||
messages = [currentProperties objectForKey: @"Messages"];
|
||||
if (!messages)
|
||||
{
|
||||
messages = [NSMutableDictionary new];
|
||||
[currentProperties setObject: messages forKey: @"Messages"];
|
||||
[messages release];
|
||||
}
|
||||
|
||||
messageEntry = [messages objectForKey: nameInContainer];
|
||||
if (!messageEntry)
|
||||
{
|
||||
/* Fetch the message by its name */
|
||||
if (!fields)
|
||||
fields = [[NSArray alloc]
|
||||
initWithObjects: @"c_name", @"c_version", @"c_lastmodified",
|
||||
@"c_deleted", nil];
|
||||
|
||||
searchQualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_name"
|
||||
operatorSelector: EOQualifierOperatorEqual
|
||||
value: nameInContainer];
|
||||
fetchQualifier = [[EOAndQualifier alloc]
|
||||
initWithQualifiers: searchQualifier,
|
||||
[self contentComponentQualifier],
|
||||
nil];
|
||||
[fetchQualifier autorelease];
|
||||
[searchQualifier release];
|
||||
|
||||
ocsFolder = [sogoObject ocsFolder];
|
||||
fs = [EOFetchSpecification
|
||||
fetchSpecificationWithEntityName: [ocsFolder folderName]
|
||||
qualifier: fetchQualifier
|
||||
sortOrderings: nil];
|
||||
fetchResults = [ocsFolder fetchFields: fields
|
||||
fetchSpecification: fs
|
||||
ignoreDeleted: NO];
|
||||
|
||||
if ([fetchResults count] == 1)
|
||||
{
|
||||
result = [fetchResults objectAtIndex: 0];
|
||||
cLastModified = [result objectForKey: @"c_lastmodified"];
|
||||
cDeleted = [result objectForKey: @"c_deleted"];
|
||||
if ([cDeleted isKindOfClass: NSNumberK] && [cDeleted intValue])
|
||||
cVersion = [NSNumber numberWithInt: -1];
|
||||
else
|
||||
cVersion = [result objectForKey: @"c_version"];
|
||||
|
||||
changeNumber = [[self context] getNewChangeNumber];
|
||||
changeNumberStr = [NSString stringWithUnsignedLongLong: changeNumber];
|
||||
|
||||
/* Create new message entry in Messages dict */
|
||||
messageEntry = [NSMutableDictionary new];
|
||||
[messages setObject: messageEntry forKey: nameInContainer];
|
||||
[messageEntry release];
|
||||
|
||||
/* Store cLastModified, cVersion and the change number */
|
||||
[messageEntry setObject: cLastModified forKey: @"c_lastmodified"];
|
||||
[messageEntry setObject: cVersion forKey: @"c_version"];
|
||||
[messageEntry setObject: changeNumberStr forKey: @"version"];
|
||||
|
||||
/* Store the change key */
|
||||
changeKey = [self getReplicaKeyFromGlobCnt: changeNumber >> 16];
|
||||
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
|
||||
|
||||
/* Store the changeNumber -> cLastModified mapping */
|
||||
mapping = [currentProperties objectForKey: @"VersionMapping"];
|
||||
if (!mapping)
|
||||
{
|
||||
mapping = [NSMutableDictionary new];
|
||||
[currentProperties setObject: mapping forKey: @"VersionMapping"];
|
||||
[mapping release];
|
||||
}
|
||||
[mapping setObject: cLastModified forKey: changeNumberStr];
|
||||
|
||||
/* Save the message */
|
||||
[versionsMessage save];
|
||||
return YES;
|
||||
}
|
||||
else
|
||||
return NO;
|
||||
}
|
||||
|
||||
/* If message entry exists, then synchroniseCache did its job */
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void) updateVersionsForMessageWithKey: (NSString *) messageKey
|
||||
withChangeKey: (NSData *) newChangeKey
|
||||
withChangeKey: (NSData *) oldChangeKey
|
||||
andPredecessorChangeList: (NSData *) pcl
|
||||
{
|
||||
NSMutableDictionary *messages, *messageEntry;
|
||||
|
||||
[self synchroniseCache];
|
||||
if (newChangeKey)
|
||||
if (oldChangeKey || pcl)
|
||||
{
|
||||
messages = [[versionsMessage properties] objectForKey: @"Messages"];
|
||||
messageEntry = [messages objectForKey: messageKey];
|
||||
@@ -496,8 +672,8 @@ static Class NSNumberK;
|
||||
[NSException raise: @"MAPIStoreIOException"
|
||||
format: @"no version record found for message '%@'",
|
||||
messageKey];
|
||||
[self _setChangeKey: newChangeKey forMessageEntry: messageEntry
|
||||
inChangeListOnly: YES];
|
||||
[self _updatePredecessorChangeList: pcl forMessageEntry: messageEntry
|
||||
withOldChangeKey: oldChangeKey];
|
||||
[versionsMessage save];
|
||||
}
|
||||
}
|
||||
@@ -505,12 +681,12 @@ static Class NSNumberK;
|
||||
- (NSNumber *) lastModifiedFromMessageChangeNumber: (NSString *) changeNumber
|
||||
{
|
||||
NSDictionary *mapping;
|
||||
NSNumber *modseq;
|
||||
NSNumber *lastModified;
|
||||
|
||||
mapping = [[versionsMessage properties] objectForKey: @"VersionMapping"];
|
||||
modseq = [mapping objectForKey: changeNumber];
|
||||
lastModified = [mapping objectForKey: changeNumber];
|
||||
|
||||
return modseq;
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
- (NSString *) changeNumberForMessageWithKey: (NSString *) messageKey
|
||||
|
||||
@@ -140,9 +140,16 @@
|
||||
[parentFolder synchroniseCache];
|
||||
changeKey = [parentFolder changeKeyForMessageWithKey: nameInContainer];
|
||||
}
|
||||
if (!changeKey)
|
||||
abort ();
|
||||
*data = [changeKey asBinaryInMemCtx: memCtx];
|
||||
if (changeKey)
|
||||
*data = [changeKey asBinaryInMemCtx: memCtx];
|
||||
else
|
||||
{
|
||||
[self warnWithFormat: @"No change key for %@ in folder %@",
|
||||
nameInContainer,
|
||||
[parentFolder url]
|
||||
];
|
||||
rc = MAPISTORE_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -180,7 +187,8 @@
|
||||
{
|
||||
uint64_t version = ULLONG_MAX;
|
||||
NSString *changeNumber;
|
||||
|
||||
BOOL synced;
|
||||
|
||||
if (!isNew)
|
||||
{
|
||||
changeNumber = [(MAPIStoreGCSFolder *) container
|
||||
@@ -189,16 +197,28 @@
|
||||
{
|
||||
[self warnWithFormat: @"attempting to get change number"
|
||||
@" by synchronising folder..."];
|
||||
[(MAPIStoreGCSFolder *) container synchroniseCache];
|
||||
changeNumber = [(MAPIStoreGCSFolder *) container
|
||||
changeNumberForMessageWithKey: [self nameInContainer]];
|
||||
|
||||
if (changeNumber)
|
||||
[self logWithFormat: @"got one"];
|
||||
else
|
||||
synced = [(MAPIStoreGCSFolder *) container synchroniseCache];
|
||||
if (synced)
|
||||
{
|
||||
[self errorWithFormat: @"still nothing. We crash!"];
|
||||
abort();
|
||||
changeNumber = [(MAPIStoreGCSFolder *) container
|
||||
changeNumberForMessageWithKey: [self nameInContainer]];
|
||||
}
|
||||
if (!changeNumber)
|
||||
{
|
||||
[self warnWithFormat: @"attempting to get change number"
|
||||
@" by synchronising this specific message..."];
|
||||
synced = [(MAPIStoreGCSFolder *) container
|
||||
synchroniseCacheFor: [self nameInContainer]];
|
||||
if (synced)
|
||||
{
|
||||
changeNumber = [(MAPIStoreGCSFolder *) container
|
||||
changeNumberForMessageWithKey: [self nameInContainer]];
|
||||
}
|
||||
if (!changeNumber)
|
||||
{
|
||||
[self errorWithFormat: @"still nothing. We crash!"];
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
version = [changeNumber unsignedLongLongValue] >> 16;
|
||||
@@ -209,13 +229,16 @@
|
||||
|
||||
- (void) updateVersions
|
||||
{
|
||||
NSData *newChangeKey;
|
||||
/* Update ChangeKey and PredecessorChangeList on message's save */
|
||||
NSData *newChangeKey, *predecessorChangeList;
|
||||
|
||||
newChangeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)];
|
||||
predecessorChangeList = [properties objectForKey: MAPIPropertyKey (PR_PREDECESSOR_CHANGE_LIST)];
|
||||
|
||||
[(MAPIStoreGCSFolder *) container
|
||||
updateVersionsForMessageWithKey: [self nameInContainer]
|
||||
withChangeKey: newChangeKey];
|
||||
updateVersionsForMessageWithKey: [self nameInContainer]
|
||||
withChangeKey: newChangeKey
|
||||
andPredecessorChangeList: predecessorChangeList];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -27,6 +27,7 @@
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSObject+Values.h>
|
||||
|
||||
#import <EOControl/EOFetchSpecification.h>
|
||||
#import <EOControl/EOQualifier.h>
|
||||
@@ -38,7 +39,6 @@
|
||||
|
||||
#import "MAPIStoreTypes.h"
|
||||
#import "MAPIStoreGCSFolder.h"
|
||||
|
||||
#import "MAPIStoreGCSMessageTable.h"
|
||||
|
||||
#undef DEBUG
|
||||
@@ -89,21 +89,31 @@
|
||||
|
||||
if (res->ulPropTag == PidTagChangeNumber)
|
||||
{
|
||||
NSString *changeNumber;
|
||||
|
||||
value = NSObjectFromMAPISPropValue (&res->lpProp);
|
||||
changeNumber = [NSString stringWithUnsignedLongLong: [(NSNumber *)value unsignedLongLongValue]];
|
||||
lastModified = [(MAPIStoreGCSFolder *)
|
||||
container lastModifiedFromMessageChangeNumber: value];
|
||||
container lastModifiedFromMessageChangeNumber: changeNumber];
|
||||
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
|
||||
//[self logWithFormat: @" c_lastmodified: %@", lastModified];
|
||||
if (lastModified)
|
||||
{
|
||||
SEL operator;
|
||||
|
||||
operator = [self operatorFromRestrictionOperator: res->relop];
|
||||
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_lastmodified"
|
||||
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
|
||||
operatorSelector: operator
|
||||
value: lastModified];
|
||||
[*qualifier autorelease];
|
||||
rc = MAPIRestrictionStateNeedsEval;
|
||||
}
|
||||
else
|
||||
rc = MAPIRestrictionStateAlwaysTrue;
|
||||
{
|
||||
[self logWithFormat: @"No last modified found for: 0x%.16"PRIx64". Then no restriction applied",
|
||||
[value unsignedLongLongValue]];
|
||||
rc = MAPIRestrictionStateAlwaysTrue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <Mailer/SOGoMailBodyPart.h>
|
||||
#import <Mailer/SOGoMailObject.h>
|
||||
#import <Mailer/NSDictionary+Mail.h>
|
||||
|
||||
#import "MAPIStoreTypes.h"
|
||||
#import "MAPIStoreMailMessage.h"
|
||||
@@ -108,7 +109,7 @@
|
||||
static char recordBytes[] = {0xd9, 0xd8, 0x11, 0xa3, 0xe2, 0x90, 0x18, 0x41,
|
||||
0x9e, 0x04, 0x58, 0x46, 0x9d, 0x6d, 0x1b,
|
||||
0x68};
|
||||
|
||||
|
||||
*data = [[NSData dataWithBytes: recordBytes length: 16]
|
||||
asBinaryInMemCtx: memCtx];
|
||||
|
||||
@@ -117,19 +118,7 @@
|
||||
|
||||
- (NSString *) _fileName
|
||||
{
|
||||
NSString *fileName;
|
||||
NSDictionary *parameters;
|
||||
|
||||
fileName = [[bodyInfo objectForKey: @"parameterList"]
|
||||
objectForKey: @"name"];
|
||||
if (!fileName)
|
||||
{
|
||||
parameters = [[bodyInfo objectForKey: @"disposition"]
|
||||
objectForKey: @"parameterList"];
|
||||
fileName = [parameters objectForKey: @"filename"];
|
||||
}
|
||||
|
||||
return fileName;
|
||||
return [bodyInfo filename];
|
||||
}
|
||||
|
||||
- (int) getPidTagAttachLongFilename: (void **) data
|
||||
@@ -178,7 +167,7 @@
|
||||
|
||||
- (int) getPidTagAttachContentId: (void **) data
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
{
|
||||
*data = [[bodyInfo objectForKey: @"bodyId"]
|
||||
asUnicodeInMemCtx: memCtx];
|
||||
|
||||
|
||||
@@ -160,23 +160,25 @@ MakeDisplayFolderName (NSString *folderName)
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
context = talloc_zero (memCtx, struct mapistore_contexts_list);
|
||||
// secondaryFolders has the names (1) Imap4Encoded and (2) asCSSIdentifier
|
||||
// e.g.: Probl&AOg-mes_SP_de_SP_synchronisation
|
||||
// secondaryFolders has the names (1) Imap4Encoded ,(2) asCSSIdentifier and (3) "folder"-prefixed
|
||||
// e.g.: folderProbl&AOg-mes_SP_de_SP_synchronisation
|
||||
currentName = [secondaryFolders objectAtIndex: count];
|
||||
// To get the real name we have to revert that (applying the decode functions)
|
||||
// in reverse order
|
||||
// To get the real name we have to revert that (applying the decode functions
|
||||
// in reverse order)
|
||||
// e.g.: Problèmes de synchronisation
|
||||
realName = [[currentName fromCSSIdentifier]
|
||||
stringByDecodingImap4FolderName];
|
||||
realName = [[[currentName substringFromIndex: 6]
|
||||
fromCSSIdentifier]
|
||||
stringByDecodingImap4FolderName];
|
||||
// And finally to represent that as URI we have to (1) asCSSIdentifier,
|
||||
// (2) Imap4Encode and (3) AddPercentEscapes
|
||||
// e.g.: Probl&AOg-mes_SP_de_SP_synchronisation
|
||||
// (2) Imap4Encode (3) AddPercentEscapes and (4) add the "folder" prefix
|
||||
// e.g.: folderProbl&AOg-mes_SP_de_SP_synchronisation
|
||||
// In the example there are no percent escapes added because is already ok
|
||||
stringData = [[[realName asCSSIdentifier]
|
||||
stringByEncodingImap4FolderName]
|
||||
stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
|
||||
stringData = [NSString stringWithFormat: @"folder%@", stringData];
|
||||
context->url = [[NSString stringWithFormat: @"%@%@", urlBase, stringData] asUnicodeInMemCtx: context];
|
||||
context->name = [[realName substringFromIndex: 6] asUnicodeInMemCtx: context];
|
||||
context->name = [realName asUnicodeInMemCtx: context];
|
||||
context->main_folder = false;
|
||||
context->role = MAPISTORE_MAIL_ROLE;
|
||||
context->tag = "tag";
|
||||
@@ -200,7 +202,7 @@ MakeDisplayFolderName (NSString *folderName)
|
||||
andTDBIndexing: NULL];
|
||||
accountFolder = [[userContext rootFolders] objectForKey: @"mail"];
|
||||
folderName = [NSString stringWithFormat: @"folder%@",
|
||||
[newFolderName asCSSIdentifier]];
|
||||
[[newFolderName stringByEncodingImap4FolderName] asCSSIdentifier]];
|
||||
newFolder = [SOGoMailFolder objectWithName: folderName
|
||||
inContainer: accountFolder];
|
||||
if ([newFolder create])
|
||||
@@ -209,7 +211,7 @@ MakeDisplayFolderName (NSString *folderName)
|
||||
withString: @"%40"],
|
||||
[userName stringByReplacingOccurrencesOfString: @"@"
|
||||
withString: @"%40"],
|
||||
[[folderName stringByEncodingImap4FolderName] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
|
||||
[folderName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
|
||||
else
|
||||
mapistoreURI = nil;
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
- (NSString *) changeNumberForMessageUID: (NSString *) messageUid;
|
||||
- (void) setChangeKey: (NSData *) changeKey
|
||||
forMessageWithKey: (NSString *) messageKey;
|
||||
- (BOOL) updatePredecessorChangeListWith: (NSData *) changeKey
|
||||
forMessageWithKey: (NSString *) messageKey;
|
||||
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey;
|
||||
- (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey;
|
||||
|
||||
|
||||
@@ -68,10 +68,13 @@
|
||||
|
||||
static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
|
||||
#include <gen_ndr/exchange.h>
|
||||
|
||||
#undef DEBUG
|
||||
#include <util/attr.h>
|
||||
#include <libmapi/libmapi.h>
|
||||
#include <libmapiproxy.h>
|
||||
#include <limits.h>
|
||||
#include <mapistore/mapistore.h>
|
||||
#include <mapistore/mapistore_errors.h>
|
||||
|
||||
@@ -109,6 +112,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
[SOGoMAPIDBMessage objectWithName: @"versions.plist"
|
||||
inContainer: dbFolder]);
|
||||
[versionsMessage setObjectType: MAPIInternalCacheObject];
|
||||
[versionsMessage reloadIfNeeded];
|
||||
}
|
||||
|
||||
- (BOOL) ensureFolderExists
|
||||
@@ -178,7 +182,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
if (aRow->lpProps[i].ulPropTag == PR_DISPLAY_NAME_UNICODE)
|
||||
folderName = [NSString stringWithUTF8String: aRow->lpProps[i].value.lpszW];
|
||||
else if (aRow->lpProps[i].ulPropTag == PR_DISPLAY_NAME)
|
||||
folderName = [NSString stringWithUTF8String: aRow->lpProps[i].value.lpszA];
|
||||
folderName = [NSString stringWithUTF8String: (const char *) aRow->lpProps[i].value.lpszA];
|
||||
}
|
||||
|
||||
if (folderName)
|
||||
@@ -254,6 +258,67 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
- (EOQualifier *) simplifyQualifier: (EOQualifier *) qualifier
|
||||
{
|
||||
/* Hack: Reduce the number of MODSEQ constraints to a single one as
|
||||
we assume the difference among MODSEQs will be small enough to
|
||||
return a small number of UIDs.
|
||||
|
||||
This is the only case we do simplify:
|
||||
MODSEQ >= x | MODSEQ >= y | MODSEQ >= z => MODSEQ >= min(x,y,z)
|
||||
*/
|
||||
if (qualifier && [qualifier isKindOfClass: [EOOrQualifier class]])
|
||||
{
|
||||
EOQualifier *simplifiedQualifier;
|
||||
NSArray *quals;
|
||||
NSNumber *minModseq;
|
||||
NSUInteger i, count;
|
||||
|
||||
quals = [(EOOrQualifier *)qualifier qualifiers];
|
||||
count = [quals count];
|
||||
if (count < 2)
|
||||
return qualifier;
|
||||
|
||||
minModseq = [NSNumber numberWithUnsignedLongLong: ULLONG_MAX];
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
EOQualifier *subQualifier;
|
||||
|
||||
subQualifier = [quals objectAtIndex: i];
|
||||
if ([subQualifier isKindOfClass: [EOAndQualifier class]]
|
||||
&& [[(EOAndQualifier *)subQualifier qualifiers] count] == 1)
|
||||
subQualifier = [[(EOAndQualifier *)subQualifier qualifiers] objectAtIndex: 0];
|
||||
|
||||
if ([subQualifier isKindOfClass: [EOKeyValueQualifier class]]
|
||||
&& [[(EOKeyValueQualifier *)subQualifier key] isEqualToString: @"MODSEQ"])
|
||||
{
|
||||
NSNumber *value;
|
||||
|
||||
value = (NSNumber *)[(EOKeyValueQualifier *)subQualifier value];
|
||||
if ([minModseq compare: value] == NSOrderedDescending
|
||||
&& [value unsignedLongLongValue] > 0)
|
||||
minModseq = (NSNumber *)[(EOKeyValueQualifier *)subQualifier value];
|
||||
|
||||
}
|
||||
else
|
||||
return qualifier;
|
||||
}
|
||||
|
||||
if ([minModseq unsignedLongLongValue] > 0 && [minModseq unsignedLongLongValue] < ULLONG_MAX)
|
||||
{
|
||||
simplifiedQualifier = [[EOKeyValueQualifier alloc]
|
||||
initWithKey: @"MODSEQ"
|
||||
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
|
||||
value: minModseq];
|
||||
[simplifiedQualifier autorelease];
|
||||
return simplifiedQualifier;
|
||||
}
|
||||
}
|
||||
|
||||
return qualifier;
|
||||
}
|
||||
|
||||
- (EOQualifier *) nonDeletedQualifier
|
||||
{
|
||||
static EOQualifier *nonDeletedQualifier = nil;
|
||||
@@ -278,7 +343,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
andSortOrderings: (NSArray *) sortOrderings
|
||||
{
|
||||
NSArray *uidKeys;
|
||||
EOQualifier *fetchQualifier;
|
||||
EOQualifier *fetchQualifier, *simplifiedQualifier;
|
||||
|
||||
if ([self ensureFolderExists])
|
||||
{
|
||||
@@ -287,9 +352,10 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||
|
||||
if (qualifier)
|
||||
{
|
||||
simplifiedQualifier = [self simplifyQualifier: qualifier];
|
||||
fetchQualifier
|
||||
= [[EOAndQualifier alloc] initWithQualifiers:
|
||||
[self nonDeletedQualifier], qualifier,
|
||||
[self nonDeletedQualifier], simplifiedQualifier,
|
||||
nil];
|
||||
[fetchQualifier autorelease];
|
||||
}
|
||||
@@ -516,6 +582,44 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
return [modseq1 compare: modseq2];
|
||||
}
|
||||
|
||||
- (void) _updatePredecessorChangeListWith: (NSData *) predecessorChangeList
|
||||
forMessageEntry: (NSMutableDictionary *) messageEntry
|
||||
{
|
||||
NSData *globCnt, *oldGlobCnt;
|
||||
NSMutableDictionary *changeList;
|
||||
NSString *guid;
|
||||
struct SizedXid *sizedXIDList;
|
||||
struct XID xid;
|
||||
uint32_t i, length;
|
||||
|
||||
sizedXIDList = [predecessorChangeList asSizedXidArrayInMemCtx: NULL with: &length];
|
||||
|
||||
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
|
||||
if (!changeList)
|
||||
{
|
||||
changeList = [NSMutableDictionary new];
|
||||
[messageEntry setObject: changeList
|
||||
forKey: @"PredecessorChangeList"];
|
||||
[changeList release];
|
||||
}
|
||||
|
||||
if (sizedXIDList) {
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
xid = sizedXIDList[i].XID;
|
||||
guid = [NSString stringWithGUID: &xid.NameSpaceGuid];
|
||||
globCnt = [NSData dataWithBytes: xid.LocalId.data length: xid.LocalId.length];
|
||||
oldGlobCnt = [changeList objectForKey: guid];
|
||||
if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending))
|
||||
[changeList setObject: globCnt forKey: guid];
|
||||
}
|
||||
|
||||
talloc_free (sizedXIDList);
|
||||
}
|
||||
|
||||
[versionsMessage save];
|
||||
}
|
||||
|
||||
- (void) _setChangeKey: (NSData *) changeKey
|
||||
forMessageEntry: (NSMutableDictionary *) messageEntry
|
||||
{
|
||||
@@ -526,8 +630,8 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
NSMutableDictionary *changeList;
|
||||
|
||||
xid = [changeKey asXIDInMemCtx: NULL];
|
||||
guid = [NSString stringWithGUID: &xid->GUID];
|
||||
globCnt = [NSData dataWithBytes: xid->Data length: xid->Size];
|
||||
guid = [NSString stringWithGUID: &xid->NameSpaceGuid];
|
||||
globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length];
|
||||
talloc_free (xid);
|
||||
|
||||
/* 1. set change key association */
|
||||
@@ -553,13 +657,12 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
{
|
||||
BOOL rc = YES;
|
||||
uint64_t newChangeNum;
|
||||
NSNumber *ti, *modseq, *initialLastModseq, *lastModseq,
|
||||
*nextModseq;
|
||||
NSNumber *ti, *modseq, *lastModseq, *nextModseq;
|
||||
NSString *changeNumber, *uid, *messageKey;
|
||||
uint64_t lastModseqNbr;
|
||||
EOQualifier *searchQualifier;
|
||||
NSArray *uids, *changeNumbers;
|
||||
NSUInteger count, max;
|
||||
NSUInteger count, max, nFetched;
|
||||
NSArray *fetchResults;
|
||||
NSDictionary *result;
|
||||
NSData *changeKey;
|
||||
@@ -593,7 +696,6 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
}
|
||||
|
||||
lastModseq = [currentProperties objectForKey: @"SyncLastModseq"];
|
||||
initialLastModseq = lastModseq;
|
||||
if (lastModseq)
|
||||
{
|
||||
lastModseqNbr = [lastModseq unsignedLongLongValue];
|
||||
@@ -639,6 +741,13 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
= [fetchResults sortedArrayUsingFunction: _compareFetchResultsByMODSEQ
|
||||
context: NULL];
|
||||
|
||||
nFetched = [fetchResults count];
|
||||
if (nFetched != max) {
|
||||
[self errorWithFormat: @"Error fetching UIDs. Asked: %d Received: %d."
|
||||
@"Check the IMAP conversation for details", max, nFetched];
|
||||
return NO;
|
||||
}
|
||||
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
result = [fetchResults objectAtIndex: count];
|
||||
@@ -677,40 +786,37 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
}
|
||||
|
||||
/* 2. we synchronise expunged UIDs */
|
||||
if (initialLastModseq)
|
||||
fetchResults = [(SOGoMailFolder *) sogoObject
|
||||
fetchUIDsOfVanishedItems: lastModseqNbr];
|
||||
|
||||
max = [fetchResults count];
|
||||
|
||||
changeNumber = nil;
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
fetchResults = [(SOGoMailFolder *) sogoObject
|
||||
fetchUIDsOfVanishedItems: lastModseqNbr];
|
||||
|
||||
max = [fetchResults count];
|
||||
|
||||
changeNumber = nil;
|
||||
for (count = 0; count < max; count++)
|
||||
uid = [[fetchResults objectAtIndex: count] stringValue];
|
||||
if ([messages objectForKey: uid])
|
||||
{
|
||||
uid = [[fetchResults objectAtIndex: count] stringValue];
|
||||
if ([messages objectForKey: uid])
|
||||
if (!changeNumber)
|
||||
{
|
||||
if (!changeNumber)
|
||||
{
|
||||
newChangeNum = [[self context] getNewChangeNumber];
|
||||
changeNumber = [NSString stringWithUnsignedLongLong: newChangeNum];
|
||||
}
|
||||
[messages removeObjectForKey: uid];
|
||||
[self logWithFormat: @"Removed message entry for UID %@", uid];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self logWithFormat:@"Message entry not found for UID %@", uid];
|
||||
newChangeNum = [[self context] getNewChangeNumber];
|
||||
changeNumber = [NSString stringWithUnsignedLongLong: newChangeNum];
|
||||
}
|
||||
[messages removeObjectForKey: uid];
|
||||
[self logWithFormat: @"Removed message entry for UID %@", uid];
|
||||
}
|
||||
if (changeNumber)
|
||||
else
|
||||
{
|
||||
[currentProperties setObject: changeNumber
|
||||
forKey: @"SyncLastDeleteChangeNumber"];
|
||||
[mapping setObject: lastModseq forKey: changeNumber];
|
||||
foundChange = YES;
|
||||
[self logWithFormat:@"Message entry not found for UID %@", uid];
|
||||
}
|
||||
}
|
||||
if (changeNumber)
|
||||
{
|
||||
[currentProperties setObject: changeNumber
|
||||
forKey: @"SyncLastDeleteChangeNumber"];
|
||||
[mapping setObject: lastModseq forKey: changeNumber];
|
||||
foundChange = YES;
|
||||
}
|
||||
|
||||
if (foundChange)
|
||||
{
|
||||
@@ -924,8 +1030,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
return changeNumber;
|
||||
}
|
||||
|
||||
- (void) setChangeKey: (NSData *) changeKey
|
||||
forMessageWithKey: (NSString *) messageKey
|
||||
- (NSMutableDictionary *) _messageEntryFromMessageKey: (NSString *) messageKey
|
||||
{
|
||||
NSMutableDictionary *messages, *messageEntry;
|
||||
NSString *messageUid;
|
||||
@@ -936,7 +1041,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
messageEntry = [messages objectForKey: messageUid];
|
||||
if (!messageEntry)
|
||||
{
|
||||
[self warnWithFormat: @"attempting to synchronise to set the change key for "
|
||||
[self warnWithFormat: @"attempting to synchronise to get the message entry for "
|
||||
@"this message %@", messageKey];
|
||||
synced = [self synchroniseCacheForUID: messageUid];
|
||||
if (synced)
|
||||
@@ -947,11 +1052,57 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
|
||||
|
||||
return messageEntry;
|
||||
}
|
||||
|
||||
- (void) setChangeKey: (NSData *) changeKey
|
||||
forMessageWithKey: (NSString *) messageKey
|
||||
{
|
||||
[self _setChangeKey: changeKey
|
||||
forMessageEntry: [self _messageEntryFromMessageKey: messageKey]];
|
||||
|
||||
[versionsMessage save];
|
||||
}
|
||||
|
||||
- (BOOL) updatePredecessorChangeListWith: (NSData *) changeKey
|
||||
forMessageWithKey: (NSString *) messageKey
|
||||
{
|
||||
/* Update predecessor change list property given the change key. It
|
||||
returns if the change key has been added to the list or not */
|
||||
BOOL added = NO;
|
||||
NSData *globCnt, *oldGlobCnt;
|
||||
NSDictionary *messageEntry;
|
||||
NSMutableDictionary *changeList;
|
||||
NSString *guid;
|
||||
struct XID *xid;
|
||||
|
||||
xid = [changeKey asXIDInMemCtx: NULL];
|
||||
guid = [NSString stringWithGUID: &xid->NameSpaceGuid];
|
||||
globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length];
|
||||
talloc_free (xid);
|
||||
|
||||
messageEntry = [self _messageEntryFromMessageKey: messageKey];
|
||||
if (messageEntry)
|
||||
{
|
||||
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
|
||||
if (changeList)
|
||||
{
|
||||
oldGlobCnt = [changeList objectForKey: guid];
|
||||
if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending))
|
||||
{
|
||||
[changeList setObject: globCnt forKey: guid];
|
||||
[versionsMessage save];
|
||||
added = YES;
|
||||
}
|
||||
}
|
||||
else
|
||||
[self errorWithFormat: @"Missing predecessor change list to update"];
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey
|
||||
{
|
||||
NSDictionary *messages, *changeKeyDict;
|
||||
@@ -1217,6 +1368,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
fromFolder: (MAPIStoreFolder *) sourceFolder
|
||||
withMIDs: (uint64_t *) targetMids
|
||||
andChangeKeys: (struct Binary_r **) targetChangeKeys
|
||||
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
|
||||
wantCopy: (uint8_t) wantCopy
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
|
||||
@@ -1231,12 +1383,13 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
NSDictionary *result;
|
||||
NSUInteger count;
|
||||
NSArray *a;
|
||||
NSData *changeKey;
|
||||
NSData *changeList;
|
||||
|
||||
if (![sourceFolder isKindOfClass: [MAPIStoreMailFolder class]])
|
||||
return [super moveCopyMessagesWithMIDs: srcMids andCount: midCount
|
||||
fromFolder: sourceFolder withMIDs: targetMids
|
||||
andChangeKeys: targetChangeKeys
|
||||
andPredecessorChangeLists: targetPredecessorChangeLists
|
||||
wantCopy: wantCopy
|
||||
inMemCtx: memCtx];
|
||||
|
||||
@@ -1325,11 +1478,11 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
[self synchroniseCache];
|
||||
for (count = 0; count < midCount; count++)
|
||||
{
|
||||
changeKey = [NSData dataWithBinary: targetChangeKeys[count]];
|
||||
changeList = [NSData dataWithBinary: targetPredecessorChangeLists[count]];
|
||||
messageKey = [NSString stringWithFormat: @"%@.eml",
|
||||
[destUIDs objectAtIndex: count]];
|
||||
[self setChangeKey: changeKey
|
||||
forMessageWithKey: messageKey];
|
||||
[self _updatePredecessorChangeListWith: changeList
|
||||
forMessageEntry: [self _messageEntryFromMessageKey: messageKey]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1558,10 +1711,10 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
|
||||
rights |= RightsCreateItems;
|
||||
if ([roles containsObject: SOGoRole_ObjectEraser]
|
||||
&& [roles containsObject: SOGoRole_FolderEraser])
|
||||
rights |= RightsDeleteAll;
|
||||
rights |= RightsDeleteAll | RightsDeleteOwn;
|
||||
|
||||
if ([roles containsObject: SOGoRole_ObjectEditor])
|
||||
rights |= RightsEditAll;
|
||||
rights |= RightsEditAll | RightsEditOwn;
|
||||
if ([roles containsObject: SOGoRole_ObjectViewer])
|
||||
rights |= RightsReadItems;
|
||||
if ([roles containsObject: SOGoRole_FolderCreator])
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#import <Mailer/NSData+Mail.h>
|
||||
#import <Mailer/SOGoMailBodyPart.h>
|
||||
#import <Mailer/SOGoMailObject.h>
|
||||
#import <Mailer/NSDictionary+Mail.h>
|
||||
|
||||
#import "Codepages.h"
|
||||
#import "NSData+MAPIStore.h"
|
||||
@@ -196,7 +197,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
count1 = [keys indexOfObject: data1];
|
||||
data2 = [entry2 objectForKey: @"mimeType"];
|
||||
count2 = [keys indexOfObject: data2];
|
||||
|
||||
|
||||
if (count1 == count2)
|
||||
{
|
||||
data1 = [entry1 objectForKey: @"key"];
|
||||
@@ -339,7 +340,6 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
wrapperWithICalEvent: event
|
||||
andUser: [context activeUser]
|
||||
andSenderEmail: senderEmail
|
||||
inTimeZone: [[self userContext] timeZone]
|
||||
withConnectionInfo: [context connectionInfo]];
|
||||
[appointmentWrapper retain];
|
||||
}
|
||||
@@ -521,6 +521,9 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
NSUInteger colIdx;
|
||||
NSString *stringValue;
|
||||
|
||||
/* As specified in [MS-OXCMAIL] 2.2.3.2.6.1, if there are three
|
||||
or less characters followed by a colon at the beginning of
|
||||
the subject, we can assume that's the subject prefix */
|
||||
subject = [self subject];
|
||||
colIdx = [subject rangeOfString: @":"].location;
|
||||
if (colIdx != NSNotFound && colIdx < 4)
|
||||
@@ -529,24 +532,52 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
else
|
||||
stringValue = @"";
|
||||
*data = [stringValue asUnicodeInMemCtx: memCtx];
|
||||
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
- (int) getPidTagNormalizedSubject: (void **) data
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
NSString *subject;
|
||||
NSUInteger colIdx;
|
||||
NSString *stringValue;
|
||||
NSString *stringValue, *subject;
|
||||
NSUInteger quoteStartIdx, quoteEndIdx, colIdx;
|
||||
NSRange quoteRange;
|
||||
|
||||
if (!headerSetup)
|
||||
[self _fetchHeaderData];
|
||||
|
||||
subject = [self subject];
|
||||
colIdx = [subject rangeOfString: @":"].location;
|
||||
if (colIdx != NSNotFound && colIdx < 4)
|
||||
stringValue = [[subject substringFromIndex: colIdx + 1]
|
||||
stringByTrimmingLeadSpaces];
|
||||
if (mailIsMeetingRequest)
|
||||
{
|
||||
|
||||
/* SOGo "spices up" the invitation/update mail's subject, but
|
||||
the client uses it to name the attendee's event, so we keep
|
||||
only what's inside the quotes */
|
||||
quoteStartIdx = [subject rangeOfString: @"\""].location;
|
||||
quoteEndIdx = [subject rangeOfString: @"\""
|
||||
options: NSBackwardsSearch].location;
|
||||
if (quoteStartIdx != NSNotFound
|
||||
&& quoteEndIdx != NSNotFound
|
||||
&& quoteStartIdx != quoteEndIdx)
|
||||
{
|
||||
quoteRange = NSMakeRange(quoteStartIdx + 1, quoteEndIdx - quoteStartIdx - 1);
|
||||
stringValue = [subject substringWithRange: quoteRange];
|
||||
}
|
||||
else stringValue = subject;
|
||||
}
|
||||
else
|
||||
stringValue = subject;
|
||||
{
|
||||
|
||||
/* As specified in [MS-OXCMAIL] 2.2.3.2.6.1, if there are three
|
||||
or less characters followed by a colon at the beginning of
|
||||
the subject, we can assume that's the subject prefix */
|
||||
colIdx = [subject rangeOfString: @":"].location;
|
||||
if (colIdx != NSNotFound && colIdx < 4)
|
||||
stringValue = [[subject substringFromIndex: colIdx + 1]
|
||||
stringByTrimmingLeadSpaces];
|
||||
else
|
||||
stringValue = subject;
|
||||
}
|
||||
if (!stringValue)
|
||||
stringValue = @"";
|
||||
*data = [stringValue asUnicodeInMemCtx: memCtx];
|
||||
@@ -624,7 +655,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
NSDictionary *coreInfos;
|
||||
NSArray *flags;
|
||||
unsigned int v = 0;
|
||||
|
||||
|
||||
coreInfos = [sogoObject fetchCoreInfos];
|
||||
flags = [coreInfos objectForKey: @"flags"];
|
||||
|
||||
@@ -636,7 +667,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
if ([[self attachmentKeys]
|
||||
count] > 0)
|
||||
v |= MSGFLAG_HASATTACH;
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, v);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -656,7 +687,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
v = 2;
|
||||
else
|
||||
v = 0;
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, v);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -668,15 +699,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
NSDictionary *coreInfos;
|
||||
NSArray *flags;
|
||||
unsigned int v;
|
||||
|
||||
|
||||
coreInfos = [sogoObject fetchCoreInfos];
|
||||
|
||||
|
||||
flags = [coreInfos objectForKey: @"flags"];
|
||||
if ([flags containsObject: @"flagged"])
|
||||
v = 6;
|
||||
else
|
||||
v = 0;
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, v);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -755,7 +786,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
if ([ngAddress isKindOfClass: [NGMailAddress class]])
|
||||
{
|
||||
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.
|
||||
@@ -779,7 +810,6 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
NSDictionary *contactInfos;
|
||||
NGMailAddress *ngAddress;
|
||||
NSData *entryId;
|
||||
struct ldb_context *samCtx;
|
||||
int rc;
|
||||
|
||||
if (fullMail)
|
||||
@@ -802,14 +832,13 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
if (contactInfos)
|
||||
{
|
||||
username = [contactInfos objectForKey: @"sAMAccountName"];
|
||||
samCtx = [[self context] connectionInfo]->sam_ctx;
|
||||
entryId = MAPIStoreInternalEntryId (samCtx, username);
|
||||
entryId = MAPIStoreInternalEntryId([[self context] connectionInfo], username);
|
||||
}
|
||||
else
|
||||
entryId = MAPIStoreExternalEntryId (cn, email);
|
||||
|
||||
*data = [entryId asBinaryInMemCtx: memCtx];
|
||||
|
||||
|
||||
rc = MAPISTORE_SUCCESS;
|
||||
}
|
||||
else
|
||||
@@ -966,15 +995,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
{
|
||||
uint32_t v;
|
||||
NSString *s;
|
||||
|
||||
|
||||
s = [[sogoObject mailHeaders] objectForKey: @"x-priority"];
|
||||
v = 0x1;
|
||||
|
||||
|
||||
if ([s hasPrefix: @"1"]) v = 0x2;
|
||||
else if ([s hasPrefix: @"2"]) v = 0x2;
|
||||
else if ([s hasPrefix: @"4"]) v = 0x0;
|
||||
else if ([s hasPrefix: @"5"]) v = 0x0;
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, v);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -1163,14 +1192,14 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
|
||||
if (!headerSetup)
|
||||
[self _fetchHeaderData];
|
||||
|
||||
|
||||
if ([headerMimeType isEqualToString: @"text/plain"])
|
||||
format = EDITOR_FORMAT_PLAINTEXT;
|
||||
else if ([headerMimeType isEqualToString: @"text/html"])
|
||||
format = EDITOR_FORMAT_HTML;
|
||||
else
|
||||
format = 0; /* EDITOR_FORMAT_DONTKNOW */
|
||||
|
||||
|
||||
*data = MAPILongValue (memCtx, format);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
@@ -1446,11 +1475,9 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
NSData *entryId;
|
||||
NSDictionary *contactInfos;
|
||||
SOGoUserManager *mgr;
|
||||
struct ldb_context *samCtx;
|
||||
struct mapistore_message *msgData;
|
||||
struct mapistore_message_recipient *recipient;
|
||||
|
||||
samCtx = [[self context] connectionInfo]->sam_ctx;
|
||||
[super getMessageData: &msgData inMemCtx: memCtx];
|
||||
|
||||
if (!headerSetup)
|
||||
@@ -1504,7 +1531,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
{
|
||||
username = [contactInfos objectForKey: @"sAMAccountName"];
|
||||
recipient->username = [username asUnicodeInMemCtx: msgData];
|
||||
entryId = MAPIStoreInternalEntryId (samCtx, username);
|
||||
entryId = MAPIStoreInternalEntryId ([[self context] connectionInfo], username);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1517,7 +1544,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
p = 0;
|
||||
recipient->data = talloc_array (msgData, void *, msgData->columns->cValues);
|
||||
memset (recipient->data, 0, msgData->columns->cValues * sizeof (void *));
|
||||
|
||||
|
||||
// PR_OBJECT_TYPE = MAPI_MAILUSER (see MAPI_OBJTYPE)
|
||||
recipient->data[p] = MAPILongValue (msgData, MAPI_MAILUSER);
|
||||
p++;
|
||||
@@ -1525,7 +1552,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
// PR_DISPLAY_TYPE = DT_MAILUSER (see MS-NSPI)
|
||||
recipient->data[p] = MAPILongValue (msgData, 0);
|
||||
p++;
|
||||
|
||||
|
||||
// PR_7BIT_DISPLAY_NAME_UNICODE
|
||||
recipient->data[p] = [cn asUnicodeInMemCtx: msgData];
|
||||
p++;
|
||||
@@ -1533,7 +1560,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
// PR_SMTP_ADDRESS_UNICODE
|
||||
recipient->data[p] = [email asUnicodeInMemCtx: msgData];
|
||||
p++;
|
||||
|
||||
|
||||
// PR_SEND_INTERNET_ENCODING = 0x00060000 (plain text, see OXCMAIL)
|
||||
recipient->data[p] = MAPILongValue (msgData, 0x00060000);
|
||||
p++;
|
||||
@@ -1566,12 +1593,9 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
withPrefix: (NSString *) keyPrefix
|
||||
{
|
||||
NSArray *parts;
|
||||
NSDictionary *parameters;
|
||||
NSUInteger count, max;
|
||||
|
||||
parameters = [[bodyInfo objectForKey: @"disposition"]
|
||||
objectForKey: @"parameterList"];
|
||||
if ([[parameters objectForKey: @"filename"] length] > 0)
|
||||
if ([[bodyInfo filename] length] > 0)
|
||||
{
|
||||
if ([keyPrefix length] == 0)
|
||||
keyPrefix = @"0";
|
||||
@@ -1645,15 +1669,13 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
return attachment;
|
||||
}
|
||||
|
||||
- (int) setReadFlag: (uint8_t) flag
|
||||
- (enum mapistore_error) setReadFlag: (uint8_t) flag
|
||||
{
|
||||
NSString *imapFlag = @"\\Seen";
|
||||
|
||||
/* TODO: notifications should probably be emitted from here */
|
||||
if (flag & CLEAR_READ_FLAG)
|
||||
[sogoObject removeFlags: imapFlag];
|
||||
[properties setObject: [NSNumber numberWithBool: NO] forKey: @"read_flag_set"];
|
||||
else
|
||||
[sogoObject addFlags: imapFlag];
|
||||
[properties setObject: [NSNumber numberWithBool: YES] forKey: @"read_flag_set"];
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
@@ -1694,9 +1716,12 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void) save: (TALLOC_CTX *) memCtx
|
||||
- (void) save: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
BOOL modified = NO;
|
||||
BOOL seen, storedSeenFlag;
|
||||
NSNumber *value;
|
||||
NSString *imapFlag = @"\\Seen";
|
||||
|
||||
value = [properties objectForKey: MAPIPropertyKey (PR_FLAG_STATUS)];
|
||||
if (value)
|
||||
@@ -1706,8 +1731,35 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
[sogoObject addFlags: @"\\Flagged"];
|
||||
else /* 0: unflagged, 1: follow up complete */
|
||||
[sogoObject removeFlags: @"\\Flagged"];
|
||||
|
||||
modified = YES;
|
||||
}
|
||||
|
||||
/* Manage seen flag on save */
|
||||
value = [properties objectForKey: @"read_flag_set"];
|
||||
if (value)
|
||||
{
|
||||
seen = [value boolValue];
|
||||
storedSeenFlag = [[[sogoObject fetchCoreInfos] objectForKey: @"flags"] containsObject: @"seen"];
|
||||
/* We modify the flags anyway to generate a new change number */
|
||||
if (seen)
|
||||
{
|
||||
if (storedSeenFlag)
|
||||
[sogoObject removeFlags: imapFlag];
|
||||
[sogoObject addFlags: imapFlag];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!storedSeenFlag)
|
||||
[sogoObject addFlags: imapFlag];
|
||||
[sogoObject removeFlags: imapFlag];
|
||||
}
|
||||
modified = YES;
|
||||
}
|
||||
|
||||
if (modified)
|
||||
[(MAPIStoreMailFolder *)[self container] synchroniseCache];
|
||||
|
||||
if (mailIsSharingObject)
|
||||
[[self _sharingObject] saveWithMessage: self
|
||||
andSOGoObject: sogoObject];
|
||||
|
||||
@@ -161,15 +161,30 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK;
|
||||
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
|
||||
//[self logWithFormat: @" modseq: %.16lx", [modseq unsignedLongLongValue]];
|
||||
if (modseq)
|
||||
modseq = [NSNumber numberWithUnsignedLongLong:
|
||||
[modseq unsignedLongLongValue] + 1];
|
||||
{
|
||||
if (res->relop == RELOP_GT)
|
||||
modseq = [NSNumber numberWithUnsignedLongLong:
|
||||
[modseq unsignedLongLongValue] + 1];
|
||||
|
||||
}
|
||||
else
|
||||
modseq = [NSNumber numberWithUnsignedLongLong: 0];
|
||||
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"MODSEQ"
|
||||
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
|
||||
value: modseq];
|
||||
[*qualifier autorelease];
|
||||
rc = MAPIRestrictionStateNeedsEval;
|
||||
|
||||
if (res->relop == RELOP_GT || res->relop == RELOP_GE)
|
||||
{
|
||||
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"MODSEQ"
|
||||
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
|
||||
value: modseq];
|
||||
[*qualifier autorelease];
|
||||
rc = MAPIRestrictionStateNeedsEval;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Ignore other operations as IMAP only support MODSEQ >= X */
|
||||
[self warnWithFormat: @"Ignoring '%@' as only supported operators are > and >=",
|
||||
NSStringFromSelector ([self operatorFromRestrictionOperator: res->relop])];
|
||||
rc = MAPIRestrictionStateAlwaysTrue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
#import <NGExtensions/NGHashMap.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSObject+Values.h>
|
||||
#import <NGExtensions/NSString+Encoding.h>
|
||||
#import <NGMime/NGMimeBodyPart.h>
|
||||
#import <NGMime/NGMimeMultipartBody.h>
|
||||
@@ -166,9 +167,9 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
|
||||
|
||||
- (BOOL) hasContentId
|
||||
{
|
||||
return ([properties
|
||||
objectForKey: MAPIPropertyKey (PR_ATTACH_CONTENT_ID_UNICODE)]
|
||||
!= nil);
|
||||
NSString *contentId = [properties
|
||||
objectForKey: MAPIPropertyKey (PR_ATTACH_CONTENT_ID_UNICODE)];
|
||||
return contentId && [contentId length] > 0;
|
||||
}
|
||||
|
||||
- (NGMimeBodyPart *) asMIMEBodyPart
|
||||
@@ -232,7 +233,7 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
|
||||
[map addObject: contentDisposition forKey: @"content-disposition"];
|
||||
contentId = [properties
|
||||
objectForKey: MAPIPropertyKey (PR_ATTACH_CONTENT_ID_UNICODE)];
|
||||
if (contentId)
|
||||
if (contentId && [contentId length] > 0)
|
||||
[map setObject: [NSString stringWithFormat: @"<%@>", contentId]
|
||||
forKey: @"content-id"];
|
||||
bodyPart = [NGMimeBodyPart bodyPartWithHeader: map];
|
||||
@@ -285,7 +286,7 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
|
||||
version = [properties objectForKey: @"version"];
|
||||
|
||||
return (version
|
||||
? exchange_globcnt ([version unsignedLongLongValue])
|
||||
? [version unsignedLongLongValue]
|
||||
: ULLONG_MAX);
|
||||
}
|
||||
|
||||
@@ -337,13 +338,10 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
|
||||
NSData *entryId;
|
||||
NSDictionary *allRecipients, *dict, *contactInfos;
|
||||
SOGoUserManager *mgr;
|
||||
struct ldb_context *samCtx;
|
||||
struct mapistore_message *msgData;
|
||||
struct mapistore_message_recipient *recipient;
|
||||
enum ulRecipClass type;
|
||||
|
||||
samCtx = [[self context] connectionInfo]->sam_ctx;
|
||||
|
||||
// [super getMessageData: &msgData inMemCtx: memCtx];
|
||||
|
||||
msgData = talloc_zero (memCtx, struct mapistore_message);
|
||||
@@ -388,7 +386,7 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
|
||||
{
|
||||
username = [contactInfos objectForKey: @"sAMAccountName"];
|
||||
recipient->username = [username asUnicodeInMemCtx: msgData];
|
||||
entryId = MAPIStoreInternalEntryId (samCtx, username);
|
||||
entryId = MAPIStoreInternalEntryId ([[self context] connectionInfo], username);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -681,6 +679,14 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
|
||||
|
||||
if (!fromResolved)
|
||||
{
|
||||
TALLOC_CTX *local_mem_ctx;
|
||||
local_mem_ctx = talloc_new(NULL);
|
||||
if (!local_mem_ctx)
|
||||
{
|
||||
NSLog (@"%s: Out of memory", __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
NSLog (@"Message without an orig from, try to guess it from PidTagSenderEntryId");
|
||||
senderEntryId = [mailProperties objectForKey: MAPIPropertyKey (PR_SENDER_ENTRYID)];
|
||||
if (senderEntryId)
|
||||
@@ -694,12 +700,12 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
|
||||
|
||||
bin32.cb = [senderEntryId length];
|
||||
bin32.lpb = (uint8_t *) [senderEntryId bytes];
|
||||
addrBookEntryId = get_AddressBookEntryId (connInfo->sam_ctx, &bin32);
|
||||
addrBookEntryId = get_AddressBookEntryId (local_mem_ctx, &bin32);
|
||||
if (addrBookEntryId && [[NSString stringWithGUID: &addrBookEntryId->ProviderUID]
|
||||
hasSuffix: @"08002b2fe182"])
|
||||
{
|
||||
/* TODO: better way to distinguish local and other ones */
|
||||
username = MAPIStoreSamDBUserAttribute (connInfo->sam_ctx, @"legacyExchangeDN",
|
||||
username = MAPIStoreSamDBUserAttribute (connInfo, @"legacyExchangeDN",
|
||||
[NSString stringWithUTF8String: addrBookEntryId->X500DN], @"sAMAccountName");
|
||||
if (username)
|
||||
{
|
||||
@@ -720,7 +726,7 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
|
||||
/* Try with One-Off EntryId */
|
||||
struct OneOffEntryId *oneOffEntryId;
|
||||
|
||||
oneOffEntryId = get_OneOffEntryId (connInfo->sam_ctx, &bin32);
|
||||
oneOffEntryId = get_OneOffEntryId (local_mem_ctx, &bin32);
|
||||
if (oneOffEntryId && [[NSString stringWithGUID: &oneOffEntryId->ProviderUID]
|
||||
hasSuffix: @"00dd010f5402"])
|
||||
{
|
||||
@@ -729,9 +735,7 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
|
||||
[fromRecipient setObject: [NSString stringWithUTF8String: oneOffEntryId->EmailAddress.lpszW]
|
||||
forKey: @"email"];
|
||||
}
|
||||
talloc_free (oneOffEntryId);
|
||||
}
|
||||
talloc_free (addrBookEntryId);
|
||||
|
||||
if ([[fromRecipient allKeys] count] > 0)
|
||||
{
|
||||
@@ -741,6 +745,8 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers,
|
||||
}
|
||||
|
||||
}
|
||||
/* Free entryId */
|
||||
talloc_free(local_mem_ctx);
|
||||
}
|
||||
|
||||
if (!recipients)
|
||||
@@ -1007,7 +1013,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
|
||||
- (NGMimeMessage *) _generateMessageWithBcc: (BOOL) withBcc
|
||||
{
|
||||
NSString *contentType;
|
||||
NGMimeMessage *message;
|
||||
NGMimeMessage *message;
|
||||
NGMutableHashMap *headers;
|
||||
id messageBody;
|
||||
|
||||
@@ -1047,6 +1053,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
|
||||
|
||||
- (int) submitWithFlags: (enum SubmitFlags) flags
|
||||
{
|
||||
enum mapistore_error rc = MAPISTORE_SUCCESS;
|
||||
NSDictionary *recipients;
|
||||
NSData *messageData;
|
||||
NSMutableArray *recipientEmails;
|
||||
@@ -1093,7 +1100,10 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
|
||||
withAuthenticator: authenticator
|
||||
inContext: woContext];
|
||||
if (error)
|
||||
[self logWithFormat: @"an error occurred: '%@'", error];
|
||||
{
|
||||
[self errorWithFormat: @"an error occurred: '%@'", error];
|
||||
rc = MAPISTORE_ERR_MSG_SEND;
|
||||
}
|
||||
|
||||
// mapping = [self mapping];
|
||||
// [mapping unregisterURLWithID: [self objectId]];
|
||||
@@ -1105,12 +1115,13 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
|
||||
[self logWithFormat: @"skipping submit of message with class '%@'",
|
||||
msgClass];
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
return rc;
|
||||
}
|
||||
|
||||
- (void) save: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
NSString *folderName, *flag, *newIdString, *messageKey;
|
||||
BOOL updatedMetadata;
|
||||
NSString *folderName, *flag, *newIdString, *messageKey, *changeNumber;
|
||||
NSData *changeKey, *messageData;
|
||||
NGImap4Connection *connection;
|
||||
NGImap4Client *client;
|
||||
@@ -1146,21 +1157,33 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
|
||||
[sogoObject setNameInContainer: messageKey];
|
||||
[mapping registerURL: [self url] withID: mid];
|
||||
|
||||
/* synchronise the cache and update the change key with the one provided
|
||||
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 */
|
||||
/* synchronise the cache and update the predecessor change list
|
||||
with the change key provided 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)
|
||||
[(MAPIStoreMailFolder *) container
|
||||
setChangeKey: changeKey
|
||||
forMessageWithKey: messageKey];
|
||||
{
|
||||
updatedMetadata = [(MAPIStoreMailFolder *) container updatePredecessorChangeListWith: changeKey
|
||||
forMessageWithKey: messageKey];
|
||||
if (!updatedMetadata)
|
||||
[self warnWithFormat: @"Predecessor change list not updated with client data"];
|
||||
}
|
||||
|
||||
/* Update version property (PR_CHANGE_KEY indeed) as it is
|
||||
requested once it is saved */
|
||||
changeNumber = [(MAPIStoreMailFolder *) container changeNumberForMessageUID: newIdString];
|
||||
if (changeNumber)
|
||||
[properties setObject: [NSNumber numberWithUnsignedLongLong: [changeNumber unsignedLongLongValue] >> 16]
|
||||
forKey: @"version"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
withAID: (uint32_t) aid;
|
||||
- (int) getAttachmentTable: (MAPIStoreAttachmentTable **) tablePtr
|
||||
andRowCount: (uint32_t *) countPtr;
|
||||
- (int) setReadFlag: (uint8_t) flag;
|
||||
- (enum mapistore_error) setReadFlag: (uint8_t) flag;
|
||||
- (enum mapistore_error) saveMessage: (TALLOC_CTX *) memCtx;
|
||||
|
||||
- (NSArray *) activeContainerMessageTables;
|
||||
|
||||
@@ -549,11 +549,12 @@ rtf2html (NSData *compressedRTF)
|
||||
}
|
||||
|
||||
[self save: memCtx];
|
||||
/* We make sure that any change-related properties are removes from the
|
||||
/* We make sure that any change-related properties are removed from the
|
||||
properties dictionary, to make sure that related methods will be
|
||||
invoked the next time they are requested. */
|
||||
[properties removeObjectForKey: MAPIPropertyKey (PidTagChangeKey)];
|
||||
[properties removeObjectForKey: MAPIPropertyKey (PidTagChangeNumber)];
|
||||
[properties removeObjectForKey: MAPIPropertyKey (PidTagPredecessorChangeList)];
|
||||
|
||||
if ([container isKindOfClass: MAPIStoreFolderK])
|
||||
{
|
||||
@@ -918,7 +919,7 @@ rtf2html (NSData *compressedRTF)
|
||||
return [self getNo: data inMemCtx: memCtx];;
|
||||
}
|
||||
|
||||
- (int) setReadFlag: (uint8_t) flag
|
||||
- (enum mapistore_error) setReadFlag: (uint8_t) flag
|
||||
{
|
||||
// [self subclassResponsibility: _cmd];
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
else
|
||||
{
|
||||
connInfo = [(MAPIStoreContext *) [container context] connectionInfo];
|
||||
entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, userId);
|
||||
entryId = MAPIStoreInternalEntryId (connInfo, userId);
|
||||
}
|
||||
*data = [entryId asBinaryInMemCtx: memCtx];
|
||||
|
||||
|
||||
@@ -25,12 +25,9 @@
|
||||
|
||||
#include <talloc.h>
|
||||
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalRecurrenceRule.h>
|
||||
|
||||
@class NSTimeZone;
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
|
||||
@class iCalEvent;
|
||||
@class iCalRepeatableEntityObject;
|
||||
@@ -46,7 +43,7 @@
|
||||
fromRecurrencePattern: (struct RecurrencePattern *) rp
|
||||
withExceptions: (struct ExceptionInfo *) exInfos
|
||||
andExceptionCount: (uint16_t) exInfoCount
|
||||
inTimeZone: (NSTimeZone *) tz;
|
||||
inTimeZone: (iCalTimeZone *) tz;
|
||||
|
||||
@end
|
||||
|
||||
@@ -54,7 +51,6 @@
|
||||
|
||||
- (void) fillRecurrencePattern: (struct RecurrencePattern *) rp
|
||||
withEvent: (iCalEvent *) event
|
||||
inTimeZone: (NSTimeZone *) timeZone
|
||||
inMemCtx: (TALLOC_CTX *) memCtx;
|
||||
|
||||
@end
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSSet.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
@@ -35,6 +34,7 @@
|
||||
#import <NGCards/iCalRepeatableEntityObject.h>
|
||||
#import <NGCards/iCalRecurrenceRule.h>
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
#import <NGCards/iCalTimeZonePeriod.h>
|
||||
|
||||
#import "NSDate+MAPIStore.h"
|
||||
#import "MAPIStoreRecurrenceUtils.h"
|
||||
@@ -51,7 +51,7 @@
|
||||
fromRecurrencePattern: (struct RecurrencePattern *) rp
|
||||
withExceptions: (struct ExceptionInfo *) exInfos
|
||||
andExceptionCount: (uint16_t) exInfoCount
|
||||
inTimeZone: (NSTimeZone *) tz
|
||||
inTimeZone: (iCalTimeZone *) tz
|
||||
|
||||
{
|
||||
NSCalendarDate *startDate, *olEndDate, *untilDate, *exDate;
|
||||
@@ -63,7 +63,7 @@
|
||||
iCalWeekOccurrence weekOccurrence;
|
||||
iCalWeekOccurrences dayMaskDays;
|
||||
NSUInteger count, max;
|
||||
NSInteger bySetPos;
|
||||
NSInteger bySetPos, tzOffset;
|
||||
unsigned char maskValue;
|
||||
|
||||
[entity removeAllRecurrenceRules];
|
||||
@@ -242,9 +242,10 @@
|
||||
{
|
||||
/* The OriginalStartDate is in local time */
|
||||
exDate = [NSDate dateFromMinutesSince1601: exInfos[count].OriginalStartDate];
|
||||
tzOffset = -[[tz periodForDate: exDate] secondsOffsetFromGMT];
|
||||
exDate = [exDate dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: - [tz secondsFromGMT]];
|
||||
seconds: tzOffset];
|
||||
[exceptionDates removeObject: exDate];
|
||||
}
|
||||
}
|
||||
@@ -263,7 +264,6 @@
|
||||
|
||||
- (void) fillRecurrencePattern: (struct RecurrencePattern *) rp
|
||||
withEvent: (iCalEvent *) event
|
||||
inTimeZone: (NSTimeZone *) timeZone
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
iCalRecurrenceFrequency freq;
|
||||
@@ -279,10 +279,8 @@
|
||||
NSMutableArray *deletedDates, *modifiedDates;
|
||||
|
||||
startDate = [event firstRecurrenceStartDate];
|
||||
[startDate setTimeZone: timeZone];
|
||||
endDate = [event lastPossibleRecurrenceStartDate];
|
||||
[endDate setTimeZone: timeZone];
|
||||
|
||||
|
||||
rp->ReaderVersion = 0x3004;
|
||||
rp->WriterVersion = 0x3004;
|
||||
|
||||
|
||||
+46
-44
@@ -64,11 +64,11 @@ static BOOL initialization_done = NO;
|
||||
} \
|
||||
OC_DEBUG(5, "[SOGo] --->");
|
||||
|
||||
#define NS_CURRENT_THREAD_TRY_UNREGISTER() \
|
||||
#define NS_CURRENT_THREAD_TRY_UNREGISTER(rc) \
|
||||
if (__nsrct_thread_registered) { \
|
||||
GSUnregisterCurrentThread(); \
|
||||
} \
|
||||
OC_DEBUG(6, "[SOGo] <---");
|
||||
OC_DEBUG(6, "[SOGo] <--- [%s]", mapistore_errstr (rc));
|
||||
|
||||
#define TRYCATCH_START @try {
|
||||
#define TRYCATCH_END(pool) \
|
||||
@@ -76,7 +76,7 @@ static BOOL initialization_done = NO;
|
||||
enum mapistore_error ret = sogo_backend_handle_objc_exception(e, __PRETTY_FUNCTION__, __LINE__); \
|
||||
mapiapp_cleanup(); \
|
||||
[pool release]; \
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(); \
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(ret); \
|
||||
return ret; \
|
||||
} \
|
||||
mapiapp_cleanup();
|
||||
@@ -253,7 +253,7 @@ sogo_backend_create_context(TALLOC_CTX *mem_ctx,
|
||||
rc = MAPISTORE_ERROR;
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -291,7 +291,7 @@ sogo_backend_create_root_folder (const char *username,
|
||||
rc = MAPISTORE_ERROR;
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -322,7 +322,7 @@ sogo_backend_list_contexts(const char *username, struct indexing_context *indexi
|
||||
rc = MAPISTORE_ERROR;
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -363,7 +363,7 @@ sogo_context_get_path(void *backend_object, TALLOC_CTX *mem_ctx,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -397,7 +397,7 @@ sogo_context_get_root_folder(void *backend_object, TALLOC_CTX *mem_ctx,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -439,7 +439,7 @@ sogo_folder_open_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -480,7 +480,7 @@ sogo_folder_create_folder(void *folder_object, TALLOC_CTX *mem_ctx,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -519,7 +519,7 @@ sogo_folder_delete(void *folder_object)
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -549,7 +549,7 @@ sogo_folder_get_child_count(void *folder_object, enum mapistore_table_type table
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -588,7 +588,7 @@ sogo_folder_open_message(void *folder_object,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -627,7 +627,7 @@ sogo_folder_create_message(void *folder_object,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -657,7 +657,7 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags)
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -674,6 +674,7 @@ sogo_folder_move_copy_messages(void *folder_object,
|
||||
uint32_t mid_count,
|
||||
uint64_t *src_mids, uint64_t *t_mids,
|
||||
struct Binary_r **target_change_keys,
|
||||
struct Binary_r **target_predecessor_change_lists,
|
||||
uint8_t want_copy)
|
||||
{
|
||||
MAPIStoreFolder *sourceFolder, *targetFolder;
|
||||
@@ -698,12 +699,13 @@ sogo_folder_move_copy_messages(void *folder_object,
|
||||
fromFolder: sourceFolder
|
||||
withMIDs: t_mids
|
||||
andChangeKeys: target_change_keys
|
||||
andPredecessorChangeLists: target_predecessor_change_lists
|
||||
wantCopy: want_copy
|
||||
inMemCtx: mem_ctx];
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -751,7 +753,7 @@ sogo_folder_move_folder(void *folder_object, void *target_folder_object,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -793,7 +795,7 @@ sogo_folder_copy_folder(void *folder_object, void *target_folder_object, TALLOC_
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -829,7 +831,7 @@ sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -867,7 +869,7 @@ sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -901,7 +903,7 @@ sogo_folder_modify_permissions(void *folder_object, uint8_t flags,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -932,7 +934,7 @@ sogo_folder_preload_message_bodies(void *folder_object, enum mapistore_table_typ
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -965,8 +967,8 @@ sogo_message_get_message_data(void *message_object,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
rc = MAPISTORE_SUCCESS;
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -999,7 +1001,7 @@ sogo_message_create_attachment (void *message_object, TALLOC_CTX *mem_ctx, void
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1033,7 +1035,7 @@ sogo_message_open_attachment (void *message_object, TALLOC_CTX *mem_ctx,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1067,7 +1069,7 @@ sogo_message_get_attachment_table (void *message_object, TALLOC_CTX *mem_ctx, vo
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1102,7 +1104,7 @@ sogo_message_modify_recipients (void *message_object,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1118,7 +1120,7 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
|
||||
struct MAPIStoreTallocWrapper *wrapper;
|
||||
NSAutoreleasePool *pool;
|
||||
MAPIStoreMessage *message;
|
||||
int rc;
|
||||
enum mapistore_error rc;
|
||||
|
||||
if (message_object)
|
||||
{
|
||||
@@ -1132,7 +1134,7 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1162,7 +1164,7 @@ sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx)
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1192,7 +1194,7 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags)
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1232,7 +1234,7 @@ sogo_message_attachment_open_embedded_message (void *attachment_object,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1270,7 +1272,7 @@ sogo_message_attachment_create_embedded_message (void *attachment_object,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1300,7 +1302,7 @@ static enum mapistore_error sogo_table_get_available_properties(void *table_obje
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1331,7 +1333,7 @@ sogo_table_set_columns (void *table_object, uint16_t count, enum MAPITAGS *prope
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1364,7 +1366,7 @@ sogo_table_set_restrictions (void *table_object, struct mapi_SRestriction *restr
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1397,7 +1399,7 @@ sogo_table_set_sort_order (void *table_object, struct SSortOrderSet *sort_order,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1430,7 +1432,7 @@ sogo_table_get_row (void *table_object, TALLOC_CTX *mem_ctx,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1463,7 +1465,7 @@ sogo_table_get_row_count (void *table_object,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1493,8 +1495,8 @@ sogo_table_handle_destructor (void *table_object, uint32_t handle_id)
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
rc = MAPISTORE_SUCCESS;
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1525,7 +1527,7 @@ static enum mapistore_error sogo_properties_get_available_properties(void *objec
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1560,7 +1562,7 @@ sogo_properties_get_properties (void *object,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1590,7 +1592,7 @@ sogo_properties_set_properties (void *object, struct SRow *aRow)
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1644,7 +1646,7 @@ sogo_manager_generate_uri (TALLOC_CTX *mem_ctx,
|
||||
TRYCATCH_END(pool)
|
||||
|
||||
[pool release];
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER();
|
||||
NS_CURRENT_THREAD_TRY_UNREGISTER(MAPISTORE_SUCCESS);
|
||||
|
||||
return MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -197,6 +197,7 @@ static Class MAPIStoreFolderK;
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
int rc;
|
||||
struct mapistore_connection_info *connInfo;
|
||||
uint64_t obVersion;
|
||||
|
||||
obVersion = [self objectVersion];
|
||||
@@ -204,8 +205,9 @@ static Class MAPIStoreFolderK;
|
||||
rc = MAPISTORE_ERR_NOT_FOUND;
|
||||
else
|
||||
{
|
||||
connInfo = [[self context] connectionInfo];
|
||||
*data = MAPILongLongValue (memCtx, ((obVersion << 16)
|
||||
| 0x0001));
|
||||
| connInfo->repl_id));
|
||||
rc = MAPISTORE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,13 +25,13 @@
|
||||
|
||||
@class NSString;
|
||||
|
||||
struct ldb_context;
|
||||
#include <mapistore/mapistore.h>
|
||||
|
||||
NSString *MAPIStoreSamDBUserAttribute (struct ldb_context *samCtx,
|
||||
NSString *MAPIStoreSamDBUserAttribute (struct mapistore_connection_info *connInfo,
|
||||
NSString *userKey,
|
||||
NSString *value,
|
||||
NSString *attributeName);
|
||||
NSData *MAPIStoreInternalEntryId (struct ldb_context *, NSString *username);
|
||||
NSData *MAPIStoreInternalEntryId (struct mapistore_connection_info *connInfo, NSString *username);
|
||||
NSData *MAPIStoreExternalEntryId (NSString *cn, NSString *email);
|
||||
|
||||
#endif /* MAPISTORESAMDBUTILS_H */
|
||||
@@ -24,13 +24,18 @@
|
||||
#import <Foundation/NSString.h>
|
||||
#include <talloc.h>
|
||||
#include <ldb.h>
|
||||
#include <libmapiproxy.h>
|
||||
#include <samba/version.h>
|
||||
|
||||
#import "NSData+MAPIStore.h"
|
||||
|
||||
#import "MAPIStoreSamDBUtils.h"
|
||||
|
||||
|
||||
|
||||
|
||||
NSString *
|
||||
MAPIStoreSamDBUserAttribute (struct ldb_context *samCtx,
|
||||
MAPIStoreSamDBUserAttribute (struct mapistore_connection_info *connInfo,
|
||||
NSString *userKey,
|
||||
NSString *value,
|
||||
NSString *attributeName)
|
||||
@@ -48,10 +53,20 @@ MAPIStoreSamDBUserAttribute (struct ldb_context *samCtx,
|
||||
attrs[0] = [attributeName UTF8String];
|
||||
searchFormat
|
||||
= [NSString stringWithFormat: @"(&(objectClass=user)(%@=%%s))", userKey];
|
||||
ret = ldb_search (samCtx, memCtx, &res, ldb_get_default_basedn(samCtx),
|
||||
#if SAMBA_VERSION_MAJOR <= 4 && SAMBA_VERSION_MINOR < 3
|
||||
ret = ldb_search (connInfo->sam_ctx, memCtx, &res,
|
||||
ldb_get_default_basedn(connInfo->sam_ctx),
|
||||
LDB_SCOPE_SUBTREE, attrs,
|
||||
[searchFormat UTF8String],
|
||||
[value UTF8String]);
|
||||
#else
|
||||
ret = safe_ldb_search (&connInfo->sam_ctx, memCtx, &res,
|
||||
ldb_get_default_basedn(connInfo->sam_ctx),
|
||||
LDB_SCOPE_SUBTREE, attrs,
|
||||
[searchFormat UTF8String],
|
||||
[value UTF8String]);
|
||||
#endif
|
||||
|
||||
if (ret == LDB_SUCCESS && res->count == 1)
|
||||
{
|
||||
result = ldb_msg_find_attr_as_string (res->msgs[0], attrs[0], NULL);
|
||||
@@ -65,7 +80,7 @@ MAPIStoreSamDBUserAttribute (struct ldb_context *samCtx,
|
||||
}
|
||||
|
||||
NSData *
|
||||
MAPIStoreInternalEntryId (struct ldb_context *samCtx, NSString *username)
|
||||
MAPIStoreInternalEntryId (struct mapistore_connection_info *connInfo, NSString *username)
|
||||
{
|
||||
static const uint8_t const providerUid[] = { 0xdc, 0xa7, 0x40, 0xc8,
|
||||
0xc0, 0x42, 0x10, 0x1a,
|
||||
@@ -82,7 +97,7 @@ MAPIStoreInternalEntryId (struct ldb_context *samCtx, NSString *username)
|
||||
type: 32
|
||||
X500DN: variable */
|
||||
|
||||
legacyDN = MAPIStoreSamDBUserAttribute (samCtx, @"sAMAccountName", username,
|
||||
legacyDN = MAPIStoreSamDBUserAttribute (connInfo, @"sAMAccountName", username,
|
||||
@"legacyExchangeDN");
|
||||
if (legacyDN)
|
||||
{
|
||||
|
||||
@@ -107,11 +107,11 @@
|
||||
if ([roles containsObject: SOGoRole_ObjectCreator])
|
||||
rights |= RightsCreateItems;
|
||||
if ([roles containsObject: SOGoRole_ObjectEraser])
|
||||
rights |= RightsDeleteAll;
|
||||
rights |= RightsDeleteAll | RightsDeleteOwn;
|
||||
if ([roles containsObject: SOGoCalendarRole_PublicModifier]
|
||||
&& [roles containsObject: SOGoCalendarRole_PrivateModifier]
|
||||
&& [roles containsObject: SOGoCalendarRole_ConfidentialModifier])
|
||||
rights |= RightsReadItems | RightsEditAll;
|
||||
rights |= RightsReadItems | RightsEditAll | RightsEditOwn;
|
||||
else if ([roles containsObject: SOGoCalendarRole_PublicViewer]
|
||||
&& [roles containsObject: SOGoCalendarRole_PrivateViewer]
|
||||
&& [roles containsObject: SOGoCalendarRole_ConfidentialViewer])
|
||||
|
||||
@@ -531,7 +531,7 @@
|
||||
}
|
||||
[vToDo setTimeStampAsDate: now];
|
||||
|
||||
[sogoObject saveComponent: vCalendar];
|
||||
[sogoObject saveCalendar: vCalendar];
|
||||
|
||||
[self updateVersions];
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ NSObjectFromSPropValue (const struct SPropValue *value)
|
||||
break;
|
||||
case PT_STRING8:
|
||||
result = (value->value.lpszA
|
||||
? [NSString stringWithUTF8String: value->value.lpszA]
|
||||
? [NSString stringWithUTF8String: (const char *) value->value.lpszA]
|
||||
: (id) @"");
|
||||
break;
|
||||
case PT_SYSTIME:
|
||||
|
||||
@@ -73,6 +73,8 @@ static NSMapTable *contextsTable = nil;
|
||||
[userContext autorelease];
|
||||
[contextsTable setObject: userContext forKey: username];
|
||||
}
|
||||
else
|
||||
[userContext activate];
|
||||
|
||||
return userContext;
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@
|
||||
mvResult = [NSMutableArray arrayWithCapacity: mvString->cValues];
|
||||
for (count = 0; count < mvString->cValues; count++)
|
||||
{
|
||||
subObject = [NSString stringWithUTF8String: mvString->lppszA[count]];
|
||||
subObject = [NSString stringWithUTF8String: (const char *) mvString->lppszA[count]];
|
||||
[mvResult addObject: subObject];
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
|
||||
+ (id) dataWithXID: (const struct XID *) xid;
|
||||
- (struct XID *) asXIDInMemCtx: (void *) memCtx;
|
||||
- (struct SizedXid *) asSizedXidArrayInMemCtx: (void *) memCtx
|
||||
with: (uint32_t *) length;
|
||||
|
||||
+ (id) dataWithChangeKeyGUID: (NSString *) guidString
|
||||
andCnt: (NSData *) globCnt;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import "MAPIStoreTypes.h"
|
||||
#import "NSObject+MAPIStore.h"
|
||||
#import "NSString+MAPIStore.h"
|
||||
|
||||
@@ -29,6 +30,7 @@
|
||||
|
||||
#undef DEBUG
|
||||
#include <stdbool.h>
|
||||
#include <libmapi/libmapi.h>
|
||||
#include <talloc.h>
|
||||
#include <util/time.h>
|
||||
#include <gen_ndr/exchange.h>
|
||||
@@ -136,11 +138,11 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
|
||||
NSMutableData *xidData;
|
||||
struct FlatUID_r flatUID;
|
||||
|
||||
_fillFlatUIDWithGUID (&flatUID, &xid->GUID);
|
||||
_fillFlatUIDWithGUID (&flatUID, &xid->NameSpaceGuid);
|
||||
|
||||
xidData = [NSMutableData dataWithCapacity: 16 + xid->Size];
|
||||
xidData = [NSMutableData dataWithCapacity: 16 + xid->LocalId.length];
|
||||
[xidData appendBytes: flatUID.ab length: 16];
|
||||
[xidData appendBytes: xid->Data length: xid->Size];
|
||||
[xidData appendBytes: xid->LocalId.data length: xid->LocalId.length];
|
||||
|
||||
return xidData;
|
||||
}
|
||||
@@ -156,12 +158,12 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
|
||||
{
|
||||
xid = talloc_zero (memCtx, struct XID);
|
||||
|
||||
[self _extractGUID: &xid->GUID];
|
||||
[self _extractGUID: &xid->NameSpaceGuid];
|
||||
|
||||
xid->Size = max - 16;
|
||||
xid->LocalId.length = max - 16;
|
||||
|
||||
bytes = (uint8_t *) [self bytes];
|
||||
xid->Data = talloc_memdup (xid, (bytes+16), xid->Size);
|
||||
xid->LocalId.data = talloc_memdup (xid, (bytes+16), xid->LocalId.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -172,6 +174,38 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
|
||||
return xid;
|
||||
}
|
||||
|
||||
- (struct SizedXid *) asSizedXidArrayInMemCtx: (void *) memCtx
|
||||
with: (uint32_t *) length
|
||||
{
|
||||
struct Binary_r bin;
|
||||
struct SizedXid *sizedXIDArray;
|
||||
|
||||
bin.cb = [self length];
|
||||
bin.lpb = (uint8_t *)[self bytes];
|
||||
|
||||
sizedXIDArray = get_SizedXidArray(memCtx, &bin, length);
|
||||
if (!sizedXIDArray)
|
||||
{
|
||||
NSLog (@"Impossible to parse SizedXID array");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sizedXIDArray;
|
||||
}
|
||||
|
||||
- (NSComparisonResult) compare: (NSData *) otherGlobCnt
|
||||
{
|
||||
uint64_t globCnt = 0, oGlobCnt = 0;
|
||||
|
||||
if ([self length] > 0)
|
||||
globCnt = *(uint64_t *) [self bytes];
|
||||
|
||||
if ([otherGlobCnt length] > 0)
|
||||
oGlobCnt = *(uint64_t *) [otherGlobCnt bytes];
|
||||
|
||||
return MAPICNCompare (globCnt, oGlobCnt, NULL);
|
||||
}
|
||||
|
||||
+ (id) dataWithChangeKeyGUID: (NSString *) guidString
|
||||
andCnt: (NSData *) globCnt;
|
||||
{
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
|
||||
- (BOOL) isNever; /* occurs on 4500-12-31 */
|
||||
|
||||
+ (NSCalendarDate *) dateFromSystemTime: (struct SYSTEMTIME) date
|
||||
andRuleYear: (uint16_t) rYear;
|
||||
@end
|
||||
|
||||
NSComparisonResult NSDateCompare (id date1, id date2, void *);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import "MAPIStoreTypes.h"
|
||||
#import "NSDate+MAPIStore.h"
|
||||
|
||||
#undef DEBUG
|
||||
@@ -48,7 +49,7 @@ _setupRefDate ()
|
||||
refDate = [[NSCalendarDate alloc]
|
||||
initWithYear: 1601 month: 1 day: 1
|
||||
hour: 0 minute: 0 second: 0
|
||||
timeZone: [NSTimeZone timeZoneWithName: @"UTC"]];
|
||||
timeZone: utcTZ];
|
||||
}
|
||||
|
||||
+ (NSCalendarDate *) dateFromMinutesSince1601: (uint32_t) minutes
|
||||
@@ -128,6 +129,64 @@ _setupRefDate ()
|
||||
return [calDate yearOfCommonEra] == 4500;
|
||||
}
|
||||
|
||||
+ (NSCalendarDate *) dateFromSystemTime: (struct SYSTEMTIME) date
|
||||
andRuleYear: (uint16_t) rYear
|
||||
{
|
||||
NSCalendarDate *result;
|
||||
NSInteger daysToDate;
|
||||
NSUInteger firstDayOfWeek, year;
|
||||
|
||||
/* ([MS-OXOCAL] 2.2.1.41.1) When we're provided an absolute date (i.e., it
|
||||
happens once), the SYSTEMTIME structure is enough to fill the date.
|
||||
When we're parsing a SYSTEMTIME field from a time zone rule, however, a
|
||||
relative date can be provided for the peroidicity of its periods. In this
|
||||
scenario, the wYear field is empty and we have to use the wYear field in
|
||||
the parent rule */
|
||||
if (date.wYear != 0)
|
||||
year = date.wYear;
|
||||
else
|
||||
year = rYear;
|
||||
|
||||
/* The wDay field indicates the occurrence of the wDayOfWeek within the month.
|
||||
The 5th occurrence means the last one, even if it is the 4th. */
|
||||
if (date.wDay < 5)
|
||||
{
|
||||
result = [[NSCalendarDate alloc] initWithYear: year month: date.wMonth day: 1
|
||||
hour: date.wHour minute: date.wMinute second: date.wSecond
|
||||
timeZone: utcTZ];
|
||||
[result autorelease];
|
||||
|
||||
firstDayOfWeek = [result dayOfWeek];
|
||||
|
||||
daysToDate = 7 * (date.wDay - 1) + date.wDayOfWeek - firstDayOfWeek;
|
||||
if (date.wDayOfWeek < firstDayOfWeek)
|
||||
daysToDate += 7;
|
||||
|
||||
result = [result dateByAddingYears: 0 months: 0 days: daysToDate
|
||||
hours: 0 minutes: 0
|
||||
seconds: 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
result = [[NSCalendarDate alloc] initWithYear: year month: date.wMonth + 1 day: 1
|
||||
hour: date.wHour minute: date.wMinute second: date.wSecond
|
||||
timeZone: utcTZ];
|
||||
[result autorelease];
|
||||
|
||||
firstDayOfWeek = [result dayOfWeek];
|
||||
|
||||
daysToDate = date.wDayOfWeek - firstDayOfWeek;
|
||||
if (date.wDayOfWeek >= firstDayOfWeek)
|
||||
daysToDate -= 7;
|
||||
|
||||
result = [result dateByAddingYears: 0 months: 0 days: daysToDate
|
||||
hours: 0 minutes: 0
|
||||
seconds: 0];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NSComparisonResult
|
||||
|
||||
+11
-2
@@ -28,6 +28,8 @@
|
||||
//
|
||||
//
|
||||
//
|
||||
@class RTFFontTable;
|
||||
|
||||
@interface RTFHandler : NSObject
|
||||
{
|
||||
NSMapTable *_charsets;
|
||||
@@ -41,6 +43,11 @@
|
||||
|
||||
- (id) initWithData: (NSData *) theData;
|
||||
- (NSMutableData *) parse;
|
||||
|
||||
- (RTFFontTable *) parseFontTable;
|
||||
- (void) mangleInternalStateWithBytesPtr: (const char*) newBytes
|
||||
andCurrentPos: (int) newCurrentPos;
|
||||
|
||||
@end
|
||||
|
||||
//
|
||||
@@ -67,6 +74,7 @@
|
||||
int font_index;
|
||||
int color_index;
|
||||
int start_pos;
|
||||
const unsigned short *charset;
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -77,12 +85,13 @@
|
||||
{
|
||||
@public
|
||||
NSString *family;
|
||||
NSString *charset;
|
||||
unsigned char charset;
|
||||
NSString *name;
|
||||
unsigned int pitch;
|
||||
unsigned int index;
|
||||
}
|
||||
|
||||
- (NSString *) description;
|
||||
@end
|
||||
|
||||
//
|
||||
@@ -96,8 +105,8 @@
|
||||
|
||||
- (void) addFontInfo: (RTFFontInfo *) theFontInfo
|
||||
atIndex: (unsigned int ) theIndex;
|
||||
|
||||
- (RTFFontInfo *) fontInfoAtIndex: (unsigned int ) theIndex;
|
||||
- (NSString *) description;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+728
-295
File diff suppressed because it is too large.
Load diff
@@ -1,8 +1,8 @@
|
||||
/* dbmsgreader.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2011-2012 Inverse inc
|
||||
* 2015 Enrique J. Hernandez
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -33,21 +33,58 @@
|
||||
#import <SOGo/SOGoProductLoader.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
|
||||
#import <libmapi/libmapi.h>
|
||||
|
||||
#import "MAPIStoreUserContext.h"
|
||||
#import <SOGo/SOGoCacheGCSObject.h>
|
||||
|
||||
#import <SOGo/BSONCodec.h>
|
||||
#import "NSObject+PropertyList.h"
|
||||
|
||||
Class MAPIStoreUserContextK, SOGoCacheGCSObjectK;
|
||||
|
||||
Class MAPIStoreUserContextK, SOGoCacheGCSObjectK, NSStringK;
|
||||
|
||||
static void
|
||||
DumpBSONData(NSData *data)
|
||||
{
|
||||
id key, value;
|
||||
NSEnumerator *dictEnum;
|
||||
NSDictionary *dvalue;
|
||||
NSMutableString *outStr;
|
||||
NSUInteger max;
|
||||
|
||||
dvalue = [data BSONValue];
|
||||
[dvalue displayWithIndentation:0];
|
||||
printf("\n");
|
||||
max = [dvalue count];
|
||||
dictEnum = [dvalue keyEnumerator];
|
||||
NSStringK = [NSString class];
|
||||
outStr = [NSMutableString stringWithFormat: @"{ %d items\n", max];
|
||||
while ((key = [dictEnum nextObject]))
|
||||
{
|
||||
uint32_t proptag = 0;
|
||||
if ([key isKindOfClass: NSStringK] && [(NSString *)key intValue] > 0)
|
||||
proptag = [(NSString *)key intValue];
|
||||
|
||||
if (proptag > 0)
|
||||
{
|
||||
const char *propTagName = get_proptag_name (proptag);
|
||||
NSString *propName;
|
||||
|
||||
if (propTagName)
|
||||
propName = [NSString stringWithCString: propTagName
|
||||
encoding: NSUTF8StringEncoding];
|
||||
else
|
||||
propName = [NSString stringWithFormat: @"0x%.4x", [key unsignedLongValue]];
|
||||
|
||||
[outStr appendFormat: @" %@ = ", propName];
|
||||
}
|
||||
else
|
||||
[outStr appendFormat: @" %@ = ", key];
|
||||
|
||||
value = [dvalue objectForKey: key];
|
||||
[outStr appendFormat: @"(%@) %@,\n", NSStringFromClass ([value class]), value];
|
||||
}
|
||||
[outStr appendFormat: @"}\n"];
|
||||
printf ("%s\n", [outStr UTF8String]);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -67,7 +104,7 @@ DbDumpObject (NSString *username, NSString *path)
|
||||
{
|
||||
printf("record found: %p\n", record);
|
||||
content = [[record objectForKey: @"c_content"] dataByDecodingBase64];
|
||||
DumpBSONData(content);
|
||||
DumpBSONData (content);
|
||||
}
|
||||
else
|
||||
NSLog (@"record not found");
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
#import <NGCards/iCalTimeZonePeriod.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
#import <SOGo/SOGoPermissions.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
@@ -70,11 +71,12 @@
|
||||
#include <mapistore/mapistore_nameid.h>
|
||||
|
||||
#import "iCalEvent+MAPIStore.h"
|
||||
#import "iCalTimeZone+MAPIStore.h"
|
||||
|
||||
@implementation iCalEvent (MAPIStoreProperties)
|
||||
|
||||
- (void) _setupEventRecurrence: (NSData *) mapiRecurrenceData
|
||||
inTimeZone: (NSTimeZone *) tz
|
||||
inTimeZone: (iCalTimeZone *) tz
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
struct Binary_r *blob;
|
||||
@@ -250,10 +252,8 @@
|
||||
BOOL isAllDay;
|
||||
iCalDateTime *start, *end;
|
||||
iCalTimeZone *tz;
|
||||
NSTimeZone *userTimeZone;
|
||||
NSString *priority, *class = nil;
|
||||
NSString *priority, *class = nil, *tzDescription = nil;
|
||||
NSUInteger responseStatus = 0;
|
||||
NSInteger tzOffset;
|
||||
SOGoUser *ownerUser;
|
||||
id value;
|
||||
|
||||
@@ -274,7 +274,31 @@
|
||||
[self setAccessClass: @"PUBLIC"];
|
||||
}
|
||||
|
||||
userTimeZone = [userContext timeZone];
|
||||
/* Time zone = PidLidAppointmentTimeZoneDefinitionRecur
|
||||
or PidLidAppointmentTimeZoneDefinition[Start|End]Display */
|
||||
value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentTimeZoneDefinitionStartDisplay)];
|
||||
if (!value)
|
||||
{
|
||||
value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentTimeZoneDefinitionEndDisplay)];
|
||||
if (!value)
|
||||
{
|
||||
/* If PidLidtimeZoneStruct, TZID SHOULD come from PidLidTimeZoneDescription,
|
||||
if PidLidAppointmentTimeZoneDefinition[Start|End]Display it MUST be derived from KeyName
|
||||
(MS-OXCICAL] 2.1.3.1.1.19.1) */
|
||||
value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentTimeZoneDefinitionRecur)];
|
||||
tzDescription = [properties objectForKey: MAPIPropertyKey (PidLidTimeZoneDescription)];
|
||||
}
|
||||
}
|
||||
if (value)
|
||||
{
|
||||
tz = [[iCalTimeZone alloc] iCalTimeZoneFromDefinition: value
|
||||
withDescription: tzDescription
|
||||
inMemCtx: memCtx];
|
||||
}
|
||||
else
|
||||
/* The client is more likely to have the webmail's time zone than any other */
|
||||
tz = [iCalTimeZone timeZoneForName: [[userContext timeZone] name]];
|
||||
[(iCalCalendar *) parent addTimeZone: tz];
|
||||
|
||||
/* CREATED */
|
||||
value = [properties objectForKey: MAPIPropertyKey (PidTagCreationTime)];
|
||||
@@ -306,20 +330,13 @@
|
||||
objectForKey: MAPIPropertyKey (PidLidAppointmentSubType)];
|
||||
if (value)
|
||||
isAllDay = [value boolValue];
|
||||
if (!isAllDay)
|
||||
{
|
||||
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
|
||||
[(iCalCalendar *) parent addTimeZone: tz];
|
||||
}
|
||||
else
|
||||
tz = nil;
|
||||
|
||||
// recurrence-id
|
||||
value
|
||||
= [properties objectForKey: MAPIPropertyKey (PidLidExceptionReplaceTime)];
|
||||
if (value)
|
||||
[self setRecurrenceId: value];
|
||||
|
||||
|
||||
// start
|
||||
value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentStartWhole)];
|
||||
if (!value)
|
||||
@@ -330,15 +347,7 @@
|
||||
[start setTimeZone: tz];
|
||||
if (isAllDay)
|
||||
{
|
||||
/* when user TZ is positive (East) all-day events were not
|
||||
shown properly in SOGo UI. This day delay fixes it */
|
||||
tzOffset = [userTimeZone secondsFromGMTForDate: value];
|
||||
if (tzOffset > 0)
|
||||
{
|
||||
value = [value dateByAddingYears: 0 months: 0 days: 1
|
||||
hours: 0 minutes: 0
|
||||
seconds: 0];
|
||||
}
|
||||
/* All-day events are set in floating time ([MS-OXCICAL] 2.1.3.1.1.20.8) */
|
||||
[start setDate: value];
|
||||
[start setTimeZone: nil];
|
||||
}
|
||||
@@ -356,15 +365,7 @@
|
||||
[end setTimeZone: tz];
|
||||
if (isAllDay)
|
||||
{
|
||||
/* when user TZ is positive (East) all-day events were not
|
||||
shown properly in SOGo UI. This day delay fixes it */
|
||||
tzOffset = [userTimeZone secondsFromGMTForDate: value];
|
||||
if (tzOffset > 0)
|
||||
{
|
||||
value = [value dateByAddingYears: 0 months: 0 days: 1
|
||||
hours: 0 minutes: 0
|
||||
seconds: 0];
|
||||
}
|
||||
/* All-day events are set in floating time ([MS-OXCICAL] 2.1.3.1.1.20.8) */
|
||||
[end setDate: value];
|
||||
[end setTimeZone: nil];
|
||||
}
|
||||
@@ -467,7 +468,7 @@
|
||||
value = [properties
|
||||
objectForKey: MAPIPropertyKey (PidLidAppointmentRecur)];
|
||||
if (value)
|
||||
[self _setupEventRecurrence: value inTimeZone: userTimeZone inMemCtx: memCtx];
|
||||
[self _setupEventRecurrence: value inTimeZone: tz inMemCtx: memCtx];
|
||||
|
||||
/* alarm */
|
||||
[self _setupEventAlarmFromProperties: properties];
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
- (struct Binary_r *) asTimeZoneStructInMemCtx: (TALLOC_CTX *) memCtx;
|
||||
- (struct Binary_r *) asZoneTimeDefinitionWithFlags: (enum TZRuleFlag) flags
|
||||
inMemCtx: (TALLOC_CTX *) memCtx;
|
||||
- (iCalTimeZone *) iCalTimeZoneFromDefinition: (NSData *) value
|
||||
withDescription: (NSString *) description
|
||||
inMemCtx: (TALLOC_CTX *) memCtx;
|
||||
- (NSCalendarDate *) shiftedCalendarDateForDate: (NSCalendarDate *) date;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -23,11 +23,15 @@
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
#import <NGCards/iCalByDayMask.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalTimeZonePeriod.h>
|
||||
#import <NGCards/iCalRecurrenceRule.h>
|
||||
|
||||
#import "NSString+MAPIStore.h"
|
||||
#import "NSData+MAPIStore.h"
|
||||
#import "NSDate+MAPIStore.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@@ -36,6 +40,7 @@
|
||||
#include <libmapi/libmapi.h>
|
||||
|
||||
#import "iCalTimeZone+MAPIStore.h"
|
||||
#import "MAPIStoreTypes.h"
|
||||
|
||||
@interface iCalTimeZonePeriod (MAPIStorePropertiesPrivate)
|
||||
|
||||
@@ -103,18 +108,18 @@
|
||||
{
|
||||
iCalTimeZonePeriod *period;
|
||||
struct TimeZoneStruct tz;
|
||||
int lBias, dlBias;
|
||||
int32_t lBias, dlBias;
|
||||
|
||||
memset (&tz, 0, sizeof (struct TimeZoneStruct));
|
||||
period = [self _mostRecentPeriodWithName: @"STANDARD"];
|
||||
lBias = -[period secondsOffsetFromGMT] / 60;
|
||||
tz.lBias = (uint32_t) lBias;
|
||||
tz.lBias = lBias;
|
||||
[period _fillTZDate: &tz.stStandardDate];
|
||||
period = [self _mostRecentPeriodWithName: @"DAYLIGHT"];
|
||||
if (!period)
|
||||
tz.stStandardDate.wMonth = 0;
|
||||
dlBias = -([period secondsOffsetFromGMT] / 60) - lBias;
|
||||
tz.lDaylightBias = (uint32_t) (dlBias);
|
||||
tz.lDaylightBias = dlBias;
|
||||
[period _fillTZDate: &tz.stDaylightDate];
|
||||
tz.wStandardYear = tz.stStandardDate.wYear;
|
||||
tz.wDaylightYear = tz.stDaylightDate.wYear;
|
||||
@@ -153,18 +158,220 @@
|
||||
period = [self _mostRecentPeriodWithName: @"STANDARD"];
|
||||
rule.wYear = [[period startDate] yearOfCommonEra];
|
||||
lBias = -[period secondsOffsetFromGMT] / 60;
|
||||
rule.lBias = (uint32_t) lBias;
|
||||
rule.lBias = lBias;
|
||||
[period _fillTZDate: &rule.stStandardDate];
|
||||
period = [self _mostRecentPeriodWithName: @"DAYLIGHT"];
|
||||
if (!period)
|
||||
rule.stStandardDate.wMonth = 0;
|
||||
dlBias = -([period secondsOffsetFromGMT] / 60) - lBias;
|
||||
rule.lDaylightBias = (uint32_t) (dlBias);
|
||||
rule.lDaylightBias = dlBias;
|
||||
[period _fillTZDate: &rule.stDaylightDate];
|
||||
|
||||
|
||||
return set_TimeZoneDefinition (memCtx, &definition);
|
||||
}
|
||||
|
||||
- (NSString *) _offsetStringFromOffset: (NSInteger) offset
|
||||
{
|
||||
NSInteger offsetHours, offsetMins;
|
||||
NSString *offsetSign;
|
||||
|
||||
/* The offset format is, eg, "+0200" for 2 hours 0 minutes ahead */
|
||||
if (offset < 0)
|
||||
offsetSign = @"-";
|
||||
else
|
||||
offsetSign = @"+";
|
||||
offsetHours = abs (offset) / 60;
|
||||
offsetMins = abs (offset) % 60;
|
||||
|
||||
return [NSString stringWithFormat: @"%@%d%d%d%d",
|
||||
offsetSign, offsetHours / 10, offsetHours % 10,
|
||||
offsetMins / 10, offsetMins % 10];
|
||||
|
||||
}
|
||||
|
||||
- (NSString *) _rRuleStringFromSystemTime: (struct SYSTEMTIME) date
|
||||
{
|
||||
NSString *result, *byDay;
|
||||
|
||||
/* The conversion tables between the SYSTEMTIME fields and the RRULE ones
|
||||
can be found at [MS-OXCICAL] 2.1.3.2.1 */
|
||||
if (date.wDay == 5)
|
||||
byDay = @"-1";
|
||||
else
|
||||
byDay = [NSString stringWithFormat: @"%d", date.wDay];
|
||||
|
||||
switch (date.wDayOfWeek)
|
||||
{
|
||||
case iCalWeekDaySunday:
|
||||
byDay = [byDay stringByAppendingString: @"SU"];
|
||||
break;
|
||||
case iCalWeekDayMonday:
|
||||
byDay = [byDay stringByAppendingString: @"MO"];
|
||||
break;
|
||||
case iCalWeekDayTuesday:
|
||||
byDay = [byDay stringByAppendingString: @"TU"];
|
||||
break;
|
||||
case iCalWeekDayWednesday:
|
||||
byDay = [byDay stringByAppendingString: @"WE"];
|
||||
break;
|
||||
case iCalWeekDayThursday:
|
||||
byDay = [byDay stringByAppendingString: @"TH"];
|
||||
break;
|
||||
case iCalWeekDayFriday:
|
||||
byDay = [byDay stringByAppendingString: @"FR"];
|
||||
break;
|
||||
case iCalWeekDaySaturday:
|
||||
byDay = [byDay stringByAppendingString: @"SA"];
|
||||
break;
|
||||
}
|
||||
|
||||
result = [NSString stringWithFormat: @"FREQ=YEARLY;BYDAY=%@;BYMONTH=%d", byDay, date.wMonth];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (iCalTimeZone *) iCalTimeZoneFromDefinition: (NSData *) value
|
||||
withDescription: (NSString *) description
|
||||
inMemCtx: (TALLOC_CTX *) memCtx
|
||||
{
|
||||
BOOL daylightDefined = NO, ruleFound = NO;
|
||||
iCalDateTime *daylightStart, *standardStart;
|
||||
iCalRecurrenceRule *daylightRRule, *standardRRule;
|
||||
iCalTimeZone *tz = nil;
|
||||
iCalTimeZonePeriod *daylight, *standard;
|
||||
NSCalendarDate *dlStartValue, *stStartValue;
|
||||
NSString *strOffsetFrom, *strOffsetTo, *tzID;
|
||||
char *keyName;
|
||||
struct Binary_r *binValue;
|
||||
struct SYSTEMTIME initDate;
|
||||
struct TimeZoneDefinition *definition;
|
||||
struct TZRule rule;
|
||||
uint16_t count;
|
||||
|
||||
binValue = [value asBinaryInMemCtx: memCtx];
|
||||
definition = get_TimeZoneDefinition (memCtx, binValue);
|
||||
|
||||
if (!definition)
|
||||
return nil;
|
||||
|
||||
if (!definition->cRules)
|
||||
goto end;
|
||||
|
||||
for (count = 0; count < definition->cRules; count++)
|
||||
{
|
||||
/* ([MS-OXCICAL] 2.1.3.1.1.19) The TZRule with the
|
||||
TZRULE_FLAG_EFFECTIVE_TZREG bit set in the TZRule flags field
|
||||
is the one that MUST be exported */
|
||||
if (definition->TZRules[count].flags & TZRULE_FLAG_EFFECTIVE_TZREG)
|
||||
{
|
||||
rule = definition->TZRules[count];
|
||||
ruleFound = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ruleFound)
|
||||
goto end;
|
||||
|
||||
if (!description)
|
||||
{
|
||||
/* The cbHeader field contains the size, in bytes of the Reserved (2b),
|
||||
cchKeyName (2b) keyName (variable Unicode string) and cRules (2b)
|
||||
([MS-OXOCAL] 2.2.1.41). The keyName field is a non-NULL-terminated
|
||||
char array. */
|
||||
keyName = talloc_strndup (memCtx, definition->keyName, (definition->cbHeader - 6) / 2);
|
||||
tzID = [NSString stringWithCString: keyName
|
||||
encoding: [NSString defaultCStringEncoding]];
|
||||
talloc_free (keyName);
|
||||
}
|
||||
else
|
||||
tzID = [NSString stringWithString: description];
|
||||
|
||||
tz = [iCalTimeZone groupWithTag: @"vtimezone"];
|
||||
[tz addChild: [CardElement simpleElementWithTag: @"tzid"
|
||||
value: tzID]];
|
||||
|
||||
if (rule.stStandardDate.wMonth != 0)
|
||||
daylightDefined = YES;
|
||||
|
||||
/* STANDARD TIME ([MS-OXCICAL] 2.1.3.1.1.19.2) */
|
||||
standard = [iCalTimeZonePeriod groupWithTag: @"standard"];
|
||||
|
||||
/* TZOFFSETFROM = -1 * (PidLidTimeZoneStruct.lBias + PidLidTimeZoneStruct.lDaylightBias) */
|
||||
strOffsetFrom = [self _offsetStringFromOffset: -1 * (rule.lBias + rule.lDaylightBias)];
|
||||
[standard addChild: [CardElement simpleElementWithTag: @"tzoffsetfrom"
|
||||
value: strOffsetFrom]];
|
||||
|
||||
/* TZOFFSETTO = -1 * (PidLidTimeZoneStruct.lBias + PidLidTimeZoneStruct.lStandardBias) */
|
||||
strOffsetTo = [self _offsetStringFromOffset: -1 * (rule.lBias + rule.lStandardBias)];
|
||||
[standard addChild: [CardElement simpleElementWithTag: @"tzoffsetto"
|
||||
value: strOffsetTo]];
|
||||
|
||||
/* DTSTART & RRULE are derived from the stStandardDate and wYear properties */
|
||||
standardStart = [iCalDateTime elementWithTag: @"dtstart"];
|
||||
|
||||
initDate = rule.stStandardDate;
|
||||
stStartValue = [NSCalendarDate dateFromSystemTime: initDate
|
||||
andRuleYear: rule.wYear];
|
||||
|
||||
[standardStart setDateTime: stStartValue];
|
||||
[standard addChild: standardStart];
|
||||
|
||||
if (daylightDefined)
|
||||
{
|
||||
standardRRule = [[iCalRecurrenceRule alloc] initWithString: [self _rRuleStringFromSystemTime: initDate]];
|
||||
[standard addChild: standardRRule];
|
||||
|
||||
/* DAYLIGHT SAVING TIME ([MS-OXCICAL] 2.1.3.1.1.19.3) */
|
||||
daylight = [iCalTimeZonePeriod groupWithTag: @"daylight"];
|
||||
/* TZOFFSETFROM = -1 * (PidLidTimeZoneStruct.lBias + PidLidTimeZoneStruct.lStandardBias) */
|
||||
[daylight addChild: [CardElement simpleElementWithTag: @"tzoffsetfrom"
|
||||
value: strOffsetTo]];
|
||||
/* TZOFFSETTO = -1 * (PidLidTimeZoneStruct.lBias + PidLidTimeZoneStruct.lDaylightBias) */
|
||||
[daylight addChild: [CardElement simpleElementWithTag: @"tzoffsetto"
|
||||
value: strOffsetFrom]];
|
||||
|
||||
/* DTSTART & RRULE are derived from the stDaylightDate and wYear properties */
|
||||
daylightStart = [iCalDateTime elementWithTag: @"dtstart"];
|
||||
initDate = rule.stDaylightDate;
|
||||
dlStartValue = [NSCalendarDate dateFromSystemTime: initDate
|
||||
andRuleYear: rule.wYear];
|
||||
|
||||
[daylightStart setDateTime: dlStartValue];
|
||||
[daylight addChild: daylightStart];
|
||||
|
||||
daylightRRule = [[iCalRecurrenceRule alloc] initWithString: [self _rRuleStringFromSystemTime: initDate]];
|
||||
[daylight addChild: daylightRRule];
|
||||
[tz addChild: daylight];
|
||||
}
|
||||
[tz addChild: standard];
|
||||
|
||||
end:
|
||||
|
||||
talloc_free (definition);
|
||||
return tz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust a date in this vTimeZone to its representation in UTC
|
||||
* Example: Timezone is +0001, the date is 2015-12-15 00:00:00 +0000
|
||||
* it returns 2015-12-14 23:00:00 +0000
|
||||
* @param date the date to adjust to the timezone.
|
||||
* @return a new GMT date adjusted with the offset of the timezone.
|
||||
*/
|
||||
- (NSCalendarDate *) shiftedCalendarDateForDate: (NSCalendarDate *) date
|
||||
{
|
||||
NSCalendarDate *tmpDate;
|
||||
|
||||
tmpDate = [date copy];
|
||||
[tmpDate autorelease];
|
||||
|
||||
[tmpDate setTimeZone: utcTZ];
|
||||
|
||||
return [tmpDate addYear: 0 month: 0 day: 0
|
||||
hour: 0 minute: 0
|
||||
second: -[[self periodForDate: tmpDate] secondsOffsetFromGMT]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,27 +1,64 @@
|
||||
[](http://www.sogo.nu/)
|
||||
## Contribute
|
||||
|
||||
Share your calendars, address books and mails in your community with a completely free and open source solution.
|
||||
SOGo is a collaborative effort in order to create the best Free and Open Source groupware solution.
|
||||
|
||||
Let your Mozilla Thunderbird/Lightning, Microsoft Outlook, Apple iCal/iPhone, Android and BlackBerry users collaborate using a modern platform.
|
||||
There are multiple ways you can contribute to the project
|
||||
|
||||
## What is SOGo?
|
||||
* Documentation reviews, enhancements and translations
|
||||
* Feature requests or by sharing your ideas (see the roadmap)
|
||||
* Participate in the discussion on mailing lists
|
||||
* Patches for bugs or enhancements
|
||||
* Provide new translations
|
||||
|
||||
SOGo is [fully supported](http://www.sogo.nu/support/commercial_support.html) and [trusted](http://www.sogo.nu/tour/testimonials.html) groupware server with a focus on scalability and open standards. SOGo is released under the GNU GPL/LGPL v2 and above.
|
||||
## Source Code
|
||||
|
||||
SOGo provides a rich AJAX-based Web interface and supports multiple native clients through the use of standard protocols such as CalDAV, CardDAV and GroupDAV.
|
||||
You can browse the lastest version of the source code online from Inverse's github repository:
|
||||
|
||||
SOGo is the missing component of your infrastructure; it sits in the middle of your servers to offer your users an uniform and complete interface to access their information. It has been deployed in production environments where thousands of users are involved.
|
||||
* [https://github.com/inverse-inc](https://github.com/inverse-inc)
|
||||
|
||||
[](http://www.sogo.nu/)
|
||||
To compile SOGo, you first need to obtain the source code of both SOGo and SOPE. The source code of SOPE and SOGo can be obtained from Inverse's github repository:
|
||||
|
||||
[Learn more...](http://www.sogo.nu/about/overview.html)
|
||||
* [https://github.com/inverse-inc/sope](https://github.com/inverse-inc/sope)
|
||||
* [https://github.com/inverse-inc/sogo](https://github.com/inverse-inc/sogo)
|
||||
|
||||
## Microsoft Outlook Compatible
|
||||
The source code of the SOGo Connector and SOGo Integrator extensions for Thunderbird 31+ can be obtained from Inverse's github repository:
|
||||
|
||||
SOGo offers native Microsoft Outlook compatibility using the [OpenChange](http://www.openchange.org/) backend developed by [Inverse](http://www.inverse.ca/). This means Microsoft Outlook 2003, 2007, 2010 and 2013 can talk directly to SOGo – just like if it was a Microsoft Exchange server. **No plugins are required in Outlook to make this work**.
|
||||
* [https://github.com/inverse-inc/sogo-connector.tb31](https://github.com/inverse-inc/sogo-connector.tb31)
|
||||
* [https://github.com/inverse-inc/sogo-integrator.tb31](https://github.com/inverse-inc/sogo-integrator.tb31)
|
||||
|
||||
The following screencast shows Outlook 2010 connected to SOGo as if it was an Exchange server, along the Web interface of SOGo.
|
||||
Please refer to the [FAQ](http://sogo.nu/support/faq.html) for [compilation instructions](http://sogo.nu/support/faq/article/how-do-i-compile-sogo-2.html).
|
||||
|
||||
[](http://www.youtube.com/watch?v=1hcBSB4Kxww)
|
||||
## Translations
|
||||
|
||||
[](https://github.com/inverse-inc/sogo/) [](https://www.ohloh.net/p/sogo) [](http://twitter.com/scalableogo) [](http://sourceforge.net/projects/sogo-zeg) [](https://freecode.com/projects/sogo-inverse) [](http://www.linkedin.com/groups/SOGo-Groupware-4164805)
|
||||
SOGo and its associated components are available in various languages. The following list describes the official translations alongside their maintainers :
|
||||
|
||||
* English - [Inverse inc.](http://www.inverse.ca/)
|
||||
* Arabic - Anass Ahmed
|
||||
* Basque - Gorka Gonzalez
|
||||
* Brazilian Portuguese - Alexandre Marcilio
|
||||
* Catalan - Hector M. Rulot Segovia
|
||||
* Chinese (Taiwan)
|
||||
* Croatian - Jens Riecken
|
||||
* Czech - Šimon Halamásek
|
||||
* Danish (Denmark) - Altibox
|
||||
* Dutch - Roel van Os
|
||||
* Finnish - Kari Salmu
|
||||
* French - [Inverse](http://www.inverse.ca/)
|
||||
* German - Alexander Greiner-Baer
|
||||
* Hungarian - Sándor Kuti
|
||||
* Icelandic - Anna Jonna Armannsdottir
|
||||
* Italian - Alessio Fattorini
|
||||
* Macedonian - Miroslav Jovanovic
|
||||
* Norwegian (Bokmål) - Jan Ivar Karlsen
|
||||
* Norwegian (Nynorsk) - Altibox
|
||||
* Polish - Paweł Bogusławski
|
||||
* Russian - Alex Kabakaev
|
||||
* Slovak - Martin Pastor
|
||||
* Slovenian - Jens Riecken
|
||||
* Spanish (Argentina) - Federico Alberto Sayd
|
||||
* Spanish (Spain) - Dominique Couot
|
||||
* Swedish - Peter Johansson
|
||||
* Ukrainian - Oleksa Stasevych
|
||||
* Welsh - Iona Bailey
|
||||
|
||||
If you would like to translate the software in an other language, please consult the [FAQ](http://sogo.nu/support/faq/article/how-to-translate-sogo-in-another-language-2.html). You can also subscribe to the SOGo i18n mailing list to follow string additions or changes. To subscribe to i18n@sogo.nu, send an email to i18n-request@sogo.nu with SUBSCRIBE i18n as the subject. Archived posts are [available online](https://inverse.ca/sogo/lists/arc/i18n).
|
||||
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
|
||||
#import <Foundation/NSValue.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#ifndef GCSALARMSFOLDER_H
|
||||
#define GCSALARMSFOLDER_H
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class NSCalendarDate;
|
||||
@class NSException;
|
||||
|
||||
@@ -18,16 +18,10 @@
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
#import <Foundation/NSUserDefaults.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
|
||||
#import <GDLAccess/EOAdaptorChannel.h>
|
||||
#import <GDLAccess/EOAdaptorContext.h>
|
||||
#import <GDLAccess/EOAttribute.h>
|
||||
#import <GDLAccess/EOEntity.h>
|
||||
@@ -37,7 +31,6 @@
|
||||
#import "GCSChannelManager.h"
|
||||
#import "GCSFolderManager.h"
|
||||
#import "GCSSpecialQueries.h"
|
||||
#import "GCSStringFormatter.h"
|
||||
#import "NSURL+GCS.h"
|
||||
|
||||
#import "GCSAlarmsFolder.h"
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#ifndef __GDLContentStore_GCSChannelManager_H__
|
||||
#define __GDLContentStore_GCSChannelManager_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
GCSChannelManager
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSLock.h>
|
||||
#import <Foundation/NSTimer.h>
|
||||
#import <Foundation/NSUserDefaults.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
@@ -33,7 +31,6 @@
|
||||
|
||||
#import <GDLAccess/EOAdaptor.h>
|
||||
#import <GDLAccess/EOAdaptorContext.h>
|
||||
#import <GDLAccess/EOAdaptorChannel.h>
|
||||
|
||||
#import "GCSChannelManager.h"
|
||||
#import "NSURL+GCS.h"
|
||||
@@ -500,7 +497,7 @@ static NSTimeInterval ChannelCollectionTimer = 5 * 60;
|
||||
ms = [NSMutableString stringWithCapacity: 256];
|
||||
[ms appendFormat: @"<0x%p[%@]: ", self, NSStringFromClass ([self class])];
|
||||
|
||||
[ms appendFormat: @" #adaptors=%d", [urlToAdaptor count]];
|
||||
[ms appendFormat: @" #adaptors=%d", (int)[urlToAdaptor count]];
|
||||
|
||||
[ms appendString: @">"];
|
||||
return ms;
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#ifndef __GDLContentStore_GCSFieldInfo_H__
|
||||
#define __GDLContentStore_GCSFieldInfo_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
GCSFieldInfo
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#ifndef __GDLContentStore_GCSFolder_H__
|
||||
#define __GDLContentStore_GCSFolder_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
GCSFolder
|
||||
|
||||
Loaded 100 of 1183 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user