From dd0008f6ab9d05df5f3a743357a6e2567bdeae01 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 12 Jun 2012 14:42:52 +0000 Subject: [PATCH 001/127] Fixed version Monotone-Parent: ea6bc80cdabf55c83e6df32dd1aaa4ecfa16a6e1 Monotone-Revision: 8d523fe7796cff9d335706a89105b900379bfa52 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-06-12T14:42:52 Monotone-Branch: ca.inverse.sogo --- Version | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Version b/Version index 0de612ba1..09503ebca 100644 --- a/Version +++ b/Version @@ -2,6 +2,6 @@ # This file is included by library makefiles to set the version information # of the executable. -MAJOR_VERSION=1 -MINOR_VERSION=3 -SUBMINOR_VERSION=17 +MAJOR_VERSION=2 +MINOR_VERSION=0 +SUBMINOR_VERSION=0 From 07cc5e8cf8f66a5ce0ad7d3b3fba676b9dac79c9 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 15 Jun 2012 13:33:21 +0000 Subject: [PATCH 002/127] Monotone-Parent: 8d523fe7796cff9d335706a89105b900379bfa52 Monotone-Revision: b664e2e19975c70a7614aa975a3a045f0bec7ec3 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-06-15T13:33:21 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreContext.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m index 17907e93b..1817658ea 100644 --- a/OpenChange/MAPIStoreContext.m +++ b/OpenChange/MAPIStoreContext.m @@ -294,9 +294,11 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) [MAPIStoreUserContext userContextWithUsername: username andTDBIndexing: indexingTdb]); +#if 0 mapistore_mgmt_backend_register_user (newConnInfo, "SOGo", [username UTF8String]); +#endif connInfo = newConnInfo; username = [NSString stringWithUTF8String: newConnInfo->username]; @@ -315,9 +317,12 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) - (void) dealloc { +#if 0 mapistore_mgmt_backend_unregister_user ([self connectionInfo], "SOGo", [[userContext username] UTF8String]); +#endif + [contextUrl release]; [userContext release]; [containersBag release]; From 988ca2d853e7563e99c74242507db9bf602aa0f0 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 18 Jun 2012 17:50:31 +0000 Subject: [PATCH 003/127] Monotone-Parent: 6748af72ecdd0c613acb968eb261448ae6b6982d Monotone-Revision: c69af3e4b83d5cab3a52701fb736c8a149697338 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-06-18T17:50:31 Monotone-Branch: ca.inverse.sogo --- ...Native Microsoft Outlook Configuration.odt | Bin 54208 -> 27917 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Documentation/SOGo Native Microsoft Outlook Configuration.odt b/Documentation/SOGo Native Microsoft Outlook Configuration.odt index 8b38028861faff71f12c9d13cfc555608f567b8b..a350de392a22f7c89e179aeacef624755b9329af 100644 GIT binary patch literal 27917 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 KWs=5sTmJ{=M;VU* delta 52213 zcmZ6yV~{3K&^E`I zbz;_md&@xK6=gudP=SD;fPkD6>Js3kLH|)w05DO4HxfJ)6x4sKf|j=uqB`5zw{ z2>1W6F$fa~C}dI!2#Fx%a5}V!O(;|B0OpM$9I$x09%CqPbOEBtYCq;Sqc~7J@V|N> zp|Cd6U3LG}HuL|~_kSKD=@oyv;6q1I=RbpQilB z3GCKYtJ*qhcZ^G=;bCVGi>oX&^QG|Cy87F>MLnH-Wv^G8krp`1rmJs23}<y?Y#FdUlK!1<1#*D;h??bUcjI{t5QE0GqA?I*M?gM5QuFf;ZN?s#7kZEPD{!?@P@#1QT~V zwd!ymm8H8Nw6^lB)2Hf{C;I3W-1p&oLEeu5EhevbI~r}0Rs9srYFHsOYZ@X-<6X5~ zE(3^8-~0u@8nOb!EdpknV9g+ZWliPViZl;A{ zRm&PhH4>@_{t$g#ycCeSDy!>P>Ig-?mb-1b`ZuFfSwp`{T#o4;4%L%pI=~iEV8rrn^cy=hVJ=9L?7S$$bWgXnu9MCj6TJXxXwuPFqpc0 zkwC`*%{Q6}Nd=*Tl!hgOtu(agN$cRHkoP`h`io2XW_3-=ZHe zvM#^iQ8CbIIbzI~!ah&2(!z7e1$h!q-aAXOJ^Xf8fNx*5lyJ0TA5BZMEa5aoM^J?- zAdpz%1)}a7Za`Q4tq$PMr6ZJzoQS+LxTy4v=~9&vR( zw#~;ou1&~1_l^WDq2>1lN=$3Bd$uX+`==nw?m`m`XidMy1b+_S9HrCJn+AwVNZ(>W z+_TWTx5gk&n^9-Zfvx90OP^_-?{o(;n}v2p!KD`cwU2g0L_(vGyuN;)Z-$jUW*_&5NO?dGb? zMJLch^)s$Sk%4urH&wQ!N&ryGh87zjOUDpiym~fsS?BH%&9Bthle3!Jc~$0#cFJhQ zD~7~wt7X^+MHIIqZ@K?YKhpv&mJbP`M4Shh!q>Buw0!RBd!sM(tm-aZUS!gkL9K@I z?W*eTEUF>RTGjvN`rY^e-2-yt{xAF2%G_miS7WrzZ+1A(shr=}C300DJ>4__?v3G1 z8O9@p_0^?d}9TdUOVtxWm?aM~_DJ_nNt=c_50+u;|i#>x=> z&fna9-?w&m);?oc)mA{R=8s2m@f~bdJp!E{RlO{emU05C7UJB;_pzRr&FM50>&0_E zEv57}Lt;jUDYQZL5=M$GU);k*lZuM+J2w0|Asda_#DF(+BZ1WMgZnE8Y-zpFPRttBr3C@vcOdJUS7 zn)(HI4f}9?mm&YylU%En_cahY0pJ*mYHqpOX{oVQUl`qsD8pgsoi>~Y7J|Yz?xJe= z1WZc+`uL2pdi-~ZZ5JlZ2WP4lX=lSqwIM zLGVGq)|@JK{^-L_bmxf!Gd?D#fC~E%tq5Et^3-s15LzU;K^u@d3#8QCQamQ)|0r1V zpRX;#XnY=o2tkvDMAQJcMFvd|2g5%Z<8n@1LOL0VTM(iEqcEfc2Io5jr?CT)MN^u1_+EE)dNWVrhhDw3`D-$&pX*AW2mesZN`mbUpNmfl?a5awy!~(#-$zR%4(l zC|n&j@h%B9wqgA)_$(gfpA}nNyKje_5Y#b3=>u(}iG-IFol|+!aU?LJyfw4{J+K^_ zh)>fR9(V*38L%Aya1y7ned-%)HoEgl18CSRX8ETxi|G^nHZYZWu-_%_9R!G#Q5!{j zqNlU7CyDvF_$*s^h|?jikm`!{CG&%$3b}mA%`yKRJ}|k@OQhmasKe2L{`eY>edQIA zig~o6MQkX2>e|P(bmQS?`%s4=sO_h;R3zg zkY9hfXO3PCZIjmwMG9$eeL`VEQ+6HXKY=Uo4LU!b&+&WXIyO9J`1zg zHPhA?L%F&L!GLc!S5Nn?t+RmlxIR0*$lk{f!^a)h5H7X{0*`$#xohGw;+Q*)8p@0$ z@W>la??%Z3keHB|u1&}Gu~-#mWEquD_OQYV3fm0(g8e$X-Uqk+flO=FL?W(VdNqCf z5VhLN#Wzf6n~oSVARlo`MlLkdqxm!@feP;uy^6Q(jL0wu4OVfIffi3zZ1#p(jv>R1 zCf7mp?Mf(-!d_qHg0Zi~fcRJrO>R-igYESLXsNmZmJQmk53S%A&=bK>P?}R@Lq*Ig z0tG6RxuQ|0vbeS2lvX2_@Rsb8>I8?Sx)DLvm|k3DOim~HqX*fn!Y zsau5$$E7_) zqU59il6#sdDbU~GNtcx8?}d_V4r-3QSJ}^2xHhNoE=8pEZJ!=upp5Nj8o@p2B^*u0 z2&?{UH3LerREk8E(elf~AwLomDbwmB0;~L?N)QUqP}EfbH>L(*Q%RVV-#04)4M!L` zks35s2#Ms8p)y=EB=B>J`wVl}XTUt=mzekfRXz$NtUtiM@JJm^g0#Ua%v1Iw%KS!s zQ+Tj;>U6KoDIXMp6HwPzf)2GrU>b!{s8!O7jX%JO3p)Xs-?bQQ5^FZ;M`_^ILqWo*%QZw?$)|ENV603&m@ z`}FjPzuFlD(TmdgRf67Xc@Vm6>a>=^hzCuy8G5%bWD;z4@FrHr@YxD(nFhARVCsn$ z_W|x%G-&9O+#t!f$bO*ugqTXsw)Vr{q4$n~jQmlH z(`bwjQjbRGk5kSQ_84c5gUJ(E`?1S#ol`J*LrHTT{)Zs&Z%y~2mb_p2u4P?oSI-D{ zJHWPd4ZmG}*NEtm>%KlC`h(|n{UQcthtRq1;&Cq#@P4VcyfYo6v8AzU2Fyf}_DkA4 z+@jCAGz!;pMjrij=U1nm*TJG2*2cVV9V|R{#$VHP-(`pXYm7PvY0a97w*q1kAEe}R zCW%*|T~@w#kgFy~{e)5VM!TX42i_|?5&;M^kdtE4YRw%%Pj#P36$0536JpL$3h$*G z_ZH32TbHAbJg|o;EI~We14aFlJ{0ygX6*6YUe^R3LcXo*sujNC054e zuZqKvI1Ra`Q^ExcF5>2-LH3`{ucGvV10!0oN+T;k(K=Sw@@UqktQNZ%b#3?eXp@m_=#-LW{#CG@GSRk=w`=!aqm|!;l1KgR-`)b!aNl|1ym2T^CV_ z#WSv(btI+-!vRgGSS89EfC;w|={t^G9rWroHZ}D4N{CzIgh8hi{rltr&5UZbEX|R8 z)i#o80az_Z@5oYOb-ffv@O{OfA|vRo5)-BZnb#%ESP64f$}EfbQLclX z@b>-QBKqWTI*n@yM}MFAy1fo1bhue0K!#)!Wc)sj#4NkN9(bD~>iBY?FfdV*-eiR- z2y9y2Y##|76&Kx2ur%33k%3F$=6wt-!4+C=IY6$4yV~Ot2Lx3k88(+JRtkJUpE5yL zVe_ngRq)n+KJ5Hx2w`uQ78{E_!!0ikZv(k9r$wYEWP_sZ8>NR0XYWc}A6!Cxd!Uno zP=vQHTJy^Pij1S5g;Z3LxhD}uL+g#OsC$S|1}92?B|u=`+vG`R+C>F@#U$88A!1mQ zviazHx5F3j0|W&+RSrVYolFBizy~^%LIl>^E8m{o@hrI`T|pL0!%)dE=*rT?IQKB! zpbPyrqRY^HXTOEr`BK^!zY>WcDNfh1yxsGiXcjJH3KM8$uiA;y$Ti#P*;i`hHRVX< z5HJORErG4VcC_-E@-}ZUOknyX0kIzR>IjvPzj7yh0HQ}YM{A5;P?8#u{yq#!6oV9$ z-1y^o1jxC8*U1q~!mU_nFg{`NIVVt=P4Row#sB{?RR{tgfzD6sxF};_6W|`ba!q`!o17iV#vEE;B2-tFZ5$*ifV* zM@Y3g4_NmSsCDNcwztWKqhs#hc&tT02TT+RF)1%$Pw+W%;R`)QBq_LPF_QEE`{Z}T_xozUw5@`Y93_TD1EX;no508IyAfin|VqQDlMz=UsD>gI| zj(Z}cu{i_4_&RSdbRk{yegiqx?`PRcN@Sa}AmpUvGUgAI5OWdS6eG-7%@ZM;-yn;! zGYK{@aA?9?M^i`MNw28H0Od4NicM%@Sk<8$BSvW}-PRX7NTF#j z2^zyA)&O)25W(pr4Wao3%;j5hJAGN4`%vih!k^eMrRFSsB1|HC24@ zJ1|~ED;i)%v30(IV6T9wL?CC^k?V**3(^m1fV-|Dj}X#os`}#-(y3NGIsPdwm&P>+ z=94Seks+8Z1YaiR?~N7Xcdox*wzoM^Kgu)57Z|k$(c!@ycNL)- zpl6cRNv~byKJaS@TzFZUtd-{U-qPvI+-zO9OI+E(Q5+2$LdMAWzw(AC$_%nW&t^ht zzH&XTD^V`A}E6fwJ2JUg7NmN z_N7T!ShxUO$K}I9bN$i13etIsR9*4}1yhsDA#A(v+vkU&r==`+dx4$o9bXlctBy`g zoR80iEshn9KU-|UlO$A$&5FI_$?`w0M}1Oc5&nMkYd0&=0?Lh^M-9>-Aab~C?&5rO z*8+{BxRy~`e1+RgHwRk})3XRF)8E^SI`w>$&-s8L2o)Mvjzi~}?w^n{zI>||wou>p zSS9rdciVFlcq3OZTV@7KpbK%}EeSC$3EahWuf2J;y(wcF;vWTb(GU4j4obgaN}C#x zDPi;B*V`Dgjr7WtH5isU*c7keSi#;G*^)`qJLIqff0IjI#NSE1L>y}FTNNL#RL2kJvp zs_Ax5OlouYKwnzpf9_|tE0E$q*RvS-G(Q}qt+;8dzoXAwvG6V^Eqvk4$~oo}`7+g` zLrYgyW-&jwzbq}Iea&7M>zLeVxS?>kcq0KDS7+RU3}!pIB;ZpR=9(keue{zr{3qE$B-7}Ev_StXZssa7;Q9yNHflclX)&-I|w)M zT)5@idd7vGmwR&&lwyVKGzU<4r|J4A+a0Q}!B)?41$-UmU@8PI=m|9|6@y<&<4L_Y7iXSng&hiSQ(2MQ)|PtTMU{_{-)1b|;j|tDV_d1z$Ftt; z{FfA9Egkf&6$O8R6!04_Xzq+E&Q(wr8p<1ayv|hxmTy*Y?#2&NG7#Xz$`+PrG_lFm zeKe^Dz#|hCoDyPQ2bMAnOM)Sc#R2a>wSFIa@?xnxX>5M5%YuI#H@t*U-H!}ax^1lz zG;i3LiZ9qG^}5iQv4+p!6heknN`>9P6kv&MCQ>)+w8>ZM0Z^U9J8n{{LuP7r!GhFs zi6XQRF~{vr$Y!}lBV?8=Bnvt4Gh>8}-JWhyVqzxzEI6bNa z(JD0 z%tF&8$b}<+4`-*X5)D05*$aY4;W$f}cim)gDZXHe{H3FHM>7 zDLv_-1O!QLJtmQF|B)>USMmKJ)V`K|Ve;Z`Tv#Z`$wjz2E%wFY%dss@(y~1*R>$cg z-!i8g?B{*XV1W>ZSZZH#8ZP@;avZkxSYM5mlAwB;7VeCp=&6cWQ|I|wGK^HP&zl=4 zZ58VYfwkwkH0Wvjc34v^lUO`^PhONF(iQV01eldxk!Tiqs29!J|!IG&ZoTD+eP(?nfsb)uBoknXXWU;g5 z0dPl=Gze>Wa^=+dM`xx$*xXe9;yp^!?8zTBgv+_pBXu)QrN55TniuaRUdMbZgU@dr znZ>Z(!M}z<+l)*;ZC0y<7s{Yc@nPhqatcV=KL%iIb7RH>6sCAh)7i$&`Ghmwd~ ziU*Kmv11dWv3T9jn>u0i|}G5=Xu!bLqZ_Q zFs(%661y7GwpFP}Ys%f?Ma?2u$vjAsz^B(?(E?65_I<@X^fF~k3#LDM$(2cet#B{O zA4a%^Z!{%N@kkJ@Zb=<9?1tGUdIFq#w=#J`*!yZgRW{tDrsm_+)E-?fNW}(2?&Cyf z=dA}95;h}!*atwQgou81xNS*PqIHzK9waq?ZYL=b5&@KxUY|E!e!E5-d7e8}KQu8P zG?M>T`)cN{4u!OE*|(aqeJW-K7YR8^gw$ASVURV{E=TIgb?G+oH+Ge+?05nL?B%AY z(?A^^TYmZJ5g#h=IWkg`2k;u>clZT1ib57FQ%6=L-pA5vHCJ5ELvT*}7Sf6dTZwCE z+q^7vtN=J}1h(eueLn8)pA|GP>bYEoe2Ky^>IDt7F`pR!eER;4Mj_hBy5d(aFV>0Q zxWwI<0Og4&wqJ*`dLp6rP_^8i&E1}iI$Iq*LD?#B)Nmz})+_j7y5ksC8&pIE!ye9; zf3GS?68L>eI*T2|y=__*MOW>~dP!&RH%>seDGJa$fV$A+0!C-$28X>q-_LsZ({c)& z?-D(Wvabpg3}8{G@e(AFN~os1ZM7!vD1--A;KOJ0vRj%R!{i7Br8`WHFidN&a_%gY z7@?U~Lz^^KTN@qO3hVGRun9P*L1 zcm_0aac#f!>z}gkK*7eyL2|GlHHKjK0ntjS?a3$r13KRb^=ra)$9=s*i5G;$s$A0k;99=D^+uc$<=oB{aIA5XtB0(PV7ZYPlQiXy~az2x%l9#8~T z@E3CnoELM2vrdS48Z%PaAYB>z``uGlYf=#qrWO6r-Peum$ZBuKY=9ccZz*lc9kH9O zlUbkHVC%B63AdMFe4fIC8BWpb(a7mjJxT(imX<%gJtxE~aiw4-3M}^v_mOI?-T*@` z6LeJU++j1W#2tKCYqpWq$h!EJNP%A%)(bhR$d`o2Jndq7*hTs(W%o)2g6r#dX*$Kb zHgl}#;v#ex8QiWplln!lNf?X;ZH?I^%T8JspyKSMx%30Jc1A9bq?I?S+{gxwg#6Mz z?b&42_qcO87N)|;SuHkB!n<429e|gn4D`C&zzWKp)4vue5o}FoeUXO-wwOi5#dPMI zGvrVUD3gC*aqW%wxc&MztsJk7GLW6RQE4zY)IQHuBxSX8vUj{w%j1m(+Z99X%mHntiOe=pooe_QrhrAkqZJV9x2Q z=fp=Y|9md&Jg;?BPK+C$3IKi{-EnPhavcFS=bV2!4H|n9qE=ptwe^q59h`dB=;as= zB(?e~>xE=ZH+`y;zWAmnT@Sr-d(jx1BN$yPMbo*}h-GuAkwfJ(pa3Fe^1=T)-2Jl^ zs79yBk&G_ZVwl`R#Be#*|NL!GB4zr)OjRn%G$(v{EH~!PcG2VweN;5p=kM3|qNyB3 zS>z4BkBsYy5?K0U^E&)cINT79!sq3_KRbHrbs86cKE%tw`ngav?U=Ji#%e31Z217nuaA}u)AG$8sPS{aQoe#dexxOWn5_q^WtENaDU|n%ozZS zFh9Z0E|&>4`jBIan_W^nsG#68WYGSX&| z$=zNR`!K)Q4%iYJ(X%;kjgrd=5-gn-B2=NMGd$1EV1~zwzR1>R`HxheSYqC>ihp;X zP+z4q!K|cm9US)uz~}N@jFoTD#YIq&ixB|*hCAjb(BTgE z@_@F*O^-W05!bSx?5C59^nnR>_s(Q6=1pYtIv!7I)N2N0%@Wo$&Avv!uhoozVW+#J>*KX7CjKc8 zoLRA+BgpORcd+pD~g@7snCFE;tE+oGRtWVCa>al^ogbGbpe7DI* zS?U2m)I%btmmq+x^r!py7tLM%ooS$6Q6{EQ!jne2Bg`*Ozg+0_l#t0oFgu3sHlMGv zucMn)9MW-(JUg1@o%mNgUPO;Bx?R2R5h=FFphMOLf*Ga(*jj?*u}&8zPVc+3rLsRA z3e^`;Y2oWedaL%gg_B#AKj^arr-kj-+vTl*SxbWQX3G*DeGEG(81%N0?sikxJAH+U zy8k}Y`N=7?FrPhaC6_FY!v=oDGwaTj!dSA_ItM_tw|5iHY!Uw^9haO*ht;Tk% z*%&Ss?x@twv#4n%p6i;tyaKbcJc7haI!Mf@>rARCEkl(5Rp?47`4hSO)gM^dqd`+; zM8$Vr2YwZ5bcpm>d3yejXsWeWkX!&M{uSa3O+U#D*BC4ZOaW3|$1kNh-EHT}a)Bdz?(4w=Z&)wXI+57k$>jzKlcL*@-#77Pfy-`ukWDedp_M z><%wUxW{GIWhX1pB7lm8NaA&h0kY%^oq_=$w5BQ+30-tOql_92)Y4 zP@QKUZQ57_wXZbC4Cc^2iSPmsPjecxpi95NE9R?I2S#lYPSdOm>gR_sed`f4+z(sN zG3Ci2=^*(d^w19Ig@o0+8ZrTw74)r2V-hZo#K-J(An_nFuFR77(rFS2h8*C{S?153 zZ_iIl*F57<3sxBOpA&DAR#mlMALNE>) z&y%LH!ZCa4CR604y1LuxlJv6l!2f~?Z_6MKI;F>DqZD0=C6I=r1!4e7prMBhiM@Y{ zE_nKcO;t!T0^Cvi(u9PJ{HX#pOBU31-#rFMVL*{soQR5DL<~B$;lgTSSKEME2zqFU zh=SU^uECMvRo<&8p)8&ZJ)!;c%m?~59{Sfy_u0M}RTJQR^goZCZNj|Tk767<@BH`L zbfXlA-3Ki5Y6{{=L+AjyOe*8~ac%HcI!~^aJUxUmdc}UFSa%JEpmmJoa=5Ho^Sqx?$$s42VKDSzsW!7?ieEARI>|Czto1e zpQ5yImb<5=cKX7%=8r5=(eZABSIr^M7s#}n{8fiVyz{EF-9NI*uZ8~YF5v#9-s<4r z^}68UR#{Dn0g?YkLafNsPq11OThp?RAvjDRg3t(FNU zyCB2{D0!}43Mmhs!B|9`4ZL(!;N?JpUL3PzhQ*T03TClPzd1g|t@Ho+$ahRuPA}m{ zm8G07fHQ=WQSj zViOR?+^_|59~VeNywZgHaCQ}5$EH_vNcHc?NiH1yrb~>lN?*3s1r;HwnNkJ(p1?OV zL7UHSGAfF4x-rjV`BZlAoLg07XInbHmV9le)s-eIpd{>zJ(*jp5&zQ@|r zfOW|>*o2N^vr^Cc8@u?51bdyfn#KP80`b`?CGWw2daw<}T)8x@{#AZk$8>5U<*&!h z4>kBhXh@~2q#oKs{?{nYz-IoN41gms#>xi+Z}X3Eq-O|O9al}c3Ta)LD+etaG-*)2 zX=Ms+1xO}~4CTKATbv?!e$_@Mrp+-20HX~{oO&`nJiXT>X++c+9Se0OlIG0?tUGw- zVHywZa;6OL-z(u7W#)aShDX%4iwn?G7|eTFTbleYt5nddh^blMo)KJ%`H>q!`y;Q#8GjU8K*#7E!t?v%@;Pz0Ie|@sN(Iy__>P-E+IV!NXJ{Rqks2~P> z4i4R`X=RTUZGS9)ZZ<^}*xPT8jk4DX6Ar&6RVqsEs(!C{&##w&16_T+0Jh}c#n?Ni zv(N1mmFElJU`93rj`hm7l*8_ZFYOvj53Sx^vtSDL(0sa}$TV3Ty)LslpP1!9wsd56 za>ZQawf*9-u}5oJ$KkASlm>lbpXo+s4uM5ysS)>J9T}8ShYb^= z*o*#*m25?ftt|4KZ!me~1ElQcV{2m36VQ|xNg&J5b6c`2Hf z>96^_Ena*gOvN99dPaatMF|~D6B{F|k`sv+8Efe9eyPSXgl|cmR|%FaulB>}%Le0C z;VWPTFx&3_+tvw98>*A3xHgt8Fg56ED|5L?boudC)pvn@1z|83p zhEc`GZI~E89y#x163AUXqvD^1faQ-~W&3bBkHg;3%k1AM=kquu>H{1PE$)g&D+`15 z;L+DsI2CCe=aQB)3fNZ^qswg`OqryW*)T|s6dA{jFEt*)u+p_4nNxLQH6dYB&JbUs z@?wV(Ypyw0?HL?D0EwFQ;4np zI9}l+Szk<7XSoYgFGv(0e5m+mKz38Yl1ZY8u^(quQ9iWN1TZGG@P{J&&e1^J!FMbm z!D967n*KEW>R?wih5Iw_?Fm>@*Yzo*ztpufU=AV7BOtLH~ulz3tc zO4C_d>f}2SWMDLMVU`}6Oe!IL2yM`cOtPAoSglH02?!~KHZ9n-pL0UgTw7$Uw4dhh z=0b|!LZ49u7=U>>7z{b-*k%)GL#O&a!!-$^e%FNdZ}y4+*&etu-InhayhsB^=-PF2 z+=qFstxE^P+EvUL|EB)QOx!J3r@#D-)G!c{v3M`WZWAC|>N!K)qWF)MFY!6|w1~F4 z=z(air=jz`jPX#lE{0P&sJNgunBcatKebBM*1mdw4nP8*QCU;?lskI#h3X?Y649zf z(4hqrsh5JFZ7Sf8(p%_;4Q)n10e^N;UT!dCJ?3K5`XxMVnv)#6K)|s#F6?Zbazfbn&Cg(_w^p04+0i%2wDm*uIb}oE6C(J7H8ClK^mBuhT|gLd7ZQuS z7;N}Jwe(>3tbr!JgpQ4X;*O5VbxFlGkbX-3Hby-U>*ot-6n{!pys7Po)TuwyrO(*2 zD&UdV%sBB^5^I`xBc5ohh8eGpJ_l*gDZ11=0Tm7^*JrNrH3=k_^ab^i`ef=S7rKV0 z?DIe&wa?x?9&FXx76moDb_qJRo+mNUlRsq_7+S6=cS@=}cgp0}9BZ4A`bBPdp+Z9n z?U`SV0&y&EH8VW;7KBYumvr)R00_OZHb5~GHq&436^tXRLOM+7Bw5Z_Yxz5HYl@`- z*>>=Uz4@S-hI9I1f%@j2(K06*d9iq`kv>={>bR+wB%T>3Z*hs^WC!MXA0980IOxWz!5(GVCJt$K`76D0MaF;YZkEJ z4~^EWBWl-Ke~@QJ_I!ZgN+`9q3W&<|uB>}qTdn{)DrpxFyCmgJ6PBgm@hY4=zjRyW zfbQi$2oIWW#ptg;JP82b_B;h=mQV!KPt>~wd6yC82Q|BHLwHnXBvPimO=o?9{qdH=J~Eh`cJ{mt}+ zvDU2&x=CRcP1YJZLVcb-3|MBF-F=zX@7w@JKHkzvvmzRF=_#r>Bvz;P_VrL0DQ9wa zffk15BUs$XQP>Bun1|x}D=Eb~972AX%;&=`wPy0$Mw9JZEeK+}N1>Rk8TOhzPxCqd zgR4z=y)CE$dXoF>*thqK2@$N6WjlHZUBbBB=jtm9S0i^WQeu%bqyxCw>2&Er76AH3 zFJQYR@aC7mKm^Ejb6^LhgL7n(q6DkIGdYma0R?p_3U>j)7U#niX&;kRJ#Io%TL8%U zD)&IJb$>9zo3$ylNEznJ+G$f`@ox}yml$0e?^XEul^qB8 z(JZ=eo}mY$MXSu6zBw)0!l zRH`_>6tTH6fq2jE6usaWnG$T4A}oV^O5VXFVnQrQrv%5{uYc{xrpzf@cEA%=WM12& zH)`)SN)ML+GT5Sw%#t(HY=U}JfONo()UF<67yW96rKmlaz`NmXg<8EIvdY<& z2KaPu=#%&r56}XZ+uC-gOZ&@0BZgY~){0cqDsoL-``W%m#Die^nadTJHF^Ce4i7oz za%}?Qzdr4@uO;d+b$$SA8DNBUzzDED#WS8fcb`N~A>H_Js#emY@Wgbo6HU! z+0xCEShw%aBi~ys!%Se)m$`XUfQH*0-R6k=_w0rwD%9oW41Kky#b^)J;(5=A6>nxs zal^C9C2%Ko4Jp@%Cnf>5ub_)8;s?AN8XVQ7*%I8Z@U_iV@m5^U0#F@beT@1Dv&-}B z*WBdU+9fVjDJdL{GALPw66>zyfpf(yyaIH0%O}f83A1lY4-Xfk7Kj{NZv{~wKZcL3 zptxCXanA^Y!lRRNI1tAxtLKoJswf~%OywASizn(oNQIVf-stQQ>3;RwjS7NUH2IH> zV;UG3$QJFIkUv;rKLA_h2iEX>azDBWoO1ng79!JO5L>rCsvc}`@2=zX!4X0z=?lw; zA(T5$@lBe$3_bud@^I2PKVA3PmkZZ4O;h|?lyqKJ3iJes0GoWun{DCP*JeMkoXnMF zt}h$5NZk>n-!|?JT_XIv0FMxnS1rqEAes4AMBoQRq$0{a0g!d|8mwADG#jJ{ColyBo#wqG&x=@^u+@}Rkxm~gWBZ zLOtt?(fq5v7C?(YhX(!??Pz0R8q`2H^`ivN+f>(Xn0pn@n~X}YKP4~u3{DB27j>R! z1EVB;lun&Bo0ud{CJJrYiMPwf7;ft+X0mVJJj+ej61cpwu1-2(`E1SIjf^Kdu zZ5azm7O8iRib6hDTpk5RO+uJs6S6sz1r|I?6AcpC3uq-{6#0&TK?NJc*|aEAfs2W* zrFk}k(N?c=2(0)S996lrCQ*39`1h(k-6JXasQJgu-deGLH4<+tQQ(B4^saGtXG~>j z@;I9pMnQ8wgb^Pj78u6Go>6_&%&LO9qa|*mhW-g#TAFr>{p#cjYv4W~$i;*_Ex#R6 z?)Y%%0kD{CWLST;3G}<|9PwxevnrN$Rsqvw;CXX*cU%~yS;x9I3B{6D%!p95@7hMJ zj<2fAmr5A55bKls_8j)qfLD7gfY1hY-O<7HOr7uuP@!7Id!++!37m@Vd zgp?!p>->VO#w7P<3vw+z9G*o}K_C4XLK$9v0icUMFcJcM*$rp_kjBeW#F;p{=RQg* z_fSc9f$7WV%8Y+toNaS<)veYys?X0=a~^XB!Fbh3Nc{P12TbooDNd-Y!R?&hrh zmczEFRZh_Ffq>;@X}Zfu14j-6dLk@IGi8=~+^vplP$zMY=u%kfe8=#DeBB6AJR0F{OteQ3SfF5^2S`(=~J-a{(1+2M$SxX((sT&$o_T?-6y;j8l?>w%HM&;qO|f7O{`Piqt|jddA`8c0XPnv ze!Cej+fkU$*ie{r^W4EL8}8{&Tl9qED~wD#c?$8lpadg!s21-+t18kc4I57ZC6fV>We94 zXBKkC2$@ktSg*=EMVvS0!I3I~0+I*XCl=o3_x)RGqaqqi;ED|;FTq=s9!`mxtaF9Y(Z}r)a>$0 z2rK*SGgi-+()%^d`~xb*MTP+l>U=%MWFPebQ=T@qtLIn}Jhl(kXNq)R0KE-T4Dd=P zzS%RwBuMf$S+kf8OZyZ;KM`EU+3JS#MJ_1-WqpHoAoZ69#fgg#M-Sfas+^xqk@{io zj(%j#9LK(BV(c;GaaD#k!1TXN-TcK=e5^SB#d-@*KVI>1cD!7-+H zo>$EGD!s0Iue04-{^<)(G{^pPivG-nl+fa#*z>tF|1z%*uG8h}#|ZnIKo-YDeglTw!cZ1WCx+po0Q6Pmh4}|gqVZ!xWPC61DT|6tCa1cttw&Mu* zz_)ZyyerTpUnR$wxnkc6*f{KT>8ZF+Rha3YstEFRm2r-&ehPBKke&tfz=BNjhYPSR zIh^$g{99czJTeec^k7qLaC<-7OuI)% zWE|~|ys{U~z;7^P0}{L&?i{~kz9JaHhgon=2985|o{yA?JU5P@)6HXODj52+NnIcQ z-zkfifRe&baae)q0d8UJ)&ev*bRpJ&8$|^4z#H7v3%`sG>JT%sb|HAk3{! z&S*OWTyb{>gd&Z97>XLOeA{PqDqRt+*euz{N`Nb?+Y|q-ZDq#bspT0)H*fb_nEAb9 zdvjtdfPeipI1q10nsq#&LXULd^-0W3mUI9~Dr=g;0He&nG?pl~lN`)9$y$^U@Hr~C zxr;Yo=)hrt3a?$?Us7i)H0cO)%~ioX6%YYGu$oA$xJTNbbrHY3(T= zl(?LeF>;~e?YLxdWo5LKi!$a$I#epyjhtS}YoQ2f;GwCo>Ic!m;|EEw<6NHL!n+2oJYMGsoL2m!?I+a&cnxN5ccsUq zJh*f(h(59ik*)1{R5F^%N!RsuGa_Xvzb*1fPNoKD3VP{_0clUlqAjH;Nv4Tq;&x9SRArIu)?DKf3bB=!GU%`m`*aW zZQHhuiEZ09z8DkRP9~h##>BR5V`A>VyR{d)wdc00&fTdx@6%mRFIopM%(A}g%G|Yz_;nt?}bu&LY4pDo@gV z#7`?+gEdPzKrL=6(%Lz2D+cA>`0yGvKz2)88XoS2cOG?0CYGvf^zTve*^|RU$jk8pYVqN{%23iAUH0q1#N6#10|4hncRZwKpH;5o0+D`wE zML{?tXKVYVGJCK+3|%nj9rf#HnEJsQAB1Ol*v- zhN9+f#^mY_)?UPlPUa5(yTIt^Vrl5);%H-T>c*sG>}G03%$&R@Z3fDjEGfeXqsGB0 z&CDXt!kHW(Lyf?}z{07H>Nc2f=?9U66nLMEyG#4#^NyF5YroYyN%b|COSI%sC020R;h3AQS5zsSW@E;f65!PUg@Fay|tC z;Ro=}wg6vTJ@HH-ypKhg1$otj_+NWVN67ga#zLPjOxg8s<$GXA{ zPlDCGdzE&nk8ka*^Qrti`}^}s(yp*tYKus`#x_ng^P(8P7v8HT@L%4$P?B!SOzW8;a9_O|ODZKZ1O{)$V~hxgsS&jHQ(dsxV`muF{DKlxzpo}Ru$#oj7T4vz($oSnVR zEYeU^N(S1AiS7^1Ay~vr5AY8}m-eReyA>J{6p|g?W^gA>!E)Y`U#M&gY^o~`C7*FN zfgEUq==M%Q-`KFDCYw9@C*qc@LguOll0z`dk=#@m7jb?zvuu7!8VYmf^BH&TPwn%U z({iAAqp5lVG$hGGX4~e*2vThj&C@wb9QXIn^2V-FG2(=9r4GE2p=fV9I>y0+18;wS zpQxxPoMUxNNvU_YGN#h!c~&;>R2v9$z|3sE$G!1A6LAIBjUG5+qD%ZgG#y7oNxa|1&c!$z)*8KcJyW`hTI*81ZgaBbcF`gj;W8Fn89w9>;Kv7Wv zgRrHYh)qb?LUc>Y9&hb$cxux2n>IXEG7tX%smLliM2U7Lx6eI&CHvV)e?)I%Bp*rp z{V=3e&tMAPxfQOLl$dyTwIcLEM1P8f0PE)^#;?*=S{`^U6?rMVldQe#VYrCD{fzHw z`XUM63befSC&$yuItUV!>>FjDW?o$T zufHNbT%M`X0W!U4oFvp>T{T~|d_~D(?G+UMzxg@QvS=RvH4-pYpC2v0R&v;UWBSG` zyjp4ey$fH^AhH;CeseuPP`4HeWq!rfM_aK*Et7;euK1v2G4=HF?chnO17s8^UwXq} zk#w2p;8*tXq@WtiVRIRDp}{l!WQ&#G!q+eu+$v)83fyMzrH521{h|tS$WcBFbSe0` zb}^@;-!0NP7=FkZ97gg`kWuAlwpnCDX%OsWF5$j&^O3jnsc2I-MYmS z3LOn*L%I#0)E={tWn*!y0AO1%06Ov+Dp3vpFj&3dRn6>)-`hUvBVQ4OJtB@iSa<%D zdZCvJj>kQ^JCd=7{~U9A{6_l{IXEdG)=2L?f68;NRS#zwQ@ zds^#A5bK%eY~-f2YQHLDc4sstQON?K6;~g+QNKDN4TY^?W}a3sK+ceR@5XYy?rQnY6q3g5}lXdx%fKp?G^Mz@&h29dpQi#XG?jmdvpF2bM z3~Fqqh=`6^V1>uy^#QaILLc%+Gs+H4$Ul=vdQz6ArCt|MsW**hF_w~tQI}X_?tQJ< zzD4(u7MnO+qt#GPpm8e47%v8La{u)xq_R@FfBgV`Xd(R6xgg&c`zu}GpSJ3vtzd<2F^9yctGF4LYXp8eA8wEr$N{^RqpO&rPF zzQ)KY{%Kh8gVa$8JmGf=)+KeyvN#bdiVZv^E`rNNuT^Xb@So75E2M~Ey`wNWXPao# z_lxuBrIi5v)%rqs!TR_0q#0eYFnXG;@x)OTN|{$jZF$ytVph(%2&{jJNjLGkfYNRI zlf2ud@%(#SXC;;BYz<^8`_RJHi3BEV%z-X*y5%U%A!H|0x^2*JwA7Ct!Q|mg1f{-3YaH zyxMf%p)SCJB%eQ@HfkdbNd-UukcY!t5p=c)Wb0GA0w!+vvGoz+R@t!E5-ZCsiYfm| z1v*I5F~0v&vYl#Z`aBkn=mc|i1cOE3VME{@<0bU2`*Wq-jpd;Uf-ptIYAW_BZN^08 z@@OS>M!x+lcxNK3EIf>%Oa6no=ELGOJdP*@Om^Sg(?gL?_SL z?fLoo0yiFEmab+`jX@8{2HO))d&9x=HrJt;<~qK*tIJLv_P%lYC1)ReZ2j1T!sP+N z7BI!jQa?t<&qf(~tA$+1I{c~{MXyM*;*fEWOh`>C@K->-uKTHfsfn8095K)d;$h7C zS#tGokZk>I_om<5WQ-Ri#vX~;2xgktZguw82E^WDhL8L?A&;M$gZb78dii)vS=eWs zD_lBvvzuR z(Uw8?Uh*%IwoG+p%sn{Qf$6r;pHb+6pPtXk;|$O>T7M$Gs-03K#h1}HA|e)G(+ZiI z(->2vz|#?urd~S5Bk=GNfcG)hGmB&u)8EaYD=?~&Gf[E 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 From 8ef875b1f4580c5c89f346f7114e3ddb538fd020 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 28 Jun 2012 14:45:12 +0000 Subject: [PATCH 004/127] Monotone-Parent: c69af3e4b83d5cab3a52701fb736c8a149697338 Monotone-Revision: 58f1829bce5e146423ed657d76063f09b7596385 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-06-28T14:45:12 Monotone-Branch: ca.inverse.sogo --- SOPE/GDLContentStore/GCSSpecialQueries.h | 11 +++++++++++ SOPE/GDLContentStore/GCSSpecialQueries.m | 21 ++++++--------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/SOPE/GDLContentStore/GCSSpecialQueries.h b/SOPE/GDLContentStore/GCSSpecialQueries.h index 08c2c3e69..24330d848 100644 --- a/SOPE/GDLContentStore/GCSSpecialQueries.h +++ b/SOPE/GDLContentStore/GCSSpecialQueries.h @@ -48,4 +48,15 @@ @end +/* interfaces exposed so that categories can be created from them */ +@interface GCSPostgreSQLSpecialQueries : GCSSpecialQueries +@end + +@interface GCSMySQLSpecialQueries : GCSSpecialQueries +@end + +@interface GCSOracleSpecialQueries : GCSSpecialQueries +@end + + #endif /* GCSSPECIALQUERIES_H */ diff --git a/SOPE/GDLContentStore/GCSSpecialQueries.m b/SOPE/GDLContentStore/GCSSpecialQueries.m index 7bd771c7c..34a29ab82 100644 --- a/SOPE/GDLContentStore/GCSSpecialQueries.m +++ b/SOPE/GDLContentStore/GCSSpecialQueries.m @@ -27,15 +27,6 @@ #import "GCSSpecialQueries.h" -@interface GCSPostgreSQLSpecialQueries : GCSSpecialQueries -@end - -@interface GCSMySQLSpecialQueries : GCSSpecialQueries -@end - -@interface GCSOracleSpecialQueries : GCSSpecialQueries -@end - @implementation EOAdaptorChannel (GCSSpecialQueries) - (GCSSpecialQueries *) specialQueries @@ -163,7 +154,7 @@ { static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" - @" c_name VARCHAR (255) NOT NULL PRIMARY KEY,\n" + @" c_name VARCHAR (255) PRIMARY KEY,\n" @" c_content TEXT NOT NULL,\n" @" c_creationdate INT4 NOT NULL,\n" @" c_lastmodified INT4 NOT NULL,\n" @@ -190,7 +181,7 @@ { static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (" - @" c_id VARCHAR(255) NOT NULL PRIMARY KEY," + @" c_id VARCHAR(255) PRIMARY KEY," @" c_value VARCHAR(255) NOT NULL," @" c_creationdate INT4 NOT NULL," @" c_lastseen INT4 NOT NULL)"); @@ -257,7 +248,7 @@ { static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" - @" c_name VARCHAR (255) NOT NULL PRIMARY KEY,\n" + @" c_name VARCHAR (255) PRIMARY KEY,\n" @" c_content MEDIUMTEXT NOT NULL,\n" @" c_creationdate INT NOT NULL,\n" @" c_lastmodified INT NOT NULL,\n" @@ -284,7 +275,7 @@ { static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (" - @" c_id VARCHAR(255) NOT NULL PRIMARY KEY," + @" c_id VARCHAR(255) PRIMARY KEY," @" c_value VARCHAR(255) NOT NULL," @" c_creationdate INT NOT NULL," @" c_lastseen INT NOT NULL)"); @@ -351,7 +342,7 @@ { static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" - @" c_name VARCHAR2 (255) NOT NULL PRIMARY KEY,\n" + @" c_name VARCHAR2 (255) PRIMARY KEY,\n" @" c_content CLOB NOT NULL,\n" @" c_creationdate INTEGER NOT NULL,\n" @" c_lastmodified INTEGER NOT NULL,\n" @@ -377,7 +368,7 @@ { static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (" - @" c_id VARCHAR2(255) NOT NULL PRIMARY KEY," + @" c_id VARCHAR2(255) PRIMARY KEY," @" c_value VARCHAR2(255) NOT NULL," @" c_creationdate INTEGER NOT NULL," @" c_lastseen INTEGER NOT NULL)"); From 79552f8ff36f7cebeffc4aa57eecb599caba6f2a Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 28 Jun 2012 14:45:45 +0000 Subject: [PATCH 005/127] Monotone-Parent: 58f1829bce5e146423ed657d76063f09b7596385 Monotone-Revision: 8bf030be6f5baed09d67ad6a173017ace25834c7 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-06-28T14:45:45 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++++ SoObjects/SOGo/SOGoObject.m | 3 +++ 2 files changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index 0dcca9839..f749e20f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-06-28 Wolfgang Sourdeau + + * SoObjects/SOGo/SOGoObject.m (-initWithName:inContainer:): make + sure that "_name" is neither nil nor empty. + 2012-06-12 Wolfgang Sourdeau * SoObjects/SOGo/SOGoGroup.m diff --git a/SoObjects/SOGo/SOGoObject.m b/SoObjects/SOGo/SOGoObject.m index 8736cf050..b7b42ba9f 100644 --- a/SoObjects/SOGo/SOGoObject.m +++ b/SoObjects/SOGo/SOGoObject.m @@ -177,6 +177,9 @@ { if ((self = [self init])) { + if ([_name length] == 0) + [NSException raise: NSInvalidArgumentException + format: @"'_name' must not be an empty string"]; context = [[WOApplication application] context]; nameInContainer = [_name copy]; container = _container; From 591306481b520cb11a1896c9cafb75d0a14d4abe Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 28 Jun 2012 14:46:37 +0000 Subject: [PATCH 006/127] Monotone-Parent: 8bf030be6f5baed09d67ad6a173017ace25834c7 Monotone-Revision: 3f8608c82d9c379cc9e0fea6ffe853cc1949a24b Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-06-28T14:46:37 Monotone-Branch: ca.inverse.sogo --- Main/SOGo.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Main/SOGo.m b/Main/SOGo.m index f2b3f9e0a..8fe51d242 100644 --- a/Main/SOGo.m +++ b/Main/SOGo.m @@ -201,6 +201,7 @@ static BOOL debugLeaks; fileSuffix = [channelURL scheme]; tc = [cm acquireOpenChannelForURL: channelURL]; + /* FIXME: make use of [EOChannelAdaptor describeTableNames] instead */ tableName = [url lastPathComponent]; if ([tc evaluateExpressionX: [NSString stringWithFormat: @"SELECT count(*) FROM %@", From 95a443d89a87b03a27f9f1fa166a4ff681522680 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 29 Jun 2012 17:59:38 +0000 Subject: [PATCH 007/127] Monotone-Parent: 3f8608c82d9c379cc9e0fea6ffe853cc1949a24b Monotone-Revision: 905276f295d6f28a6946297f6a7af9ad60f71842 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-06-29T17:59:38 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 8 + OpenChange/EOQualifier+MAPI.h | 4 +- OpenChange/EOQualifier+MAPI.m | 30 +- OpenChange/GCSSpecialQueries+OpenChange.h | 34 ++ OpenChange/GCSSpecialQueries+OpenChange.m | 102 ++++ OpenChange/GNUmakefile | 34 +- OpenChange/MAPIStoreCalendarAttachment.m | 6 +- OpenChange/MAPIStoreCalendarMessage.m | 4 +- OpenChange/MAPIStoreContactsMessage.m | 4 +- OpenChange/MAPIStoreContext.m | 33 +- ...BaseContext.h => MAPIStoreDBBaseContext.h} | 12 +- OpenChange/MAPIStoreDBBaseContext.m | 116 +++++ ...APIStoreFSFolder.h => MAPIStoreDBFolder.h} | 12 +- ...APIStoreFSFolder.m => MAPIStoreDBFolder.m} | 87 ++-- ...FolderTable.h => MAPIStoreDBFolderTable.h} | 12 +- ...FolderTable.m => MAPIStoreDBFolderTable.m} | 8 +- ...IStoreFSMessage.h => MAPIStoreDBMessage.h} | 14 +- ...IStoreFSMessage.m => MAPIStoreDBMessage.m} | 108 +++- ...ssageTable.h => MAPIStoreDBMessageTable.h} | 12 +- ...ssageTable.m => MAPIStoreDBMessageTable.m} | 16 +- OpenChange/MAPIStoreFAIMessage.h | 4 +- OpenChange/MAPIStoreFAIMessageTable.h | 4 +- OpenChange/MAPIStoreFSBaseContext.m | 79 --- OpenChange/MAPIStoreFallbackContext.h | 4 +- OpenChange/MAPIStoreFallbackContext.m | 15 +- OpenChange/MAPIStoreFolder.h | 21 +- OpenChange/MAPIStoreFolder.m | 190 ++++--- OpenChange/MAPIStoreGCSFolder.h | 2 +- OpenChange/MAPIStoreGCSFolder.m | 12 +- OpenChange/MAPIStoreMailAttachment.h | 2 + OpenChange/MAPIStoreMailAttachment.m | 9 +- OpenChange/MAPIStoreMailFolder.h | 2 +- OpenChange/MAPIStoreMailFolder.m | 36 +- OpenChange/MAPIStoreMailMessage.m | 6 +- OpenChange/MAPIStoreMailMessageTable.m | 2 +- OpenChange/MAPIStoreMailVolatileMessage.h | 4 +- OpenChange/MAPIStoreMailVolatileMessage.m | 184 +++++-- OpenChange/MAPIStoreMessage.h | 4 +- OpenChange/MAPIStoreMessage.m | 12 +- OpenChange/MAPIStoreMessageTable.h | 1 + OpenChange/MAPIStoreMessageTable.m | 57 +++ OpenChange/MAPIStoreNotesContext.h | 4 +- OpenChange/MAPIStoreNotesFolder.h | 4 +- OpenChange/MAPIStoreNotesMessage.h | 4 +- OpenChange/MAPIStoreNotesMessage.m | 17 - OpenChange/MAPIStoreObject.h | 44 +- OpenChange/MAPIStoreObject.m | 224 ++------ OpenChange/MAPIStorePermissionsTable.m | 4 +- OpenChange/MAPIStoreSOGoObject.h | 89 ++++ OpenChange/MAPIStoreSOGoObject.m | 255 +++++++++ OpenChange/MAPIStoreTable.h | 2 - OpenChange/MAPIStoreTable.m | 55 -- OpenChange/MAPIStoreUserContext.h | 7 + OpenChange/MAPIStoreUserContext.m | 77 ++- OpenChange/MAPIStoreVolatileMessage.h | 37 -- OpenChange/MAPIStoreVolatileMessage.m | 208 -------- OpenChange/NSObject+PropertyList.m | 182 +++++++ ...{SOGoMAPIFSFolder.h => SOGoMAPIDBFolder.h} | 41 +- OpenChange/SOGoMAPIDBFolder.m | 402 +++++++++++++++ OpenChange/SOGoMAPIDBObject.h | 83 +++ OpenChange/SOGoMAPIDBObject.m | 483 ++++++++++++++++++ OpenChange/SOGoMAPIFSFolder.m | 439 ---------------- OpenChange/SOGoMAPIFSMessage.h | 47 -- OpenChange/SOGoMAPIFSMessage.m | 238 --------- ...MAPIVolatileMessage.h => SOGoMAPIObject.h} | 26 +- ...MAPIVolatileMessage.m => SOGoMAPIObject.m} | 50 +- OpenChange/plreader.m | 151 +----- 67 files changed, 2606 insertions(+), 1873 deletions(-) create mode 100644 OpenChange/GCSSpecialQueries+OpenChange.h create mode 100644 OpenChange/GCSSpecialQueries+OpenChange.m rename OpenChange/{MAPIStoreFSBaseContext.h => MAPIStoreDBBaseContext.h} (76%) create mode 100644 OpenChange/MAPIStoreDBBaseContext.m rename OpenChange/{MAPIStoreFSFolder.h => MAPIStoreDBFolder.h} (78%) rename OpenChange/{MAPIStoreFSFolder.m => MAPIStoreDBFolder.m} (75%) rename OpenChange/{MAPIStoreFSFolderTable.h => MAPIStoreDBFolderTable.h} (76%) rename OpenChange/{MAPIStoreFSFolderTable.m => MAPIStoreDBFolderTable.m} (85%) rename OpenChange/{MAPIStoreFSMessage.h => MAPIStoreDBMessage.h} (74%) rename OpenChange/{MAPIStoreFSMessage.m => MAPIStoreDBMessage.m} (59%) rename OpenChange/{MAPIStoreFSMessageTable.h => MAPIStoreDBMessageTable.h} (76%) rename OpenChange/{MAPIStoreFSMessageTable.m => MAPIStoreDBMessageTable.m} (92%) delete mode 100644 OpenChange/MAPIStoreFSBaseContext.m create mode 100644 OpenChange/MAPIStoreSOGoObject.h create mode 100644 OpenChange/MAPIStoreSOGoObject.m delete mode 100644 OpenChange/MAPIStoreVolatileMessage.h delete mode 100644 OpenChange/MAPIStoreVolatileMessage.m create mode 100644 OpenChange/NSObject+PropertyList.m rename OpenChange/{SOGoMAPIFSFolder.h => SOGoMAPIDBFolder.h} (52%) create mode 100644 OpenChange/SOGoMAPIDBFolder.m create mode 100644 OpenChange/SOGoMAPIDBObject.h create mode 100644 OpenChange/SOGoMAPIDBObject.m delete mode 100644 OpenChange/SOGoMAPIFSFolder.m delete mode 100644 OpenChange/SOGoMAPIFSMessage.h delete mode 100644 OpenChange/SOGoMAPIFSMessage.m rename OpenChange/{SOGoMAPIVolatileMessage.h => SOGoMAPIObject.h} (63%) rename OpenChange/{SOGoMAPIVolatileMessage.m => SOGoMAPIObject.m} (58%) diff --git a/ChangeLog b/ChangeLog index f749e20f6..a2d6e0ffe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2012-06-29 Wolfgang Sourdeau + + * OpenChange/SOGoMAPIDBObject.m: new class module that replaced + SOGoMAPIFSMessage. + + * OpenChange/SOGoMAPIDBFolder.m: new class module that replaced + SOGoMAPIFSFolder. + 2012-06-28 Wolfgang Sourdeau * SoObjects/SOGo/SOGoObject.m (-initWithName:inContainer:): make diff --git a/OpenChange/EOQualifier+MAPI.h b/OpenChange/EOQualifier+MAPI.h index cbe65b915..72f368b63 100644 --- a/OpenChange/EOQualifier+MAPI.h +++ b/OpenChange/EOQualifier+MAPI.h @@ -25,11 +25,11 @@ #import -@class SOGoMAPIVolatileMessage; +@class SOGoMAPIDBObject; @interface EOQualifier (MAPIStoreRestrictions) -- (BOOL) evaluateMAPIVolatileMessage: (SOGoMAPIVolatileMessage *) message; +- (BOOL) evaluateSOGoMAPIDBObject: (SOGoMAPIDBObject *) object; @end diff --git a/OpenChange/EOQualifier+MAPI.m b/OpenChange/EOQualifier+MAPI.m index 0584e2789..8707dd788 100644 --- a/OpenChange/EOQualifier+MAPI.m +++ b/OpenChange/EOQualifier+MAPI.m @@ -28,28 +28,28 @@ #import -#import "SOGoMAPIVolatileMessage.h" +#import "EOBitmaskQualifier.h" +#import "SOGoMAPIDBObject.h" #import "EOQualifier+MAPI.h" -#import "EOBitmaskQualifier.h" @implementation EOQualifier (MAPIStoreRestrictions) -- (BOOL) _evaluateMAPIVolatileMessageProperties: (NSDictionary *) properties +- (BOOL) _evaluateSOGoMAPIDBObject: (NSDictionary *) properties { [self subclassResponsibility: _cmd]; return NO; } -- (BOOL) evaluateMAPIVolatileMessage: (SOGoMAPIVolatileMessage *) message +- (BOOL) evaluateSOGoMAPIDBObject: (SOGoMAPIDBObject *) object { NSDictionary *properties; BOOL rc; - [self logWithFormat: @"evaluating message '%@'", message]; + [self logWithFormat: @"evaluating object '%@'", object]; - properties = [message properties]; - rc = [self _evaluateMAPIVolatileMessageProperties: properties]; + properties = [object properties]; + rc = [self _evaluateSOGoMAPIDBObject: properties]; [self logWithFormat: @" evaluation result: %d", rc]; @@ -60,7 +60,7 @@ @implementation EOAndQualifier (MAPIStoreRestrictionsPrivate) -- (BOOL) _evaluateMAPIVolatileMessageProperties: (NSDictionary *) properties +- (BOOL) _evaluateSOGoMAPIDBObject: (NSDictionary *) properties { NSUInteger i; BOOL rc; @@ -69,7 +69,7 @@ for (i = 0; rc && i < count; i++) rc = [[qualifiers objectAtIndex: i] - _evaluateMAPIVolatileMessageProperties: properties]; + _evaluateSOGoMAPIDBObject: properties]; return rc; } @@ -78,7 +78,7 @@ @implementation EOOrQualifier (MAPIStoreRestrictionsPrivate) -- (BOOL) _evaluateMAPIVolatileMessageProperties: (NSDictionary *) properties +- (BOOL) _evaluateSOGoMAPIDBObject: (NSDictionary *) properties { NSUInteger i; BOOL rc; @@ -87,7 +87,7 @@ for (i = 0; !rc && i < count; i++) rc = [[qualifiers objectAtIndex: i] - _evaluateMAPIVolatileMessageProperties: properties]; + _evaluateSOGoMAPIDBObject: properties]; return rc; } @@ -96,9 +96,9 @@ @implementation EONotQualifier (MAPIStoreRestrictionsPrivate) -- (BOOL) _evaluateMAPIVolatileMessageProperties: (NSDictionary *) properties +- (BOOL) _evaluateSOGoMAPIDBObject: (NSDictionary *) properties { - return ![qualifier _evaluateMAPIVolatileMessageProperties: properties]; + return ![qualifier _evaluateSOGoMAPIDBObject: properties]; } @end @@ -107,7 +107,7 @@ typedef BOOL (*EOComparator) (id, SEL, id); -- (BOOL) _evaluateMAPIVolatileMessageProperties: (NSDictionary *) properties +- (BOOL) _evaluateSOGoMAPIDBObject: (NSDictionary *) properties { id finalKey; id propValue; @@ -136,7 +136,7 @@ typedef BOOL (*EOComparator) (id, SEL, id); @implementation EOBitmaskQualifier (MAPIStoreRestrictionsPrivate) -- (BOOL) _evaluateMAPIVolatileMessageProperties: (NSDictionary *) properties +- (BOOL) _evaluateSOGoMAPIDBObject: (NSDictionary *) properties { NSNumber *propTag; id propValue; diff --git a/OpenChange/GCSSpecialQueries+OpenChange.h b/OpenChange/GCSSpecialQueries+OpenChange.h new file mode 100644 index 000000000..4caaca54b --- /dev/null +++ b/OpenChange/GCSSpecialQueries+OpenChange.h @@ -0,0 +1,34 @@ +/* GCSSpecialQueries+OpenChange.h - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef GCSSPECIALQUERIES_OPENCHANGE_H +#define GCSSPECIALQUERIES_OPENCHANGE_H + +#import + +@interface GCSSpecialQueries (OpenChangeHelpers) + +- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName; + +@end + +#endif /* GCSSPECIALQUERIES_OPENCHANGE_H */ diff --git a/OpenChange/GCSSpecialQueries+OpenChange.m b/OpenChange/GCSSpecialQueries+OpenChange.m new file mode 100644 index 000000000..aa336bf99 --- /dev/null +++ b/OpenChange/GCSSpecialQueries+OpenChange.m @@ -0,0 +1,102 @@ +/* GCSSpecialQueries+OpenChange.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import + +#import "GCSSpecialQueries+OpenChange.h" + +@interface GCSPostgreSQLSpecialQueries (OpenChangeHelpers) +@end + +@interface GCSMySQLSpecialQueries (OpenChangeHelpers) +@end + +@interface GCSOracleSpecialQueries (OpenChangeHelpers) +@end + +@implementation GCSSpecialQueries (OpenChangeHelpers) + +- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +@end + +@implementation GCSPostgreSQLSpecialQueries (OpenChangeHelpers) + +- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName +{ + static NSString *sqlFolderFormat + = (@"CREATE TABLE %@ (" + @" c_path VARCHAR(255) PRIMARY KEY," + @" c_type SMALLINT NOT NULL," + @" c_creationdate INT4 NOT NULL," + @" c_lastmodified INT4 NOT NULL," + @" c_version INT4 NOT NULL DEFAULT 0," + @" c_deleted SMALLINT NOT NULL DEFAULT 0," + @" c_content TEXT)"); + + return [NSString stringWithFormat: sqlFolderFormat, tableName]; +} + +@end + +@implementation GCSMySQLSpecialQueries (OpenChangeHelpers) + +- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName +{ + static NSString *sqlFolderFormat + = (@"CREATE TABLE %@ (" + @" c_path VARCHAR(255) PRIMARY KEY," + @" c_type TINYINT NOT NULL," + @" c_creationdate INT NOT NULL," + @" c_lastmodified INT NOT NULL," + @" c_version INT NOT NULL DEFAULT 0," + @" c_deleted TINYINT NOT NULL DEFAULT 0," + @" c_content TEXT)"); + + return [NSString stringWithFormat: sqlFolderFormat, tableName]; +} + +@end + +@implementation GCSOracleSpecialQueries (OpenChangeHelpers) + +- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName +{ + static NSString *sqlFolderFormat + = (@"CREATE TABLE %@ (" + @" c_path VARCHAR2(255) PRIMARY KEY," + @" c_type SMALLINT NOT NULL," + @" c_creationdate INT4 NOT NULL," + @" c_lastmodified INT4 NOT NULL," + @" c_version INT4 NOT NULL DEFAULT 0," + @" c_deleted SMALLINT NOT NULL DEFAULT 0," + @" c_content CLOB)"); + + return [NSString stringWithFormat: sqlFolderFormat, tableName]; +} + +@end diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 0f3fb1a39..6f4803ba9 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -41,9 +41,11 @@ $(SOGOBACKEND)_OBJC_FILES += \ MAPIStoreSamDBUtils.m \ MAPIStoreUserContext.m \ \ - SOGoMAPIVolatileMessage.m \ - SOGoMAPIFSFolder.m \ - SOGoMAPIFSMessage.m \ + SOGoMAPIObject.m \ + \ + SOGoMAPIDBObject.m \ + SOGoMAPIDBMessage.m \ + SOGoMAPIDBFolder.m \ \ MAPIStoreAppointmentWrapper.m \ MAPIStoreAttachment.m \ @@ -53,18 +55,17 @@ $(SOGOBACKEND)_OBJC_FILES += \ MAPIStoreFolder.m \ MAPIStoreMessage.m \ MAPIStoreObject.m \ + MAPIStoreSOGoObject.m \ MAPIStoreTable.m \ MAPIStoreMessageTable.m \ MAPIStoreFolderTable.m \ MAPIStorePermissionsTable.m \ \ - MAPIStoreVolatileMessage.m \ - \ - MAPIStoreFSBaseContext.m \ - MAPIStoreFSFolder.m \ - MAPIStoreFSFolderTable.m \ - MAPIStoreFSMessage.m \ - MAPIStoreFSMessageTable.m \ + MAPIStoreDBBaseContext.m \ + MAPIStoreDBFolder.m \ + MAPIStoreDBFolderTable.m \ + MAPIStoreDBMessage.m \ + MAPIStoreDBMessageTable.m \ \ MAPIStoreFAIMessage.m \ MAPIStoreFAIMessageTable.m \ @@ -113,7 +114,10 @@ $(SOGOBACKEND)_OBJC_FILES += \ NSValue+MAPIStore.m \ \ EOBitmaskQualifier.m \ - EOQualifier+MAPI.m \ + \ + GCSSpecialQueries+OpenChange.m\ + \ + EOQualifier+MAPI.m $(SOGOBACKEND)_RESOURCE_FILES += \ @@ -145,7 +149,13 @@ PLREADER_TOOL = plreader $(PLREADER_TOOL)_OBJC_FILES += \ plreader.m \ -TEST_TOOL_NAME += $(PLREADER_TOOL) +DBMSGREADER_TOOL = dbmsgreader +$(DBMSGREADER_TOOL)_OBJC_FILES += \ + dbmsgreader.m + +$(DBMSGREADER_TOOL)_LIB_DIRS += -L../SoObjects/SOGo/ -lSOGo -lNGObjWeb + +TEST_TOOL_NAME += $(PLREADER_TOOL) $(DBMSGREADER_TOOL) ### cflags and libs LIBMAPI_CFLAGS = $(shell pkg-config libmapi --cflags) diff --git a/OpenChange/MAPIStoreCalendarAttachment.m b/OpenChange/MAPIStoreCalendarAttachment.m index 63aa68df8..1ba40ac17 100644 --- a/OpenChange/MAPIStoreCalendarAttachment.m +++ b/OpenChange/MAPIStoreCalendarAttachment.m @@ -67,10 +67,10 @@ { MAPIStoreEmbeddedMessage *msg; - if (isNew) - msg = nil; - else + // if (isNew) msg = nil; + // else + // msg = nil; return msg; } diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index daa9cc83d..5d2eb48a6 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -1111,9 +1111,7 @@ newAid = [[self attachmentKeys] count]; newAttachment = [MAPIStoreCalendarAttachment - mapiStoreObjectWithSOGoObject: nil - inContainer: self]; - [newAttachment setIsNew: YES]; + mapiStoreObjectInContainer: self]; [newAttachment setAID: newAid]; newKey = [NSString stringWithFormat: @"%ul", newAid]; [attachmentParts setObject: newAttachment diff --git a/OpenChange/MAPIStoreContactsMessage.m b/OpenChange/MAPIStoreContactsMessage.m index c8af5c05b..99f297ea1 100644 --- a/OpenChange/MAPIStoreContactsMessage.m +++ b/OpenChange/MAPIStoreContactsMessage.m @@ -35,6 +35,7 @@ #import #import +#import "MAPIStoreAttachment.h" #import "MAPIStoreContactsAttachment.h" #import "MAPIStoreContactsFolder.h" #import "MAPIStorePropertySelectors.h" @@ -767,8 +768,7 @@ || [encoding isEqualToString: @"BASE64"]) { attachment = [MAPIStoreContactsAttachment - mapiStoreObjectWithSOGoObject: nil - inContainer: self]; + mapiStoreObjectInContainer: self]; [attachment setAID: 0]; [attachment setPhoto: photo]; [attachmentParts setObject: attachment forKey: @"photo"]; diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m index 1817658ea..a3704289b 100644 --- a/OpenChange/MAPIStoreContext.m +++ b/OpenChange/MAPIStoreContext.m @@ -28,11 +28,9 @@ #import #import +#import #import -#import "SOGoMAPIFSFolder.h" -#import "SOGoMAPIFSMessage.h" - #import "MAPIStoreAttachment.h" // #import "MAPIStoreAttachmentTable.h" #import "MAPIStoreFallbackContext.h" @@ -433,25 +431,29 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) [self ensureContextFolder]; currentFolder = [self rootSOGoFolder]; + [containersBag addObject: currentFolder]; path = [contextUrl path]; if ([path hasPrefix: @"/"]) path = [path substringFromIndex: 1]; if ([path hasSuffix: @"/"]) path = [path substringToIndex: [path length] - 1]; - pathComponents = [path componentsSeparatedByString: @"/"]; - max = [pathComponents count]; - for (count = 0; currentFolder && count < max; count++) + if ([path length] > 0) { - [woContext setClientObject: currentFolder]; - currentFolder - = [currentFolder lookupName: [pathComponents objectAtIndex: count] - inContext: woContext + pathComponents = [path componentsSeparatedByString: @"/"]; + max = [pathComponents count]; + for (count = 0; currentFolder && count < max; count++) + { + [woContext setClientObject: currentFolder]; + currentFolder = [currentFolder + lookupName: [pathComponents objectAtIndex: count] + inContext: woContext acquire: NO]; - if ([currentFolder isKindOfClass: SOGoObjectK]) /* class common to all - SOGo folder types */ - [containersBag addObject: currentFolder]; - else - currentFolder = nil; + if ([currentFolder isKindOfClass: SOGoObjectK]) /* class common to all + SOGo folder types */ + [containersBag addObject: currentFolder]; + else + currentFolder = nil; + } } if (currentFolder) @@ -460,7 +462,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) mapiStoreObjectWithSOGoObject: currentFolder inContainer: nil]; [baseFolder setContext: self]; - *folderPtr = baseFolder; rc = MAPISTORE_SUCCESS; } diff --git a/OpenChange/MAPIStoreFSBaseContext.h b/OpenChange/MAPIStoreDBBaseContext.h similarity index 76% rename from OpenChange/MAPIStoreFSBaseContext.h rename to OpenChange/MAPIStoreDBBaseContext.h index ecc63d1e6..62f5bd489 100644 --- a/OpenChange/MAPIStoreFSBaseContext.h +++ b/OpenChange/MAPIStoreDBBaseContext.h @@ -1,6 +1,6 @@ -/* MAPIStoreFSBaseContext.h - this file is part of SOGo +/* MAPIStoreDBBaseContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -20,13 +20,13 @@ * Boston, MA 02111-1307, USA. */ -#ifndef MAPISTOREFSBASECONTEXT_H -#define MAPISTOREFSBASECONTEXT_H +#ifndef MAPISTOREDBBASECONTEXT_H +#define MAPISTOREDBBASECONTEXT_H #import "MAPIStoreContext.h" -@interface MAPIStoreFSBaseContext : MAPIStoreContext +@interface MAPIStoreDBBaseContext : MAPIStoreContext @end -#endif /* MAPISTOREFSBASECONTEXT_H */ +#endif /* MAPISTOREDBBASECONTEXT_H */ diff --git a/OpenChange/MAPIStoreDBBaseContext.m b/OpenChange/MAPIStoreDBBaseContext.m new file mode 100644 index 000000000..d82538083 --- /dev/null +++ b/OpenChange/MAPIStoreDBBaseContext.m @@ -0,0 +1,116 @@ +/* MAPIStoreDBBaseContext.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* A generic parent class for all context that will store their data on the + disk in the form of a plist. */ + +#import +#import +#import + +#import + +#import "MAPIStoreDBFolder.h" +#import "MAPIStoreMapping.h" +#import "MAPIStoreUserContext.h" +#import "SOGoMAPIDBFolder.h" + +#import "MAPIStoreDBBaseContext.h" + +#undef DEBUG +#include + +static Class MAPIStoreDBFolderK; + +@implementation MAPIStoreDBBaseContext + ++ (void) initialize +{ + MAPIStoreDBFolderK = [MAPIStoreDBFolder class]; +} + ++ (NSString *) MAPIModuleName +{ + return nil; +} + +- (Class) MAPIStoreFolderClass +{ + return MAPIStoreDBFolderK; +} + +- (void) ensureContextFolder +{ + SOGoMAPIDBFolder *currentFolder; + NSArray *parts; + NSMutableArray *folders; + NSString *folderName; + NSUInteger count, max; + + parts = [[contextUrl path] componentsSeparatedByString: @"/"]; + max = [parts count]; + folders = [NSMutableArray arrayWithCapacity: max]; + + /* build the folder chain */ + currentFolder = [self rootSOGoFolder]; + [folders addObject: currentFolder]; + for (count = 1; count < max; count++) + { + folderName = [parts objectAtIndex: count]; + if ([folderName length] > 0) + { + currentFolder = [SOGoMAPIDBFolder objectWithName: folderName + inContainer: currentFolder]; + [folders addObject: currentFolder]; + } + } + + /* ensure each folder in the chain actually exists, so that it becomes + "listable" in further operations */ + max = [folders count]; + for (count = 0; count < max; count++) + { + currentFolder = [folders objectAtIndex: count]; + [currentFolder reloadIfNeeded]; + if ([currentFolder isNew]) + [currentFolder save]; + } +} + +- (id) rootSOGoFolder +{ + SOGoMAPIDBFolder *folder; + + [userContext ensureFolderTableExists]; + + folder = [SOGoMAPIDBFolder objectWithName: [isa MAPIModuleName] + inContainer: nil]; + [folder setTableUrl: [userContext folderTableURL]]; + // [folder reloadIfNeeded]; + + /* we don't need to set the "path prefix" of the folder since the module + name is used as the label for the top folder */ + + return folder; +} + +@end diff --git a/OpenChange/MAPIStoreFSFolder.h b/OpenChange/MAPIStoreDBFolder.h similarity index 78% rename from OpenChange/MAPIStoreFSFolder.h rename to OpenChange/MAPIStoreDBFolder.h index 75e3f08e5..2415af934 100644 --- a/OpenChange/MAPIStoreFSFolder.h +++ b/OpenChange/MAPIStoreDBFolder.h @@ -1,6 +1,6 @@ -/* MAPIStoreFSFolder.h - this file is part of SOGo +/* MAPIStoreDBFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -20,14 +20,14 @@ * Boston, MA 02111-1307, USA. */ -#ifndef MAPISTOREFSFOLDER_H -#define MAPISTOREFSFOLDER_H +#ifndef MAPISTOREDBFOLDER_H +#define MAPISTOREDBFOLDER_H #import "MAPIStoreFolder.h" -@interface MAPIStoreFSFolder : MAPIStoreFolder +@interface MAPIStoreDBFolder : MAPIStoreFolder @end -#endif /* MAPISTOREFSFOLDER_H */ +#endif /* MAPISTOREDBFOLDER_H */ diff --git a/OpenChange/MAPIStoreFSFolder.m b/OpenChange/MAPIStoreDBFolder.m similarity index 75% rename from OpenChange/MAPIStoreFSFolder.m rename to OpenChange/MAPIStoreDBFolder.m index 68f57545f..641b9dc59 100644 --- a/OpenChange/MAPIStoreFSFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -1,4 +1,4 @@ -/* MAPIStoreFSFolder.m - this file is part of SOGo +/* MAPIStoreDBFolder.m - this file is part of SOGo * * Copyright (C) 2011 Inverse inc * @@ -31,15 +31,15 @@ #import #import "EOQualifier+MAPI.h" #import "MAPIStoreContext.h" -#import "MAPIStoreFSFolderTable.h" -#import "MAPIStoreFSMessage.h" -#import "MAPIStoreFSMessageTable.h" +#import "MAPIStoreDBFolderTable.h" +#import "MAPIStoreDBMessage.h" +#import "MAPIStoreDBMessageTable.h" #import "MAPIStoreTypes.h" #import "MAPIStoreUserContext.h" -#import "SOGoMAPIFSFolder.h" -#import "SOGoMAPIFSMessage.h" +#import "SOGoMAPIDBFolder.h" +#import "SOGoMAPIDBMessage.h" -#import "MAPIStoreFSFolder.h" +#import "MAPIStoreDBFolder.h" #undef DEBUG #include @@ -57,39 +57,34 @@ static NSString *MAPIStoreRightCreateSubfolders = @"RightsCreateSubfolders"; static NSString *MAPIStoreRightFolderOwner = @"RightsFolderOwner"; static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; -@implementation MAPIStoreFSFolder +@implementation MAPIStoreDBFolder + (void) initialize { EOKeyValueQualifierK = [EOKeyValueQualifier class]; } +- (void) setupAuxiliaryObjects +{ + [super setupAuxiliaryObjects]; + ASSIGN (sogoObject, dbFolder); +} + - (MAPIStoreMessageTable *) messageTable { - return [MAPIStoreFSMessageTable tableForContainer: self]; + return [MAPIStoreDBMessageTable tableForContainer: self]; } - (MAPIStoreFolderTable *) folderTable { - return [MAPIStoreFSFolderTable tableForContainer: self]; + return [MAPIStoreDBFolderTable tableForContainer: self]; } - (enum mapistore_error) createFolder: (struct SRow *) aRow withFID: (uint64_t) newFID andKey: (NSString **) newKeyP { - NSString *newKey, *urlString; - NSURL *childURL; - SOGoMAPIFSFolder *childFolder; - - newKey = [NSString stringWithFormat: @"0x%.16"PRIx64, (unsigned long long) newFID]; - - urlString = [NSString stringWithFormat: @"%@/%@", [self url], newKey]; - childURL = [NSURL URLWithString: [urlString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]]; - childFolder = [SOGoMAPIFSFolder folderWithURL: childURL - andTableType: MAPISTORE_MESSAGE_TABLE]; - [childFolder ensureDirectory]; - *newKeyP = newKey; + *newKeyP = [NSString stringWithFormat: @"0x%.16"PRIx64, (unsigned long long) newFID]; return MAPISTORE_SUCCESS; } @@ -97,14 +92,15 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; - (MAPIStoreMessage *) createMessage { MAPIStoreMessage *newMessage; - SOGoMAPIFSMessage *fsObject; + SOGoMAPIDBMessage *fsObject; NSString *newKey; newKey = [NSString stringWithFormat: @"%@.plist", [SOGoObject globallyUniqueObjectId]]; - fsObject = [SOGoMAPIFSMessage objectWithName: newKey + fsObject = [SOGoMAPIDBMessage objectWithName: newKey inContainer: sogoObject]; - newMessage = [MAPIStoreFSMessage mapiStoreObjectWithSOGoObject: fsObject + [fsObject setObjectType: MAPIDBObjectTypeMessage]; + newMessage = [MAPIStoreDBMessage mapiStoreObjectWithSOGoObject: fsObject inContainer: self]; return newMessage; @@ -119,9 +115,10 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; ownerUser = [[self userContext] sogoUser]; if ([[context activeUser] isEqual: ownerUser] || [self subscriberCanReadMessages]) - keys = [(SOGoMAPIFSFolder *) sogoObject - toOneRelationshipKeysMatchingQualifier: qualifier - andSortOrderings: sortOrderings]; + keys = [(SOGoMAPIDBFolder *) sogoObject childKeysOfType: MAPIDBObjectTypeMessage + includeDeleted: NO + matchingQualifier: qualifier + andSortOrderings: sortOrderings]; else keys = [NSArray array]; @@ -131,39 +128,17 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; - (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier andSortOrderings: (NSArray *) sortOrderings { - NSArray *entries; - NSMutableArray *filteredEntries; - NSUInteger count, max; - MAPIStoreFSFolder *subfolder; - SOGoMAPIFSMessage *propertiesMessage; - NSString *subfolderKey; - - entries = [(SOGoMAPIFSFolder *) sogoObject toManyRelationshipKeys]; - if (qualifier) - { - max = [entries count]; - filteredEntries = [NSMutableArray arrayWithCapacity: max]; - for (count = 0; count < max; count++) - { - subfolderKey = [entries objectAtIndex: count]; - subfolder = [self lookupFolder: subfolderKey]; - propertiesMessage = [subfolder propertiesMessage]; - if ([qualifier evaluateMAPIVolatileMessage: propertiesMessage]) - [filteredEntries addObject: subfolderKey]; - } - entries = filteredEntries; - } - if (sortOrderings) - [self errorWithFormat: @"sort orderings are not used for folders"]; - - return entries; + return [dbFolder childKeysOfType: MAPIDBObjectTypeFolder + includeDeleted: NO + matchingQualifier: qualifier + andSortOrderings: sortOrderings]; } - (NSDate *) lastMessageModificationTime { NSUInteger count, max; NSDate *date, *fileDate; - MAPIStoreFSMessage *msg; + MAPIStoreDBMessage *msg; NSArray *messageKeys; messageKeys = [self messageKeys]; @@ -189,7 +164,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; - (SOGoFolder *) aclFolder { - return propsFolder; + return sogoObject; } - (NSArray *) rolesForExchangeRights: (uint32_t) rights diff --git a/OpenChange/MAPIStoreFSFolderTable.h b/OpenChange/MAPIStoreDBFolderTable.h similarity index 76% rename from OpenChange/MAPIStoreFSFolderTable.h rename to OpenChange/MAPIStoreDBFolderTable.h index f5a5dfb4e..afc3018e2 100644 --- a/OpenChange/MAPIStoreFSFolderTable.h +++ b/OpenChange/MAPIStoreDBFolderTable.h @@ -1,6 +1,6 @@ -/* MAPIStoreFSFolderTable.h - this file is part of SOGo +/* MAPIStoreDBFolderTable.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -20,12 +20,12 @@ * Boston, MA 02111-1307, USA. */ -#ifndef MAPISTOREFSFOLDERTABLE_H -#define MAPISTOREFSFOLDERTABLE_H +#ifndef MAPISTOREDBFOLDERTABLE_H +#define MAPISTOREDBFOLDERTABLE_H #import "MAPIStoreFolderTable.h" -@interface MAPIStoreFSFolderTable : MAPIStoreFolderTable +@interface MAPIStoreDBFolderTable : MAPIStoreFolderTable @end -#endif /* MAPISTOREFSFOLDERTABLE_H */ +#endif /* MAPISTOREDBFOLDERTABLE_H */ diff --git a/OpenChange/MAPIStoreFSFolderTable.m b/OpenChange/MAPIStoreDBFolderTable.m similarity index 85% rename from OpenChange/MAPIStoreFSFolderTable.m rename to OpenChange/MAPIStoreDBFolderTable.m index a834c5fb4..01a40b7f0 100644 --- a/OpenChange/MAPIStoreFSFolderTable.m +++ b/OpenChange/MAPIStoreDBFolderTable.m @@ -1,6 +1,6 @@ -/* MAPIStoreFSFolderTable.m - this file is part of SOGo +/* MAPIStoreDBFolderTable.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -24,9 +24,9 @@ #import "MAPIStoreTypes.h" -#import "MAPIStoreFSFolderTable.h" +#import "MAPIStoreDBFolderTable.h" -@implementation MAPIStoreFSFolderTable +@implementation MAPIStoreDBFolderTable - (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property { diff --git a/OpenChange/MAPIStoreFSMessage.h b/OpenChange/MAPIStoreDBMessage.h similarity index 74% rename from OpenChange/MAPIStoreFSMessage.h rename to OpenChange/MAPIStoreDBMessage.h index 20084a4f2..532f53a8e 100644 --- a/OpenChange/MAPIStoreFSMessage.h +++ b/OpenChange/MAPIStoreDBMessage.h @@ -1,6 +1,6 @@ -/* MAPIStoreFSMessage.h - this file is part of SOGo +/* MAPIStoreDBMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -20,12 +20,12 @@ * Boston, MA 02111-1307, USA. */ -#ifndef MAPISTOREFSMESSAGE_H -#define MAPISTOREFSMESSAGE_H +#ifndef MAPISTOREDBMESSAGE_H +#define MAPISTOREDBMESSAGE_H -#import "MAPIStoreVolatileMessage.h" +#import "MAPIStoreMessage.h" -@interface MAPIStoreFSMessage : MAPIStoreVolatileMessage +@interface MAPIStoreDBMessage : MAPIStoreMessage @end -#endif /* MAPISTOREFSMESSAGE_H */ +#endif /* MAPISTOREDBMESSAGE_H */ diff --git a/OpenChange/MAPIStoreFSMessage.m b/OpenChange/MAPIStoreDBMessage.m similarity index 59% rename from OpenChange/MAPIStoreFSMessage.m rename to OpenChange/MAPIStoreDBMessage.m index 7b7939884..945b41c8e 100644 --- a/OpenChange/MAPIStoreFSMessage.m +++ b/OpenChange/MAPIStoreDBMessage.m @@ -1,4 +1,4 @@ -/* MAPIStoreFSMessage.m - this file is part of SOGo +/* MAPIStoreDBMessage.m - this file is part of SOGo * * Copyright (C) 2011 Inverse inc * @@ -21,24 +21,25 @@ */ #import +#import #import #import #import #import "MAPIStoreContext.h" #import "MAPIStorePropertySelectors.h" -#import "SOGoMAPIFSMessage.h" +#import "SOGoMAPIDBMessage.h" -#import "MAPIStoreFSFolder.h" -#import "MAPIStoreFSMessage.h" +#import "MAPIStoreDBFolder.h" +#import "MAPIStoreDBMessage.h" #import "MAPIStoreTypes.h" -#import "NSData+MAPIStore.h" +#import "NSObject+MAPIStore.h" #undef DEBUG #include #include -@implementation MAPIStoreFSMessage +@implementation MAPIStoreDBMessage + (int) getAvailableProperties: (struct SPropTagArray **) propertiesP inMemCtx: (TALLOC_CTX *) memCtx @@ -60,13 +61,96 @@ /* FIXME (hack): append a few undocumented properties that can be added to FAI messages */ for (count = 0; count < 8; count++) - properties->aulPropTag[MAPIStoreSupportedPropertiesCount+count] = faiProperties[count]; + properties->aulPropTag[MAPIStoreSupportedPropertiesCount+count] + = faiProperties[count]; *propertiesP = properties; return MAPISTORE_SUCCESS; } +- (id) initWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newContainer +{ + if ((self = [super initWithSOGoObject: newSOGoObject + inContainer: newContainer])) + { + [properties release]; + properties = [newSOGoObject properties]; + [properties retain]; + } + + return self; +} + +- (uint64_t) objectVersion +{ + NSNumber *versionNbr; + uint64_t objectVersion; + + [(SOGoMAPIDBMessage *) sogoObject reloadIfNeeded]; + versionNbr = [properties objectForKey: @"version"]; + if (versionNbr) + objectVersion = [versionNbr unsignedLongLongValue]; + else + objectVersion = ULLONG_MAX; + + return objectVersion; +} + +- (int) getProperties: (struct mapistore_property_data *) data + withTags: (enum MAPITAGS *) tags + andCount: (uint16_t) columnCount + inMemCtx: (TALLOC_CTX *) memCtx +{ + [sogoObject reloadIfNeeded]; + + return [super getProperties: data + withTags: tags + andCount: columnCount + inMemCtx: memCtx]; +} + +- (int) getProperty: (void **) data + withTag: (enum MAPITAGS) propTag + inMemCtx: (TALLOC_CTX *) memCtx +{ + id value; + int rc; + + value = [properties objectForKey: MAPIPropertyKey (propTag)]; + if (value) + rc = [value getValue: data forTag: propTag inMemCtx: memCtx]; + else + rc = [super getProperty: data withTag: propTag inMemCtx: memCtx]; + + return rc; +} + +- (int) getPidTagSubject: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + id value; + int rc; + + value = [properties + objectForKey: MAPIPropertyKey (PidTagNormalizedSubject)]; + if (value) + rc = [value getValue: data forTag: PidTagNormalizedSubject + inMemCtx: memCtx]; + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + +- (void) addProperties: (NSDictionary *) newNewProperties +{ + [sogoObject reloadIfNeeded]; + + [super addProperties: newNewProperties]; +} + - (void) save { uint64_t newVersion; @@ -76,13 +160,11 @@ newVersion = exchange_globcnt ([[self context] getNewChangeNumber] >> 16); [properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion] - forKey: @"version"]; + forKey: @"version"]; [self logWithFormat: @"%d props in dict", [properties count]]; - [sogoObject appendProperties: properties]; [sogoObject save]; - [properties removeAllObjects]; } - (BOOL) _messageIsFreeBusy @@ -91,7 +173,7 @@ /* This is a HACK until we figure out how to determine a message position in the mailbox hierarchy.... (missing: folderid and role) */ - msgClass = [[sogoObject properties] + msgClass = [properties objectForKey: MAPIPropertyKey (PR_MESSAGE_CLASS_UNICODE)]; return [msgClass isEqualToString: @"IPM.Microsoft.ScheduleData.FreeBusy"]; @@ -115,12 +197,12 @@ - (NSDate *) creationTime { - return [sogoObject creationTime]; + return [sogoObject creationDate]; } - (NSDate *) lastModificationTime { - return [sogoObject lastModificationTime]; + return [sogoObject lastModified]; } @end diff --git a/OpenChange/MAPIStoreFSMessageTable.h b/OpenChange/MAPIStoreDBMessageTable.h similarity index 76% rename from OpenChange/MAPIStoreFSMessageTable.h rename to OpenChange/MAPIStoreDBMessageTable.h index 452c8ffdb..4b9f66480 100644 --- a/OpenChange/MAPIStoreFSMessageTable.h +++ b/OpenChange/MAPIStoreDBMessageTable.h @@ -1,6 +1,6 @@ -/* MAPIStoreFSMessageTable.h - this file is part of SOGo +/* MAPIStoreDBMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -20,12 +20,12 @@ * Boston, MA 02111-1307, USA. */ -#ifndef MAPISTOREFSMESSAGETABLE_H -#define MAPISTOREFSMESSAGETABLE_H +#ifndef MAPISTOREDBMESSAGETABLE_H +#define MAPISTOREDBMESSAGETABLE_H #import "MAPIStoreMessageTable.h" -@interface MAPIStoreFSMessageTable : MAPIStoreMessageTable +@interface MAPIStoreDBMessageTable : MAPIStoreMessageTable @end -#endif /* MAPISTOREFSMESSAGETABLE_H */ +#endif /* MAPISTOREDBMESSAGETABLE_H */ diff --git a/OpenChange/MAPIStoreFSMessageTable.m b/OpenChange/MAPIStoreDBMessageTable.m similarity index 92% rename from OpenChange/MAPIStoreFSMessageTable.m rename to OpenChange/MAPIStoreDBMessageTable.m index 7c8504c67..9f791d68a 100644 --- a/OpenChange/MAPIStoreFSMessageTable.m +++ b/OpenChange/MAPIStoreDBMessageTable.m @@ -1,6 +1,6 @@ -/* MAPIStoreFSMessageTable.m - this file is part of SOGo +/* MAPIStoreDBMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -25,25 +25,25 @@ #import #import "MAPIStoreTypes.h" -#import "MAPIStoreFSMessage.h" +#import "MAPIStoreDBMessage.h" -#import "MAPIStoreFSMessageTable.h" +#import "MAPIStoreDBMessageTable.h" #undef DEBUG #include -static Class MAPIStoreFSMessageK = Nil; +static Class MAPIStoreDBMessageK = Nil; -@implementation MAPIStoreFSMessageTable +@implementation MAPIStoreDBMessageTable + (void) initialize { - MAPIStoreFSMessageK = [MAPIStoreFSMessage class]; + MAPIStoreDBMessageK = [MAPIStoreDBMessage class]; } + (Class) childObjectClass { - return MAPIStoreFSMessageK; + return MAPIStoreDBMessageK; } - (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property diff --git a/OpenChange/MAPIStoreFAIMessage.h b/OpenChange/MAPIStoreFAIMessage.h index 4ac10e143..fd4d08930 100644 --- a/OpenChange/MAPIStoreFAIMessage.h +++ b/OpenChange/MAPIStoreFAIMessage.h @@ -23,9 +23,9 @@ #ifndef MAPISTOREFAIMESSAGE_H #define MAPISTOREFAIMESSAGE_H -#import "MAPIStoreFSMessage.h" +#import "MAPIStoreDBMessage.h" -@interface MAPIStoreFAIMessage : MAPIStoreFSMessage +@interface MAPIStoreFAIMessage : MAPIStoreDBMessage @end #endif /* MAPISTOREFAIMESSAGE_H */ diff --git a/OpenChange/MAPIStoreFAIMessageTable.h b/OpenChange/MAPIStoreFAIMessageTable.h index 70e12f43f..0aa6d7230 100644 --- a/OpenChange/MAPIStoreFAIMessageTable.h +++ b/OpenChange/MAPIStoreFAIMessageTable.h @@ -23,9 +23,9 @@ #ifndef MAPISTOREFAIMESSAGETABLE_H #define MAPISTOREFAIMESSAGETABLE_H -#import "MAPIStoreFSMessageTable.h" +#import "MAPIStoreDBMessageTable.h" -@interface MAPIStoreFAIMessageTable : MAPIStoreFSMessageTable +@interface MAPIStoreFAIMessageTable : MAPIStoreDBMessageTable @end #endif /* MAPISTOREFAIMESSAGETABLE_H */ diff --git a/OpenChange/MAPIStoreFSBaseContext.m b/OpenChange/MAPIStoreFSBaseContext.m deleted file mode 100644 index a3e448082..000000000 --- a/OpenChange/MAPIStoreFSBaseContext.m +++ /dev/null @@ -1,79 +0,0 @@ -/* MAPIStoreFSBaseContext.m - this file is part of SOGo - * - * Copyright (C) 2010 Inverse inc. - * - * Author: Wolfgang Sourdeau - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* A generic parent class for all context that will store their data on the - disk in the form of a plist. */ - -#import -#import - -#import - -#import "MAPIStoreFSFolder.h" -#import "MAPIStoreMapping.h" -#import "MAPIStoreUserContext.h" -#import "SOGoMAPIFSFolder.h" - -#import "MAPIStoreFSBaseContext.h" - -#undef DEBUG -#include - -static Class MAPIStoreFSFolderK; - -@implementation MAPIStoreFSBaseContext - -+ (void) initialize -{ - MAPIStoreFSFolderK = [MAPIStoreFSFolder class]; -} - -+ (NSString *) MAPIModuleName -{ - return nil; -} - -- (Class) MAPIStoreFolderClass -{ - return MAPIStoreFSFolderK; -} - -- (void) ensureContextFolder -{ - SOGoMAPIFSFolder *contextFolder; - - contextFolder = [SOGoMAPIFSFolder folderWithURL: contextUrl - andTableType: MAPISTORE_MESSAGE_TABLE]; - [contextFolder ensureDirectory]; -} - -- (id) rootSOGoFolder -{ - NSString *urlString; - - urlString = [NSString stringWithFormat: @"sogo://%@@%@/", - [userContext username], [isa MAPIModuleName]]; - return [SOGoMAPIFSFolder folderWithURL: [NSURL URLWithString: urlString] - andTableType: MAPISTORE_MESSAGE_TABLE]; -} - -@end diff --git a/OpenChange/MAPIStoreFallbackContext.h b/OpenChange/MAPIStoreFallbackContext.h index da8e03c0d..eaf992bb7 100644 --- a/OpenChange/MAPIStoreFallbackContext.h +++ b/OpenChange/MAPIStoreFallbackContext.h @@ -23,9 +23,9 @@ #ifndef MAPISTOREFALLBACKCONTEXT_H #define MAPISTOREFALLBACKCONTEXT_H -#import "MAPIStoreFSBaseContext.h" +#import "MAPIStoreDBBaseContext.h" -@interface MAPIStoreFallbackContext : MAPIStoreFSBaseContext +@interface MAPIStoreFallbackContext : MAPIStoreDBBaseContext @end diff --git a/OpenChange/MAPIStoreFallbackContext.m b/OpenChange/MAPIStoreFallbackContext.m index c5270d055..37da58d7d 100644 --- a/OpenChange/MAPIStoreFallbackContext.m +++ b/OpenChange/MAPIStoreFallbackContext.m @@ -26,7 +26,7 @@ #import "MAPIStoreUserContext.h" #import "NSString+MAPIStore.h" -#import "SOGoMAPIFSFolder.h" +#import "SOGoMAPIDBFolder.h" #import "MAPIStoreFallbackContext.h" @@ -51,10 +51,11 @@ inMemCtx: (TALLOC_CTX *) memCtx { struct mapistore_contexts_list *firstContext = NULL, *context; - SOGoMAPIFSFolder *root; + SOGoMAPIDBFolder *root; NSArray *names; NSUInteger count, max; NSString *baseURL, *url, *name; + MAPIStoreUserContext *userContext; baseURL = [NSString stringWithFormat: @"sogo://%@@fallback/", userName]; @@ -67,11 +68,15 @@ DLIST_ADD_END (firstContext, context, void); - /* Maybe emsmdbp_provisioning should be fixed in order to only take the uri returned above to avoid deleting its entries... */ - root = [SOGoMAPIFSFolder folderWithURL: [NSURL URLWithString: baseURL] - andTableType: MAPISTORE_MESSAGE_TABLE]; + root = [SOGoMAPIDBFolder objectWithName: [self MAPIModuleName] + inContainer: nil]; + [root setOwner: userName]; + userContext = [MAPIStoreUserContext userContextWithUsername: userName + andTDBIndexing: indexingTdb]; + [userContext ensureFolderTableExists]; + [root setTableUrl: [userContext folderTableURL]]; names = [root toManyRelationshipKeys]; max = [names count]; for (count = 0; count < max; count++) diff --git a/OpenChange/MAPIStoreFolder.h b/OpenChange/MAPIStoreFolder.h index 41b3bdd61..b29a93d3d 100644 --- a/OpenChange/MAPIStoreFolder.h +++ b/OpenChange/MAPIStoreFolder.h @@ -38,29 +38,34 @@ @class MAPIStoreMessageTable; @class MAPIStorePermissionsTable; @class SOGoFolder; -@class SOGoMAPIFSFolder; -@class SOGoMAPIFSMessage; +@class SOGoMAPIDBFolder; +@class SOGoMAPIDBMessage; -#import "MAPIStoreObject.h" +#import "MAPIStoreSOGoObject.h" -@interface MAPIStoreFolder : MAPIStoreObject +@interface MAPIStoreFolder : MAPIStoreSOGoObject { MAPIStoreContext *context; // NSArray *messageKeys; // NSArray *faiMessageKeys; // NSArray *folderKeys; - SOGoMAPIFSFolder *faiFolder; - SOGoMAPIFSFolder *propsFolder; - SOGoMAPIFSMessage *propsMessage; + SOGoMAPIDBFolder *dbFolder; + // SOGoMAPIDBFolder *faiFolder; + // SOGoMAPIDBFolder *propsFolder; + // SOGoMAPIDBMessage *propsMessage; } - (void) setContext: (MAPIStoreContext *) newContext; +- (void) setupAuxiliaryObjects; + +- (SOGoMAPIDBFolder *) dbFolder; + - (NSArray *) activeMessageTables; - (NSArray *) activeFAIMessageTables; -- (SOGoMAPIFSMessage *) propertiesMessage; +// - (SOGoMAPIDBMessage *) propertiesMessage; - (id) lookupMessageByURL: (NSString *) messageURL; - (id) lookupFolderByURL: (NSString *) folderURL; diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 3e480f11d..f4128695d 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -48,8 +48,8 @@ #import "NSDate+MAPIStore.h" #import "NSString+MAPIStore.h" #import "NSObject+MAPIStore.h" -#import "SOGoMAPIFSFolder.h" -#import "SOGoMAPIFSMessage.h" +#import "SOGoMAPIDBFolder.h" +#import "SOGoMAPIDBMessage.h" #include @@ -79,33 +79,67 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe // messageKeys = nil; // faiMessageKeys = nil; // folderKeys = nil; - faiFolder = nil; + dbFolder = nil; context = nil; - propsFolder = nil; - propsMessage = nil; + // propsFolder = nil; + // propsMessage = nil; } return self; } -- (void) _setupAuxiliaryObjects +- (void) setupAuxiliaryObjects { - NSURL *propsURL; - NSString *urlString; + NSURL *folderURL; + NSMutableString *pathPrefix; + NSString *path, *folderName; + NSArray *parts; + NSUInteger lastPartIdx; + MAPIStoreUserContext *userContext; + + folderURL = [NSURL URLWithString: [self url]]; + path = [folderURL path]; + path = [path substringFromIndex: 1]; + if ([path length] > 0) + { + parts = [path componentsSeparatedByString: @"/"]; + lastPartIdx = [parts count] - 1; + if ([path hasSuffix: @"/"]) + lastPartIdx--; + folderName = [parts objectAtIndex: lastPartIdx]; + } + else + folderName = [folderURL host]; + + userContext = [self userContext]; + [userContext ensureFolderTableExists]; + + ASSIGN (dbFolder, + [SOGoMAPIDBFolder objectWithName: folderName + inContainer: [container dbFolder]]); + [dbFolder setTableUrl: [userContext folderTableURL]]; + if (!container && [path length] > 0) + { + pathPrefix = [NSMutableString stringWithCapacity: 64]; + [pathPrefix appendFormat: @"/%@", [folderURL host]]; + parts = [parts subarrayWithRange: NSMakeRange (0, lastPartIdx)]; + if ([parts count] > 0) + [pathPrefix appendFormat: @"/%@", [parts componentsJoinedByString: @"/"]]; + [dbFolder setPathPrefix: pathPrefix]; + } + [dbFolder reloadIfNeeded]; + + /* propsMessage and self share the same properties dictionary */ + // ASSIGN (propsMessage, + // [SOGoMAPIDBMessage objectWithName: @"properties.plist" + // inContainer: dbFolder]); + // [propsMessage setObjectType: MAPIDBObjectTypeInternal]; + // [propsMessage reloadIfNeeded]; + [properties release]; + properties = [dbFolder properties]; + [properties retain]; - urlString = [[self url] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; - propsURL = [NSURL URLWithString: urlString]; - [self logWithFormat: @"_setupAuxiliaryObjects: %@", propsURL]; - ASSIGN (faiFolder, - [SOGoMAPIFSFolder folderWithURL: propsURL - andTableType: MAPISTORE_FAI_TABLE]); - ASSIGN (propsFolder, - [SOGoMAPIFSFolder folderWithURL: propsURL - andTableType: MAPISTORE_FOLDER_TABLE]); - ASSIGN (propsMessage, - [SOGoMAPIFSMessage objectWithName: @"properties.plist" - inContainer: propsFolder]); [self setupVersionsMessage]; } @@ -119,7 +153,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe inContainer: newContainer]) && newContainer) { - [self _setupAuxiliaryObjects]; + [self setupAuxiliaryObjects]; } return self; @@ -129,13 +163,13 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe { ASSIGN (context, newContext); if (newContext) - [self _setupAuxiliaryObjects]; + [self setupAuxiliaryObjects]; } - (MAPIStoreContext *) context { if (!context) - [self setContext: [container context]]; + [self setContext: (MAPIStoreContext *) [container context]]; return context; } @@ -145,29 +179,31 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe // [messageKeys release]; // [faiMessageKeys release]; // [folderKeys release]; - [propsMessage release]; - [propsFolder release]; - [faiFolder release]; + // [propsMessage release]; + [dbFolder release]; [context release]; [super dealloc]; } +- (SOGoMAPIDBFolder *) dbFolder +{ + return dbFolder; +} + /* backend interface */ -- (SOGoMAPIFSMessage *) propertiesMessage -{ - return propsMessage; -} +// - (SOGoMAPIDBMessage *) propertiesMessage +// { +// return propsMessage; +// } - (uint64_t) objectVersion { NSNumber *value; - NSDictionary *props; uint64_t cn; - props = [propsMessage properties]; - value = [props objectForKey: MAPIPropertyKey (PidTagChangeNumber)]; + value = [properties objectForKey: MAPIPropertyKey (PidTagChangeNumber)]; if (value) cn = [value unsignedLongLongValue]; else @@ -175,10 +211,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe [self logWithFormat: @"no value for PidTagChangeNumber, adding one now"]; cn = [[self context] getNewChangeNumber]; value = [NSNumber numberWithUnsignedLongLong: cn]; - props = [NSDictionary dictionaryWithObject: value - forKey: MAPIPropertyKey (PidTagChangeNumber)]; - [propsMessage appendProperties: props]; - [propsMessage save]; + + [properties setObject: value + forKey: MAPIPropertyKey (PidTagChangeNumber)]; + [dbFolder save]; } return cn >> 16; @@ -186,21 +222,24 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (id) lookupFolder: (NSString *) folderKey { - MAPIStoreFolder *childFolder = nil; + MAPIStoreFolder *childFolder; SOGoFolder *sogoFolder; WOContext *woContext; if ([[self folderKeys] containsObject: folderKey]) { woContext = [[self userContext] woContext]; - sogoFolder = [sogoObject lookupName: folderKey - inContext: woContext + sogoFolder = [sogoObject lookupName: folderKey inContext: woContext acquire: NO]; - [sogoFolder setContext: woContext]; if (sogoFolder && ![sogoFolder isKindOfClass: NSExceptionK]) - childFolder = [isa mapiStoreObjectWithSOGoObject: sogoFolder - inContainer: self]; + { + [sogoFolder setContext: woContext]; + childFolder = [isa mapiStoreObjectWithSOGoObject: sogoFolder + inContainer: self]; + } } + else + childFolder = nil; return childFolder; } @@ -264,9 +303,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe { if ([[self faiMessageKeys] containsObject: messageKey]) { - msgObject = [faiFolder lookupName: messageKey - inContext: nil - acquire: NO]; + msgObject = [dbFolder lookupName: messageKey + inContext: nil + acquire: NO]; childMessage = [MAPIStoreFAIMessageK mapiStoreObjectWithSOGoObject: msgObject inContainer: self]; @@ -383,9 +422,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (int) deleteFolder { - [propsMessage delete]; - [propsFolder delete]; - [faiFolder delete]; + // [propsMessage delete]; + [dbFolder delete]; [self cleanupCaches]; @@ -1004,7 +1042,11 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe /* TODO: this should no longer be required once mapistore v2 API is in place, when we can then do this from -dealloc below */ + [dbFolder reloadIfNeeded]; + propsCopy = [newProperties mutableCopy]; + [propsCopy autorelease]; + currentProp = bannedProps; while (*currentProp) { @@ -1012,9 +1054,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe currentProp++; } - [propsMessage appendProperties: propsCopy]; - [propsMessage save]; - [propsCopy release]; + [properties addEntriesFromDictionary: propsCopy]; + [dbFolder save]; } - (NSArray *) messageKeys @@ -1039,9 +1080,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (NSArray *) faiMessageKeysMatchingQualifier: (EOQualifier *) qualifier andSortOrderings: (NSArray *) sortOrderings { - return [faiFolder - toOneRelationshipKeysMatchingQualifier: qualifier - andSortOrderings: sortOrderings]; + return [dbFolder childKeysOfType: MAPIDBObjectTypeFAI + includeDeleted: NO + matchingQualifier: qualifier + andSortOrderings: sortOrderings]; } - (NSArray *) faiMessageKeys @@ -1287,6 +1329,19 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe return MAPISTORE_SUCCESS; } +- (int) getProperties: (struct mapistore_property_data *) data + withTags: (enum MAPITAGS *) tags + andCount: (uint16_t) columnCount + inMemCtx: (TALLOC_CTX *) memCtx +{ + [dbFolder reloadIfNeeded]; + + return [super getProperties: data + withTags: tags + andCount: columnCount + inMemCtx: memCtx]; +} + - (int) getProperty: (void **) data withTag: (enum MAPITAGS) propTag inMemCtx: (TALLOC_CTX *) memCtx @@ -1294,8 +1349,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe int rc; id value; - value = [[propsMessage properties] - objectForKey: MAPIPropertyKey (propTag)]; + value = [properties objectForKey: MAPIPropertyKey (propTag)]; if (value) rc = [value getValue: data forTag: propTag inMemCtx: memCtx]; else @@ -1307,13 +1361,15 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (MAPIStoreMessage *) _createAssociatedMessage { MAPIStoreMessage *newMessage; - SOGoMAPIFSMessage *fsObject; + SOGoMAPIDBMessage *dbObject; NSString *newKey; newKey = [NSString stringWithFormat: @"%@.plist", [SOGoObject globallyUniqueObjectId]]; - fsObject = [SOGoMAPIFSMessage objectWithName: newKey inContainer: faiFolder]; - newMessage = [MAPIStoreFAIMessageK mapiStoreObjectWithSOGoObject: fsObject + dbObject = [SOGoMAPIDBMessage objectWithName: newKey inContainer: dbFolder]; + [dbObject setObjectType: MAPIDBObjectTypeFAI]; + [dbObject setIsNew: YES]; + newMessage = [MAPIStoreFAIMessageK mapiStoreObjectWithSOGoObject: dbObject inContainer: self]; return newMessage; @@ -1328,9 +1384,15 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe newMessage = [self _createAssociatedMessage]; else newMessage = [self createMessage]; - [newMessage setIsNew: YES]; + /* FIXME: this is ugly as the specifics of message creation should all be + delegated to subclasses */ + if ([newMessage respondsToSelector: @selector (setIsNew:)]) + [newMessage setIsNew: YES]; woContext = [[self userContext] woContext]; - [[newMessage sogoObject] setContext: woContext]; + /* FIXME: this is ugly too as the specifics of message creation should all + be delegated to subclasses */ + if ([newMessage respondsToSelector: @selector (sogoObject:)]) + [[newMessage sogoObject] setContext: woContext]; return newMessage; } @@ -1598,12 +1660,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (NSDate *) creationTime { - return [propsMessage creationTime]; + return [dbFolder creationDate]; } - (NSDate *) lastModificationTime { - return [propsMessage lastModificationTime]; + return [dbFolder lastModified]; } /* subclasses */ diff --git a/OpenChange/MAPIStoreGCSFolder.h b/OpenChange/MAPIStoreGCSFolder.h index 0d0c1e6df..d889b78a9 100644 --- a/OpenChange/MAPIStoreGCSFolder.h +++ b/OpenChange/MAPIStoreGCSFolder.h @@ -34,7 +34,7 @@ @interface MAPIStoreGCSFolder : MAPIStoreFolder { - SOGoMAPIFSMessage *versionsMessage; + SOGoMAPIDBMessage *versionsMessage; NSArray *activeUserRoles; EOQualifier *componentQualifier; } diff --git a/OpenChange/MAPIStoreGCSFolder.m b/OpenChange/MAPIStoreGCSFolder.m index e5f6bbd65..b94f10ad5 100644 --- a/OpenChange/MAPIStoreGCSFolder.m +++ b/OpenChange/MAPIStoreGCSFolder.m @@ -40,7 +40,7 @@ #import "NSData+MAPIStore.h" #import "NSDate+MAPIStore.h" #import "NSString+MAPIStore.h" -#import "SOGoMAPIFSMessage.h" +#import "SOGoMAPIDBMessage.h" #import "MAPIStoreGCSFolder.h" @@ -71,8 +71,9 @@ static Class NSNumberK; - (void) setupVersionsMessage { ASSIGN (versionsMessage, - [SOGoMAPIFSMessage objectWithName: @"versions.plist" - inContainer: propsFolder]); + [SOGoMAPIDBMessage objectWithName: @"versions.plist" + inContainer: dbFolder]); + [versionsMessage setObjectType: MAPIDBObjectTypeInternal]; } - (void) dealloc @@ -288,7 +289,8 @@ static Class NSNumberK; forKey: @"PredecessorChangeList"]; [changeList release]; } - [changeList setObject: globCnt forKey: guid]; + [changeList setObject: globCnt + forKey: guid]; } - (EOQualifier *) componentQualifier @@ -349,6 +351,7 @@ static Class NSNumberK; [sortOrdering retain]; } + [versionsMessage reloadIfNeeded]; currentProperties = [versionsMessage properties]; lastModificationDate = [currentProperties objectForKey: @"SyncLastModificationDate"]; @@ -451,7 +454,6 @@ static Class NSNumberK; forKey: @"SyncLastSynchronisationDate"]; [currentProperties setObject: lastModificationDate forKey: @"SyncLastModificationDate"]; - [versionsMessage appendProperties: currentProperties]; [versionsMessage save]; } } diff --git a/OpenChange/MAPIStoreMailAttachment.h b/OpenChange/MAPIStoreMailAttachment.h index 5fded594c..f9f0011e9 100644 --- a/OpenChange/MAPIStoreMailAttachment.h +++ b/OpenChange/MAPIStoreMailAttachment.h @@ -30,9 +30,11 @@ @interface MAPIStoreMailAttachment : MAPIStoreAttachment { NSDictionary *bodyInfo; + SOGoMailBodyPart *bodyPart; } - (void) setBodyInfo: (NSDictionary *) newBodyInfo; +- (void) setBodyPart: (SOGoMailBodyPart *) newBodyPart; @end diff --git a/OpenChange/MAPIStoreMailAttachment.m b/OpenChange/MAPIStoreMailAttachment.m index 7b9641548..6834b8c1d 100644 --- a/OpenChange/MAPIStoreMailAttachment.m +++ b/OpenChange/MAPIStoreMailAttachment.m @@ -52,6 +52,7 @@ if ((self = [super init])) { bodyInfo = nil; + bodyPart = nil; } return self; @@ -60,6 +61,7 @@ - (void) dealloc { [bodyInfo release]; + [bodyPart release]; [super dealloc]; } @@ -68,6 +70,11 @@ ASSIGN (bodyInfo, newBodyInfo); } +- (void) setBodyPart: (SOGoMailBodyPart *) newBodyPart +{ + ASSIGN (bodyPart, newBodyPart); +} + - (int) getPidTagAttachMethod: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -187,7 +194,7 @@ - (int) getPidTagAttachDataBinary: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = [[sogoObject fetchBLOBWithPeek: YES] asBinaryInMemCtx: memCtx]; + *data = [[bodyPart fetchBLOBWithPeek: YES] asBinaryInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } diff --git a/OpenChange/MAPIStoreMailFolder.h b/OpenChange/MAPIStoreMailFolder.h index 7e47e8c09..ab6430489 100644 --- a/OpenChange/MAPIStoreMailFolder.h +++ b/OpenChange/MAPIStoreMailFolder.h @@ -36,7 +36,7 @@ @interface MAPIStoreMailFolder : MAPIStoreFolder { - SOGoMAPIFSMessage *versionsMessage; + SOGoMAPIDBMessage *versionsMessage; } - (BOOL) ensureFolderExists; diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index f5cfe3340..8fffd8d9d 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -54,9 +54,8 @@ #import "MAPIStoreTypes.h" #import "NSData+MAPIStore.h" #import "NSString+MAPIStore.h" -#import "SOGoMAPIFSMessage.h" +#import "SOGoMAPIDBMessage.h" -#import "SOGoMAPIVolatileMessage.h" #import "MAPIStoreMailVolatileMessage.h" #import "MAPIStoreMailFolder.h" @@ -97,8 +96,9 @@ static Class SOGoMailFolderK, MAPIStoreOutboxFolderK; - (void) setupVersionsMessage { ASSIGN (versionsMessage, - [SOGoMAPIFSMessage objectWithName: @"versions.plist" - inContainer: propsFolder]); + [SOGoMAPIDBMessage objectWithName: @"versions.plist" + inContainer: dbFolder]); + [versionsMessage setObjectType: MAPIDBObjectTypeInternal]; } - (BOOL) ensureFolderExists @@ -119,6 +119,9 @@ static Class SOGoMailFolderK, MAPIStoreOutboxFolderK; && ![[(SOGoMailFolder *) sogoObject displayName] isEqualToString: newDisplayName]) { + [NSException raise: @"MAPIStoreIOException" + format: @"renaming a mail folder via OpenChange is" + @" currently a bad idea"]; [(SOGoMailFolder *) sogoObject renameTo: newDisplayName]; propsCopy = [newProperties mutableCopy]; [propsCopy removeObjectForKey: key]; @@ -489,10 +492,8 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) now = [NSCalendarDate date]; [now setTimeZone: utcTZ]; - currentProperties = [[versionsMessage properties] mutableCopy]; - if (!currentProperties) - currentProperties = [NSMutableDictionary new]; - [currentProperties autorelease]; + [versionsMessage reloadIfNeeded]; + currentProperties = [versionsMessage properties]; messages = [currentProperties objectForKey: @"Messages"]; if (!messages) { @@ -613,7 +614,6 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) ti = [NSNumber numberWithDouble: [now timeIntervalSince1970]]; [currentProperties setObject: ti forKey: @"SyncLastSynchronisationDate"]; - [versionsMessage appendProperties: currentProperties]; [versionsMessage save]; } @@ -1004,20 +1004,16 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) - (MAPIStoreMessage *) createMessage { - MAPIStoreMailVolatileMessage *newMessage; - SOGoMAPIVolatileMessage *newObject; + SOGoMAPIObject *childObject; - newObject = [SOGoMAPIVolatileMessage - objectWithName: [SOGoObject globallyUniqueObjectId] - inContainer: sogoObject]; - newMessage - = [MAPIStoreMailVolatileMessage mapiStoreObjectWithSOGoObject: newObject - inContainer: self]; - - return newMessage; + childObject = [SOGoMAPIObject objectWithName: [SOGoMAPIObject + globallyUniqueObjectId] + inContainer: sogoObject]; + return [MAPIStoreMailVolatileMessage + mapiStoreObjectWithSOGoObject: childObject + inContainer: self]; } - - (NSArray *) rolesForExchangeRights: (uint32_t) rights { NSMutableArray *roles; diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 85081c2db..8e8070ae2 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -373,7 +373,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) if (uid) { changeNumber = [(MAPIStoreMailFolder *) container - changeNumberForMessageUID: uid]; + changeNumberForMessageUID: uid]; if (!changeNumber) { [self warnWithFormat: @"attempting to get change number" @@ -1529,8 +1529,8 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) if (currentPart) { attachment = [MAPIStoreMailAttachment - mapiStoreObjectWithSOGoObject: currentPart - inContainer: self]; + mapiStoreObjectInContainer: self]; + [attachment setBodyPart: currentPart]; [attachment setBodyInfo: [attachmentParts objectForKey: childKey]]; [attachment setAID: [[self attachmentKeys] indexOfObject: childKey]]; } diff --git a/OpenChange/MAPIStoreMailMessageTable.m b/OpenChange/MAPIStoreMailMessageTable.m index 62dc406fd..c1561bbd5 100644 --- a/OpenChange/MAPIStoreMailMessageTable.m +++ b/OpenChange/MAPIStoreMailMessageTable.m @@ -332,7 +332,7 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK; if (!fetchedCoreInfos) { fetchedCoreInfos = YES; - [(SOGoMailFolder *) [container sogoObject] + [(SOGoMailFolder *) [(MAPIStoreMailFolder *) container sogoObject] prefetchCoreInfosForMessageKeys: [self restrictedChildKeys]]; } diff --git a/OpenChange/MAPIStoreMailVolatileMessage.h b/OpenChange/MAPIStoreMailVolatileMessage.h index 82959cc6f..53a51847f 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.h +++ b/OpenChange/MAPIStoreMailVolatileMessage.h @@ -23,9 +23,9 @@ #ifndef MAPISTOREMAILVOLATILEMESSAGE_H #define MAPISTOREMAILVOLATILEMESSAGE_H -#import "MAPIStoreVolatileMessage.h" +#import "MAPIStoreMessage.h" -@interface MAPIStoreMailVolatileMessage : MAPIStoreVolatileMessage +@interface MAPIStoreMailVolatileMessage : MAPIStoreMessage - (int) submitWithFlags: (enum SubmitFlags) flags; diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index 3a3d66be3..b3bb2145f 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -51,6 +51,7 @@ #import #import "MAPIStoreAttachment.h" +#import "MAPIStoreAttachmentTable.h" #import "MAPIStoreContext.h" #import "MAPIStoreMailFolder.h" #import "MAPIStoreMIME.h" @@ -60,7 +61,7 @@ #import "NSData+MAPIStore.h" #import "NSObject+MAPIStore.h" #import "NSString+MAPIStore.h" -#import "SOGoMAPIVolatileMessage.h" +#import "SOGoMAPIObject.h" #import "MAPIStoreMailVolatileMessage.h" @@ -68,6 +69,8 @@ #include #include +static Class NSNumberK = Nil; + static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" }; // @@ -242,6 +245,106 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" }; @implementation MAPIStoreMailVolatileMessage ++ (void) initialize +{ + NSNumberK = [NSNumber class]; +} + +- (id) initWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newContainer +{ + if ((self = [super initWithSOGoObject: newSOGoObject + inContainer: newContainer])) + { + ASSIGN (properties, [sogoObject properties]); + } + + return self; +} + +- (void) addProperties: (NSDictionary *) newProperties +{ + [super addProperties: newProperties]; + [sogoObject adjustLastModified]; +} + +- (BOOL) canGetProperty: (enum MAPITAGS) propTag +{ + return ([super canGetProperty: propTag] + || [properties objectForKey: MAPIPropertyKey (propTag)] != nil); +} + +- (uint64_t) objectVersion +{ + NSNumber *version; + + version = [properties objectForKey: @"version"]; + + return (version + ? exchange_globcnt ([version unsignedLongLongValue]) + : ULLONG_MAX); +} + +- (int) getPidTagSubject: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +{ + /* if we get here, it means that the properties file didn't contain a + relevant value */ + return [self getEmptyString: data inMemCtx: memCtx]; +} + +- (int) getPidTagMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [@"IPM.Note" asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagChangeKey: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +{ + NSData *changeKey; + int rc; + + changeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)]; + if (changeKey) + { + *data = [changeKey asBinaryInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + else + rc = [super getPidTagChangeKey: data inMemCtx: memCtx]; + + return rc; +} + +- (NSArray *) attachmentsKeysMatchingQualifier: (EOQualifier *) qualifier + andSortOrderings: (NSArray *) sortOrderings +{ + NSDictionary *attachments; + + attachments = [properties objectForKey: @"attachments"]; + + return [attachments allKeys]; +} + +- (NSDate *) creationTime +{ + return [sogoObject creationDate]; +} + +- (NSDate *) lastModificationTime +{ + return [sogoObject lastModified]; +} + +- (id) lookupAttachment: (NSString *) childKey +{ + NSDictionary *attachments; + + attachments = [properties objectForKey: @"attachments"]; + + return [attachments objectForKey: childKey]; +} + - (void) getMessageData: (struct mapistore_message **) dataPtr inMemCtx: (TALLOC_CTX *) memCtx { @@ -258,9 +361,11 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" }; samCtx = [[self context] connectionInfo]->sam_ctx; - [super getMessageData: &msgData inMemCtx: memCtx]; + // [super getMessageData: &msgData inMemCtx: memCtx]; - allRecipients = [[sogoObject properties] objectForKey: @"recipients"]; + msgData = talloc_zero (memCtx, struct mapistore_message); + + allRecipients = [properties objectForKey: @"recipients"]; msgData->columns = set_SPropTagArray (msgData, 9, PR_OBJECT_TYPE, PR_DISPLAY_TYPE, @@ -660,10 +765,13 @@ MakeTextPartBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, return textBody; } +// static id +// MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, +// NSString **contentType) static id -MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, - NSString **contentType) +MakeMessageBody (NSDictionary *mailProperties, NSString **contentType) { + NSDictionary *attachmentParts; id messageBody, textBody; NSString *textContentType; NSArray *parts; @@ -671,6 +779,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NGMutableHashMap *headers; NSUInteger count, max; + attachmentParts = [mailProperties objectForKey: @"attachments"]; textBody = MakeTextPartBody (mailProperties, attachmentParts, &textContentType); @@ -707,22 +816,20 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, - (NGMimeMessage *) _generateMessage { - NSDictionary *mailProperties; NSString *contentType; NGMimeMessage *message; NGMutableHashMap *headers; id messageBody; - mailProperties = [sogoObject properties]; - headers = [[NGMutableHashMap alloc] initWithCapacity: 16]; - FillMessageHeadersFromProperties (headers, mailProperties, + FillMessageHeadersFromProperties (headers, properties, [[self context] connectionInfo]); message = [[NGMimeMessage alloc] initWithHeader: headers]; [message autorelease]; [headers release]; - messageBody = MakeMessageBody (mailProperties, attachmentParts, &contentType); + messageBody = MakeMessageBody (properties, &contentType); + // messageBody = MakeMessageBody (mailProperties, attachmentParts, &contentType); if (messageBody) { [headers setObject: contentType forKey: @"content-type"]; @@ -775,7 +882,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, - (int) submitWithFlags: (enum SubmitFlags) flags { - NSDictionary *mailProperties, *recipients; + NSDictionary *recipients; NSData *messageData; NSMutableArray *recipientEmails; NSArray *list; @@ -785,19 +892,17 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, // SOGoMailFolder *sentFolder; SOGoDomainDefaults *dd; NSException *error; - MAPIStoreMapping *mapping; + // MAPIStoreMapping *mapping; - mailProperties = [sogoObject properties]; - msgClass = [mailProperties objectForKey: MAPIPropertyKey (PidTagMessageClass)]; + msgClass = [properties objectForKey: MAPIPropertyKey (PidTagMessageClass)]; if ([msgClass isEqualToString: @"IPM.Note"]) /* we skip invitation replies */ { /* send mail */ messageData = [self _generateMailDataWithBcc: NO]; - mailProperties = [sogoObject properties]; recipientEmails = [NSMutableArray arrayWithCapacity: 32]; - recipients = [mailProperties objectForKey: @"recipients"]; + recipients = [properties objectForKey: @"recipients"]; for (count = 0; count < 3; count++) { recId = recTypes[count]; @@ -819,11 +924,11 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, if (error) [self logWithFormat: @"an error occurred: '%@'", error]; - mapping = [self mapping]; - [mapping unregisterURLWithID: [self objectId]]; - [self setIsNew: NO]; - [properties removeAllObjects]; - [[self container] cleanupCaches]; + // mapping = [self mapping]; + // [mapping unregisterURLWithID: [self objectId]]; + // [self setIsNew: NO]; + // [properties removeAllObjects]; + [(MAPIStoreMailFolder *) [self container] cleanupCaches]; } else [self logWithFormat: @"skipping submit of message with class '%@'", @@ -834,14 +939,14 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, - (void) save { - NSString *folderName, *flag, *newIdString; + NSString *folderName, *flag, *newIdString, *messageKey; NSData *changeKey, *messageData; NGImap4Connection *connection; NGImap4Client *client; SOGoMailFolder *containerFolder; NSDictionary *result, *responseResult; - MAPIStoreMapping *mapping; - uint64_t mid; + // MAPIStoreMapping *mapping; + // uint64_t mid; messageData = [self _generateMailDataWithBcc: YES]; @@ -860,21 +965,24 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, flag = [responseResult objectForKey: @"flag"]; newIdString = [[flag componentsSeparatedByString: @" "] objectAtIndex: 2]; - mid = [self objectId]; - mapping = [self mapping]; - [mapping unregisterURLWithID: mid]; - [sogoObject setNameInContainer: [NSString stringWithFormat: @"%@.eml", newIdString]]; - [mapping registerURL: [self url] withID: mid]; - } + // mid = [self objectId]; + // mapping = [self mapping]; + // [mapping unregisterURLWithID: mid]; + // [sogoObject setNameInContainer: ]; + messageKey = [NSString stringWithFormat: @"%@.eml", newIdString]; + // [mapping registerURL: [NSString stringWithFormat: @"%@%@", + // [(MAPIStoreMailFolder *) container url], messageKey] + // withID: mid]; - /* synchronise the cache and update the change key with the one provided by - the client */ - [(MAPIStoreMailFolder *) container synchroniseCache]; - changeKey = [[sogoObject properties] - objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)]; - if (changeKey) - [(MAPIStoreMailFolder *) container - setChangeKey: changeKey forMessageWithKey: [self nameInContainer]]; + /* synchronise the cache and update the change key with the one provided + by the client */ + [(MAPIStoreMailFolder *) container synchroniseCache]; + changeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)]; + if (changeKey) + [(MAPIStoreMailFolder *) container + setChangeKey: changeKey + forMessageWithKey: messageKey]; + } } @end diff --git a/OpenChange/MAPIStoreMessage.h b/OpenChange/MAPIStoreMessage.h index d1494c060..b7ba24ae7 100644 --- a/OpenChange/MAPIStoreMessage.h +++ b/OpenChange/MAPIStoreMessage.h @@ -35,9 +35,9 @@ @class MAPIStoreAttachmentTable; @class MAPIStoreFolder; -#import "MAPIStoreObject.h" +#import "MAPIStoreSOGoObject.h" -@interface MAPIStoreMessage : MAPIStoreObject +@interface MAPIStoreMessage : MAPIStoreSOGoObject { NSArray *attachmentKeys; NSMutableDictionary *attachmentParts; diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index 35ea1036d..0d42eb048 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -36,6 +36,7 @@ #import "MAPIStoreAttachmentTable.h" #import "MAPIStoreContext.h" #import "MAPIStoreFolder.h" +#import "MAPIStoreMessageTable.h" #import "MAPIStorePropertySelectors.h" #import "MAPIStoreSamDBUtils.h" #import "MAPIStoreTypes.h" @@ -116,7 +117,6 @@ rtf2html (NSData *compressedRTF) @interface SOGoObject (MAPIStoreProtocol) -- (NSString *) davEntityTag; - (NSString *) davContentLength; @end @@ -304,6 +304,7 @@ rtf2html (NSData *compressedRTF) NSData *htmlData, *rtfData; static NSNumber *htmlKey = nil, *rtfKey = nil; + /* we intercept any RTF content and convert it to HTML */ [super addProperties: newNewProperties]; if (!htmlKey) @@ -339,10 +340,8 @@ rtf2html (NSData *compressedRTF) newAid = [[self attachmentKeys] count]; - newAttachment = [MAPIStoreAttachment - mapiStoreObjectWithSOGoObject: nil - inContainer: self]; - [newAttachment setIsNew: YES]; + newAttachment = [MAPIStoreAttachment mapiStoreObjectInContainer: self]; + // [newAttachment setIsNew: YES]; [newAttachment setAID: newAid]; newKey = [NSString stringWithFormat: @"%ul", newAid]; [attachmentParts setObject: newAttachment @@ -497,7 +496,6 @@ rtf2html (NSData *compressedRTF) [[containerTables objectAtIndex: count] notifyChangesForChild: self]; [self setIsNew: NO]; - [properties removeAllObjects]; [container cleanupCaches]; rc = MAPISTORE_SUCCESS; } @@ -792,7 +790,7 @@ rtf2html (NSData *compressedRTF) - (int) getPidTagOriginalMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidTagMessageClass: data inMemCtx: memCtx]; + return [self getProperty: data withTag: PidTagMessageClass inMemCtx: memCtx]; } - (int) getPidTagHasAttachments: (void **) data diff --git a/OpenChange/MAPIStoreMessageTable.h b/OpenChange/MAPIStoreMessageTable.h index 7c3935bba..0779afaef 100644 --- a/OpenChange/MAPIStoreMessageTable.h +++ b/OpenChange/MAPIStoreMessageTable.h @@ -28,6 +28,7 @@ @interface MAPIStoreMessageTable : MAPIStoreTable - (void) setSortOrder: (const struct SSortOrderSet *) set; +- (void) notifyChangesForChild: (MAPIStoreMessage *) child; @end diff --git a/OpenChange/MAPIStoreMessageTable.m b/OpenChange/MAPIStoreMessageTable.m index 33703dc23..3c08e2bab 100644 --- a/OpenChange/MAPIStoreMessageTable.m +++ b/OpenChange/MAPIStoreMessageTable.m @@ -27,6 +27,7 @@ #import #import +#import "MAPIStoreContext.h" #import "MAPIStoreFolder.h" #import "MAPIStoreTypes.h" #import "NSData+MAPIStore.h" @@ -83,4 +84,60 @@ return [(MAPIStoreFolder *) container lookupMessage: childKey]; } +- (void) notifyChangesForChild: (MAPIStoreMessage *) child +{ + NSUInteger currentChildRow, newChildRow; + NSArray *list; + NSString *childName; + struct mapistore_table_notification_parameters notif_parameters; + struct mapistore_context *mstoreCtx; + + mstoreCtx = [[(MAPIStoreFolder *) container context] + connectionInfo]->mstore_ctx; + + notif_parameters.table_type = tableType; + notif_parameters.handle = handleId; + notif_parameters.folder_id = [(MAPIStoreFolder *) container objectId]; + notif_parameters.object_id = [child objectId]; + notif_parameters.instance_id = 0; /* TODO: always 0 ? */ + + childName = [child nameInContainer]; + list = [self restrictedChildKeys]; + currentChildRow = [list indexOfObject: childName]; + notif_parameters.row_id = currentChildRow; + + [self cleanupCaches]; + list = [self restrictedChildKeys]; + newChildRow = [list indexOfObject: childName]; + + if (currentChildRow == NSNotFound) + { + if (newChildRow != NSNotFound) + { + notif_parameters.row_id = newChildRow; + mapistore_push_notification (mstoreCtx, + MAPISTORE_TABLE, + MAPISTORE_OBJECT_CREATED, + ¬if_parameters); + } + } + else + { + if (newChildRow == NSNotFound) + mapistore_push_notification (mstoreCtx, + MAPISTORE_TABLE, + MAPISTORE_OBJECT_DELETED, + ¬if_parameters); + else + { + /* the fact that the row order has changed has no impact here */ + notif_parameters.row_id = newChildRow; + mapistore_push_notification (mstoreCtx, + MAPISTORE_TABLE, + MAPISTORE_OBJECT_MODIFIED, + ¬if_parameters); + } + } +} + @end diff --git a/OpenChange/MAPIStoreNotesContext.h b/OpenChange/MAPIStoreNotesContext.h index ad4a581e1..3f44d575d 100644 --- a/OpenChange/MAPIStoreNotesContext.h +++ b/OpenChange/MAPIStoreNotesContext.h @@ -23,9 +23,9 @@ #ifndef MAPISTORENOTESCONTEXT_H #define MAPISTORENOTESCONTEXT_H -#import "MAPIStoreFSBaseContext.h" +#import "MAPIStoreDBBaseContext.h" -@interface MAPIStoreNotesContext : MAPIStoreFSBaseContext +@interface MAPIStoreNotesContext : MAPIStoreDBBaseContext @end diff --git a/OpenChange/MAPIStoreNotesFolder.h b/OpenChange/MAPIStoreNotesFolder.h index de2eb2748..9baebab27 100644 --- a/OpenChange/MAPIStoreNotesFolder.h +++ b/OpenChange/MAPIStoreNotesFolder.h @@ -23,9 +23,9 @@ #ifndef MAPISTORENOTESFOLDER_H #define MAPISTORENOTESFOLDER_H -#import "MAPIStoreFSFolder.h" +#import "MAPIStoreDBFolder.h" -@interface MAPIStoreNotesFolder : MAPIStoreFSFolder +@interface MAPIStoreNotesFolder : MAPIStoreDBFolder @end #endif /* MAPISTORENOTESFOLDER_H */ diff --git a/OpenChange/MAPIStoreNotesMessage.h b/OpenChange/MAPIStoreNotesMessage.h index 81adfc0dc..d4ec7e1ba 100644 --- a/OpenChange/MAPIStoreNotesMessage.h +++ b/OpenChange/MAPIStoreNotesMessage.h @@ -23,9 +23,9 @@ #ifndef MAPISTORENOTESMESSAGE_H #define MAPISTORENOTESMESSAGE_H -#import "MAPIStoreFSMessage.h" +#import "MAPIStoreDBMessage.h" -@interface MAPIStoreNotesMessage : MAPIStoreFSMessage +@interface MAPIStoreNotesMessage : MAPIStoreDBMessage @end #endif /* MAPISTORENOTESMESSAGE_H */ diff --git a/OpenChange/MAPIStoreNotesMessage.m b/OpenChange/MAPIStoreNotesMessage.m index d59d9a2f8..7cac637b8 100644 --- a/OpenChange/MAPIStoreNotesMessage.m +++ b/OpenChange/MAPIStoreNotesMessage.m @@ -53,21 +53,4 @@ return MAPISTORE_SUCCESS; } -- (int) getPidTagSubject: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - id value; - int rc; - - value = [[sogoObject properties] - objectForKey: MAPIPropertyKey (PidTagNormalizedSubject)]; - if (value) - rc = [value getValue: data forTag: PidTagNormalizedSubject - inMemCtx: memCtx]; - else - rc = MAPISTORE_ERR_NOT_FOUND; - - return rc; -} - @end diff --git a/OpenChange/MAPIStoreObject.h b/OpenChange/MAPIStoreObject.h index cb7ed7809..709396e9f 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -33,56 +33,38 @@ @class NSMutableArray; @class NSMutableDictionary; -@class EOQualifier; - @class MAPIStoreContext; -@class MAPIStoreFolder; @class MAPIStoreMapping; -@class MAPIStoreTable; @class MAPIStoreUserContext; +@class MAPIStoreSOGoObject; @interface MAPIStoreObject : NSObject { const IMP *classGetters; NSMutableArray *parentContainersBag; - MAPIStoreObject *container; - id sogoObject; + id container; NSMutableDictionary *properties; - BOOL isNew; } -+ (id) mapiStoreObjectWithSOGoObject: (id) newSOGoObject - inContainer: (MAPIStoreObject *) newContainer; ++ (id) mapiStoreObjectInContainer: (MAPIStoreObject *) newContainer; +- (id) initInContainer: (MAPIStoreObject *) newContainer; + + (int) getAvailableProperties: (struct SPropTagArray **) propertiesP inMemCtx: (TALLOC_CTX *) memCtx; -- (id) initWithSOGoObject: (id) newSOGoObject - inContainer: (MAPIStoreObject *) newFolder; - -- (void) setIsNew: (BOOL) newIsNew; -- (BOOL) isNew; - -- (NSString *) nameInContainer; - -- (id) sogoObject; - (MAPIStoreObject *) container; - (MAPIStoreContext *) context; - (MAPIStoreUserContext *) userContext; - (MAPIStoreMapping *) mapping; -- (void) cleanupCaches; - -- (uint64_t) objectId; -- (NSString *) url; - /* properties */ - (BOOL) canGetProperty: (enum MAPITAGS) propTag; - (void) addProperties: (NSDictionary *) newProperties; -- (NSDictionary *) properties; +- (NSMutableDictionary *) properties; /* ops */ - (int) getAvailableProperties: (struct SPropTagArray **) propertiesP @@ -104,26 +86,12 @@ fromGlobCnt: (uint64_t) objectCnt inMemCtx: (TALLOC_CTX *) memCtx; -/* implemented getters */ -- (int) getPidTagDisplayName: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; -- (int) getPidTagSearchKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; -- (int) getPidTagGenerateExchangeViews: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; -- (int) getPidTagParentSourceKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; -- (int) getPidTagSourceKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; -- (int) getPidTagChangeKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; - (int) getPidTagCreationTime: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; - (int) getPidTagLastModificationTime: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; /* subclasses */ -- (uint64_t) objectVersion; - (NSDate *) creationTime; - (NSDate *) lastModificationTime; diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index e3d379d6b..ac782cdc8 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -58,13 +58,11 @@ static Class NSExceptionK, MAPIStoreFolderK; MAPIStoreFolderK = [MAPIStoreFolder class]; } -+ (id) mapiStoreObjectWithSOGoObject: (id) newSOGoObject - inContainer: (MAPIStoreObject *) newContainer ++ (id) mapiStoreObjectInContainer: (MAPIStoreObject *) newContainer { id newObject; - newObject = [[self alloc] initWithSOGoObject: newSOGoObject - inContainer: newContainer]; + newObject = [[self alloc] initInContainer: newContainer]; [newObject autorelease]; return newObject; @@ -106,22 +104,18 @@ static Class NSExceptionK, MAPIStoreFolderK; classGetters = (IMP *) MAPIStorePropertyGettersForClass (isa); parentContainersBag = [NSMutableArray new]; container = nil; - sogoObject = nil; properties = [NSMutableDictionary new]; - isNew = NO; } - [self logWithFormat: @"-init"]; + // [self logWithFormat: @"-init"]; return self; } -- (id) initWithSOGoObject: (id) newSOGoObject - inContainer: (MAPIStoreObject *) newContainer +- (id) initInContainer: (MAPIStoreObject *) newContainer { if ((self = [self init])) { - ASSIGN (sogoObject, newSOGoObject); ASSIGN (container, newContainer); } @@ -130,42 +124,21 @@ static Class NSExceptionK, MAPIStoreFolderK; - (void) dealloc { - [self logWithFormat: @"-dealloc"]; - [sogoObject release]; + // [self logWithFormat: @"-dealloc"]; [properties release]; [parentContainersBag release]; [container release]; [super dealloc]; } -- (void) setIsNew: (BOOL) newIsNew -{ - isNew = newIsNew; -} - -- (BOOL) isNew -{ - return isNew; -} - -- (id) sogoObject -{ - return sogoObject; -} - - (MAPIStoreObject *) container { return container; } -- (NSString *) nameInContainer -{ - return [sogoObject nameInContainer]; -} - - (MAPIStoreContext *) context { - return [container context]; + return (MAPIStoreContext *) [container context]; } - (MAPIStoreUserContext *) userContext @@ -178,47 +151,14 @@ static Class NSExceptionK, MAPIStoreFolderK; return [[self userContext] mapping]; } -- (void) cleanupCaches -{ -} - /* helpers */ -- (uint64_t) objectId -{ - uint64_t objectId; - - if ([container isKindOfClass: MAPIStoreFolderK]) - objectId = [(MAPIStoreFolder *) container - idForObjectWithKey: [sogoObject nameInContainer]]; - else - { - [self errorWithFormat: @"%s: container is not a folder", __PRETTY_FUNCTION__]; - objectId = (uint64_t) -1; - } - - return objectId; -} - -- (NSString *) url -{ - NSString *containerURL, *format; - - containerURL = [container url]; - if ([containerURL hasSuffix: @"/"]) - format = @"%@%@"; - else - format = @"%@/%@"; - - return [NSString stringWithFormat: format, - containerURL, [self nameInContainer]]; -} - (void) addProperties: (NSDictionary *) newNewProperties { [properties addEntriesFromDictionary: newNewProperties]; } -- (NSDictionary *) properties +- (NSMutableDictionary *) properties { return properties; } @@ -248,124 +188,8 @@ static Class NSExceptionK, MAPIStoreFolderK; return rc; } -/* helper getters */ -- (NSData *) getReplicaKeyFromGlobCnt: (uint64_t) objectCnt -{ - struct mapistore_connection_info *connInfo; - NSMutableData *replicaKey; - char buffer[6]; - NSUInteger count; - - connInfo = [[self context] connectionInfo]; - - for (count = 0; count < 6; count++) - { - buffer[count] = objectCnt & 0xff; - objectCnt >>= 8; - } - - replicaKey = [NSMutableData dataWithCapacity: 22]; - [replicaKey appendBytes: &connInfo->replica_guid - length: sizeof (struct GUID)]; - [replicaKey appendBytes: buffer length: 6]; - - return replicaKey; -} - -- (int) getReplicaKey: (void **) data - fromGlobCnt: (uint64_t) objectCnt - inMemCtx: (TALLOC_CTX *) memCtx -{ - *data = [[self getReplicaKeyFromGlobCnt: objectCnt] asBinaryInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - -/* getters */ -- (int) getPidTagDisplayName: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - *data = [[sogoObject displayName] asUnicodeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - -- (int) getPidTagSearchKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - NSString *stringValue; - - stringValue = [sogoObject nameInContainer]; - *data = [[stringValue dataUsingEncoding: NSASCIIStringEncoding] - asBinaryInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - -- (int) getPidTagGenerateExchangeViews: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getNo: data inMemCtx: memCtx]; -} - -- (int) getPidTagParentSourceKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getReplicaKey: data fromGlobCnt: [container objectId] >> 16 - inMemCtx: memCtx]; -} - -- (int) getPidTagSourceKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getReplicaKey: data fromGlobCnt: [self objectId] >> 16 - inMemCtx: memCtx]; -} - -- (uint64_t) objectVersion -{ - [self subclassResponsibility: _cmd]; - - return ULLONG_MAX; -} - -- (int) getPidTagChangeKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - int rc; - uint64_t obVersion; - - obVersion = [self objectVersion]; - if (obVersion == ULLONG_MAX) - rc = MAPISTORE_ERR_NOT_FOUND; - else - rc = [self getReplicaKey: data fromGlobCnt: obVersion - inMemCtx: memCtx]; - - return rc; -} - -- (int) getPidTagChangeNumber: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - int rc; - uint64_t obVersion; - - obVersion = [self objectVersion]; - if (obVersion == ULLONG_MAX) - rc = MAPISTORE_ERR_NOT_FOUND; - else - { - *data = MAPILongLongValue (memCtx, ((obVersion << 16) - | 0x0001)); - rc = MAPISTORE_SUCCESS; - } - - return rc; -} - - (int) getPidTagCreationTime: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { *data = [[self creationTime] asFileTimeInMemCtx: memCtx]; @@ -474,6 +298,38 @@ static Class NSExceptionK, MAPIStoreFolderK; return MAPISTORE_SUCCESS; } +- (NSData *) getReplicaKeyFromGlobCnt: (uint64_t) objectCnt +{ + struct mapistore_connection_info *connInfo; + NSMutableData *replicaKey; + char buffer[6]; + NSUInteger count; + + connInfo = [[self context] connectionInfo]; + + for (count = 0; count < 6; count++) + { + buffer[count] = objectCnt & 0xff; + objectCnt >>= 8; + } + + replicaKey = [NSMutableData dataWithCapacity: 22]; + [replicaKey appendBytes: &connInfo->replica_guid + length: sizeof (struct GUID)]; + [replicaKey appendBytes: buffer length: 6]; + + return replicaKey; +} + +- (int) getReplicaKey: (void **) data + fromGlobCnt: (uint64_t) objectCnt + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [[self getReplicaKeyFromGlobCnt: objectCnt] asBinaryInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + /* subclasses */ - (NSDate *) creationTime { diff --git a/OpenChange/MAPIStorePermissionsTable.m b/OpenChange/MAPIStorePermissionsTable.m index 6d4c57c55..2385ee8a5 100644 --- a/OpenChange/MAPIStorePermissionsTable.m +++ b/OpenChange/MAPIStorePermissionsTable.m @@ -50,7 +50,7 @@ MAPIStorePermissionEntry *newEntry; newEntry = [[self alloc] initWithUserId: newUserId andMemberId: newMemberId - forFolder: newFolder]; + forFolder: newFolder]; [newEntry autorelease]; return newEntry; @@ -60,7 +60,7 @@ andMemberId: (uint64_t) newMemberId forFolder: (MAPIStoreFolder *) newFolder { - if ((self = [self initWithSOGoObject: nil inContainer: newFolder])) + if ((self = [self initInContainer: newFolder])) { ASSIGN (userId, newUserId); memberId = newMemberId; diff --git a/OpenChange/MAPIStoreSOGoObject.h b/OpenChange/MAPIStoreSOGoObject.h new file mode 100644 index 000000000..90524558f --- /dev/null +++ b/OpenChange/MAPIStoreSOGoObject.h @@ -0,0 +1,89 @@ +/* MAPIStoreObject.h - this file is part of SOGo + * + * Copyright (C) 2011 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef MAPISTORESOGOOBJECT_H +#define MAPISTORESOGOOBJECT_H + +#include + +#import "MAPIStoreObject.h" + +@class NSDate; +@class NSData; +@class NSString; +@class NSMutableArray; +@class NSMutableDictionary; + +@class EOQualifier; + +@class MAPIStoreContext; +@class MAPIStoreFolder; +@class MAPIStoreMapping; +@class MAPIStoreTable; +@class MAPIStoreUserContext; + +@interface MAPIStoreSOGoObject : MAPIStoreObject +{ + id sogoObject; + BOOL isNew; +} + ++ (id) mapiStoreObjectWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newContainer; + +- (id) initWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newFolder; + +- (void) setIsNew: (BOOL) newIsNew; +- (BOOL) isNew; + +- (id) sogoObject; + +- (NSString *) nameInContainer; + +- (MAPIStoreObject *) container; + +- (void) cleanupCaches; + +- (uint64_t) objectId; +- (NSString *) url; + +/* implemented getters */ +- (int) getPidTagDisplayName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidTagSearchKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidTagGenerateExchangeViews: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidTagParentSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidTagSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidTagChangeKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; + +/* subclasses */ +- (uint64_t) objectVersion; + +@end + +#endif /* MAPISTORESOGOOBJECT_H */ diff --git a/OpenChange/MAPIStoreSOGoObject.m b/OpenChange/MAPIStoreSOGoObject.m new file mode 100644 index 000000000..d2d3b4790 --- /dev/null +++ b/OpenChange/MAPIStoreSOGoObject.m @@ -0,0 +1,255 @@ +/* MAPIStoreObject.m - this file is part of SOGo + * + * Copyright (C) 2011 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import +#import +#import +#import +#import +#import +#import + +#import "MAPIStoreContext.h" +#import "MAPIStoreFolder.h" +#import "MAPIStorePropertySelectors.h" +#import "MAPIStoreTypes.h" +#import "MAPIStoreUserContext.h" +#import "NSDate+MAPIStore.h" +#import "NSData+MAPIStore.h" +#import "NSObject+MAPIStore.h" +#import "NSString+MAPIStore.h" + +#import "MAPIStoreSOGoObject.h" + +#undef DEBUG +#include +#include +#include +#include +#include + +@implementation MAPIStoreSOGoObject + +static Class MAPIStoreFolderK; + ++ (void) initialize +{ + MAPIStoreFolderK = [MAPIStoreFolder class]; +} + ++ (id) mapiStoreObjectWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newContainer +{ + id newObject; + + newObject = [[self alloc] initWithSOGoObject: newSOGoObject + inContainer: newContainer]; + [newObject autorelease]; + + return newObject; +} + +- (id) init +{ + if ((self = [super init])) + { + sogoObject = nil; + isNew = NO; + } + + [self logWithFormat: @"-init"]; + + return self; +} + +- (id) initWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newContainer +{ + if ((self = [self initInContainer: newContainer])) + { + ASSIGN (sogoObject, newSOGoObject); + } + + return self; +} + +- (void) dealloc +{ + // [self logWithFormat: @"-dealloc"]; + [sogoObject release]; + [super dealloc]; +} + +- (void) setIsNew: (BOOL) newIsNew +{ + isNew = newIsNew; +} + +- (BOOL) isNew +{ + return isNew; +} + +- (id) sogoObject +{ + return sogoObject; +} + +- (MAPIStoreObject *) container +{ + return container; +} + +- (NSString *) nameInContainer +{ + return [sogoObject nameInContainer]; +} + +- (void) cleanupCaches +{ +} + +/* helpers */ +- (uint64_t) objectId +{ + uint64_t objectId; + + if ([container isKindOfClass: MAPIStoreFolderK]) + objectId = [(MAPIStoreFolder *) container + idForObjectWithKey: [sogoObject nameInContainer]]; + else + { + [self errorWithFormat: @"%s: container is not a folder", __PRETTY_FUNCTION__]; + objectId = (uint64_t) -1; + } + + return objectId; +} + +- (NSString *) url +{ + NSString *containerURL, *format; + + containerURL = (NSString *) [container url]; + if ([containerURL hasSuffix: @"/"]) + format = @"%@%@"; + else + format = @"%@/%@"; + + return [NSString stringWithFormat: format, + containerURL, [self nameInContainer]]; +} + +/* getters */ +- (int) getPidTagDisplayName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [[sogoObject displayName] asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagSearchKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSString *stringValue; + + stringValue = [sogoObject nameInContainer]; + *data = [[stringValue dataUsingEncoding: NSASCIIStringEncoding] + asBinaryInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagGenerateExchangeViews: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getNo: data inMemCtx: memCtx]; +} + +- (int) getPidTagParentSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getReplicaKey: data fromGlobCnt: [container objectId] >> 16 + inMemCtx: memCtx]; +} + +- (int) getPidTagSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getReplicaKey: data fromGlobCnt: [self objectId] >> 16 + inMemCtx: memCtx]; +} + +/* helper getters */ +- (int) getPidTagChangeKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + int rc; + uint64_t obVersion; + + obVersion = [self objectVersion]; + if (obVersion == ULLONG_MAX) + rc = MAPISTORE_ERR_NOT_FOUND; + else + rc = [self getReplicaKey: data fromGlobCnt: obVersion + inMemCtx: memCtx]; + + return rc; +} + +- (int) getPidTagChangeNumber: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + int rc; + uint64_t obVersion; + + obVersion = [self objectVersion]; + if (obVersion == ULLONG_MAX) + rc = MAPISTORE_ERR_NOT_FOUND; + else + { + *data = MAPILongLongValue (memCtx, ((obVersion << 16) + | 0x0001)); + rc = MAPISTORE_SUCCESS; + } + + return rc; +} + +/* subclasses */ +- (uint64_t) objectVersion +{ + [self subclassResponsibility: _cmd]; + + return ULLONG_MAX; +} + +/* logging */ +- (NSString *) loggingPrefix +{ + return [NSString stringWithFormat:@"<%@:%p:%@>", + NSStringFromClass (isa), self, [self nameInContainer]]; +} + +@end diff --git a/OpenChange/MAPIStoreTable.h b/OpenChange/MAPIStoreTable.h index fbf13a680..7695c79f0 100644 --- a/OpenChange/MAPIStoreTable.h +++ b/OpenChange/MAPIStoreTable.h @@ -100,8 +100,6 @@ typedef enum { - (int) getRowCount: (uint32_t *) countP withQueryType: (enum mapistore_query_type) queryType; -- (void) notifyChangesForChild: (MAPIStoreObject *) child; - /* helpers */ - (SEL) operatorFromRestrictionOperator: (uint32_t) resOp; diff --git a/OpenChange/MAPIStoreTable.m b/OpenChange/MAPIStoreTable.m index 620b8f248..b47ce8a72 100644 --- a/OpenChange/MAPIStoreTable.m +++ b/OpenChange/MAPIStoreTable.m @@ -874,61 +874,6 @@ static Class NSDataK, NSStringK; return MAPISTORE_SUCCESS; } -- (void) notifyChangesForChild: (MAPIStoreObject *) child -{ - NSUInteger currentChildRow, newChildRow; - NSArray *list; - NSString *childName; - struct mapistore_table_notification_parameters notif_parameters; - struct mapistore_context *mstoreCtx; - - mstoreCtx = [[container context] connectionInfo]->mstore_ctx; - - notif_parameters.table_type = tableType; - notif_parameters.handle = handleId; - notif_parameters.folder_id = [container objectId]; - notif_parameters.object_id = [child objectId]; - notif_parameters.instance_id = 0; /* TODO: always 0 ? */ - - childName = [child nameInContainer]; - list = [self restrictedChildKeys]; - currentChildRow = [list indexOfObject: childName]; - notif_parameters.row_id = currentChildRow; - - [self cleanupCaches]; - list = [self restrictedChildKeys]; - newChildRow = [list indexOfObject: childName]; - - if (currentChildRow == NSNotFound) - { - if (newChildRow != NSNotFound) - { - notif_parameters.row_id = newChildRow; - mapistore_push_notification (mstoreCtx, - MAPISTORE_TABLE, - MAPISTORE_OBJECT_CREATED, - ¬if_parameters); - } - } - else - { - if (newChildRow == NSNotFound) - mapistore_push_notification (mstoreCtx, - MAPISTORE_TABLE, - MAPISTORE_OBJECT_DELETED, - ¬if_parameters); - else - { - /* the fact that the row order has changed has no impact here */ - notif_parameters.row_id = newChildRow; - mapistore_push_notification (mstoreCtx, - MAPISTORE_TABLE, - MAPISTORE_OBJECT_MODIFIED, - ¬if_parameters); - } - } -} - /* subclasses */ - (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property { diff --git a/OpenChange/MAPIStoreUserContext.h b/OpenChange/MAPIStoreUserContext.h index 5cdd38710..70f142b3d 100644 --- a/OpenChange/MAPIStoreUserContext.h +++ b/OpenChange/MAPIStoreUserContext.h @@ -28,6 +28,7 @@ @class NSMutableDictionary; @class NSString; @class NSTimeZone; +@class NSURL; @class WOContext; @@ -52,6 +53,9 @@ MAPIStoreMapping *mapping; + BOOL userDbTableExists; + NSURL *folderTableURL; + WOContext *woContext; MAPIStoreAuthenticator *authenticator; } @@ -71,8 +75,11 @@ - (NSDictionary *) rootFolders; +- (NSURL *) folderTableURL; - (MAPIStoreMapping *) mapping; +- (void) ensureFolderTableExists; + /* SOGo hacky magic */ - (void) activateWithUser: (SOGoUser *) activeUser; - (MAPIStoreAuthenticator *) authenticator; diff --git a/OpenChange/MAPIStoreUserContext.m b/OpenChange/MAPIStoreUserContext.m index dcb3cfb72..bf5d97f0c 100644 --- a/OpenChange/MAPIStoreUserContext.m +++ b/OpenChange/MAPIStoreUserContext.m @@ -6,7 +6,7 @@ * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) + * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This file is distributed in the hope that it will be useful, @@ -23,17 +23,21 @@ #import #import #import +#import #import #import #import +#import +#import #import #import #import #import +#import "GCSSpecialQueries+OpenChange.h" #import "MAPIApplication.h" #import "MAPIStoreAuthenticator.h" #import "MAPIStoreMapping.h" @@ -80,6 +84,9 @@ static NSMapTable *contextsTable = nil; mapping = nil; + userDbTableExists = NO; + folderTableURL = nil; + authenticator = nil; woContext = [WOContext contextWithRequest: nil]; [woContext retain]; @@ -117,6 +124,8 @@ static NSMapTable *contextsTable = nil; [authenticator release]; [mapping release]; + [folderTableURL release]; + [sogoUser release]; [contextsTable removeObjectForKey: username]; @@ -213,6 +222,72 @@ static NSMapTable *contextsTable = nil; return mapping; } + +/* OpenChange db table */ + +- (NSURL *) folderTableURL +{ + NSString *urlString, *ocFSTableName; + NSMutableArray *parts; + SOGoUser *user; + + if (!folderTableURL) + { + user = [self sogoUser]; + urlString = [[user domainDefaults] folderInfoURL]; + parts = [[urlString componentsSeparatedByString: @"/"] + mutableCopy]; + [parts autorelease]; + if ([parts count] == 5) + { + /* If "OCSFolderInfoURL" is properly configured, we must have 5 + parts in this url. */ + ocFSTableName = [NSString stringWithFormat: @"socfs_%@", username]; + [parts replaceObjectAtIndex: 4 withObject: ocFSTableName]; + folderTableURL + = [NSURL URLWithString: [parts componentsJoinedByString: @"/"]]; + [folderTableURL retain]; + } + else + [NSException raise: @"MAPIStoreIOException" + format: @"'OCSFolderInfoURL' is not set"]; + } + + return folderTableURL; +} + +- (void) ensureFolderTableExists +{ + GCSChannelManager *cm; + EOAdaptorChannel *channel; + NSString *tableName, *query; + GCSSpecialQueries *queries; + + [self folderTableURL]; + + cm = [GCSChannelManager defaultChannelManager]; + channel = [cm acquireOpenChannelForURL: folderTableURL]; + + /* FIXME: make use of [EOChannelAdaptor describeTableNames] instead */ + tableName = [[folderTableURL path] lastPathComponent]; + if ([channel evaluateExpressionX: + [NSString stringWithFormat: @"SELECT count(*) FROM %@", + tableName]]) + { + queries = [channel specialQueries]; + query = [queries createOpenChangeFSTableWithName: tableName]; + if ([channel evaluateExpressionX: query]) + [NSException raise: @"MAPIStoreIOException" + format: @"could not create special table '%@'", tableName]; + } + else + [channel cancelFetch]; + + + [cm releaseChannel: channel]; +} + +/* SOGo context objects */ - (WOContext *) woContext { return woContext; diff --git a/OpenChange/MAPIStoreVolatileMessage.h b/OpenChange/MAPIStoreVolatileMessage.h deleted file mode 100644 index 71e02c5f8..000000000 --- a/OpenChange/MAPIStoreVolatileMessage.h +++ /dev/null @@ -1,37 +0,0 @@ -/* MAPIStoreVolatileMessage.h - this file is part of SOGo - * - * Copyright (C) 2011 Inverse inc - * - * Author: Wolfgang Sourdeau - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef MAPISTOREVOLATILEMESSAGE_H -#define MAPISTOREVOLATILEMESSAGE_H - -#import "MAPIStoreMessage.h" - -@interface MAPIStoreVolatileMessage : MAPIStoreMessage -{ - BOOL fetchedAttachments; - NSDate *creationTime; - NSDate *lastModificationTime; -} - -@end - -#endif /* MAPISTOREVOLATILEMESSAGE_H */ diff --git a/OpenChange/MAPIStoreVolatileMessage.m b/OpenChange/MAPIStoreVolatileMessage.m deleted file mode 100644 index b248ef12a..000000000 --- a/OpenChange/MAPIStoreVolatileMessage.m +++ /dev/null @@ -1,208 +0,0 @@ -/* MAPIStoreVolatileMessage.m - this file is part of SOGo - * - * Copyright (C) 2011 Inverse inc - * - * Author: Wolfgang Sourdeau - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -#import "MAPIStoreContext.h" -#import "MAPIStoreMailFolder.h" -#import "MAPIStoreMapping.h" -#import "MAPIStoreTypes.h" -#import "NSData+MAPIStore.h" -#import "NSObject+MAPIStore.h" -#import "NSString+MAPIStore.h" -#import "SOGoMAPIVolatileMessage.h" - -#import "MAPIStoreVolatileMessage.h" - -#undef DEBUG -#include -#include - -Class NSNumberK; - -@implementation MAPIStoreVolatileMessage - -+ (void) initialize -{ - NSNumberK = [NSNumber class]; -} - -- (id) init -{ - if ((self = [super init])) - { - fetchedAttachments = NO; - ASSIGN (creationTime, [NSDate date]); - lastModificationTime = [creationTime copy]; - } - - return self; -} - -- (void) dealloc -{ - [creationTime release]; - [lastModificationTime release]; - [super dealloc]; -} - -- (void) addProperties: (NSDictionary *) newProperties -{ - [super addProperties: newProperties]; - [sogoObject appendProperties: properties]; - [properties removeAllObjects]; - ASSIGN (lastModificationTime, [NSDate date]); -} - -- (BOOL) canGetProperty: (enum MAPITAGS) propTag -{ - return ([super canGetProperty: propTag] - || [[sogoObject properties] objectForKey: MAPIPropertyKey (propTag)]); -} - -- (uint64_t) objectVersion -{ - NSNumber *version; - - version = [[sogoObject properties] objectForKey: @"version"]; - - return (version - ? exchange_globcnt ([version unsignedLongLongValue]) - : ULLONG_MAX); -} - -- (int) getProperty: (void **) data - withTag: (enum MAPITAGS) propTag - inMemCtx: (TALLOC_CTX *) memCtx -{ - id value; - int rc; - - value = [[sogoObject properties] objectForKey: MAPIPropertyKey (propTag)]; - if (value) - rc = [value getValue: data forTag: propTag inMemCtx: memCtx]; - else - rc = [super getProperty: data withTag: propTag inMemCtx: memCtx]; - - return rc; -} - -- (int) getPidTagSubject: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - /* if we get here, it means that the properties file didn't contain a - relevant value */ - return [self getEmptyString: data inMemCtx: memCtx]; -} - -- (int) getPidTagMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - *data = [@"IPM.Note" asUnicodeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - -- (int) getPidTagChangeKey: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - NSData *changeKey; - int rc; - - changeKey = [[sogoObject properties] - objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)]; - if (changeKey) - { - *data = [changeKey asBinaryInMemCtx: memCtx]; - rc = MAPISTORE_SUCCESS; - } - else - rc = [super getPidTagChangeKey: data inMemCtx: memCtx]; - - return rc; -} - -- (NSArray *) attachmentsKeysMatchingQualifier: (EOQualifier *) qualifier - andSortOrderings: (NSArray *) sortOrderings -{ - NSDictionary *attachments; - NSArray *keys; - NSString *key, *newKey; - NSUInteger count, max, aid; - MAPIStoreAttachment *attachment; - - if (!fetchedAttachments) - { - attachments = [[sogoObject properties] objectForKey: @"attachments"]; - keys = [attachments allKeys]; - max = [keys count]; - if (max > 0) - { - aid = [keys count]; - for (count = 0; count < max; count++) - { - key = [keys objectAtIndex: count]; - attachment = [attachments objectForKey: key]; - newKey = [NSString stringWithFormat: @"%ul", (aid + count)]; - [attachmentParts setObject: attachment forKey: newKey]; - } - } - fetchedAttachments = YES; - } - - return [super attachmentKeysMatchingQualifier: qualifier - andSortOrderings: sortOrderings]; -} - -- (NSDate *) creationTime -{ - return creationTime; -} - -- (NSDate *) lastModificationTime -{ - return lastModificationTime; -} - -- (id) lookupAttachment: (NSString *) childKey -{ - return [attachmentParts objectForKey: childKey]; -} - -- (void) save -{ - [self subclassResponsibility: _cmd]; -} - -@end diff --git a/OpenChange/NSObject+PropertyList.m b/OpenChange/NSObject+PropertyList.m new file mode 100644 index 000000000..9f9762508 --- /dev/null +++ b/OpenChange/NSObject+PropertyList.m @@ -0,0 +1,182 @@ +/* dbmsgdump.m - this file is part of SOGo + * + * Copyright (C) 2011 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* A format-agnostic property list dumper. + Usage: dbmsgdump [filename] */ + +#import +#import +#import +#import +#import +#import +#import +#import +#import + +const char *indentationStep = " "; + +@interface NSObject (plext) + +- (void) displayWithIndentation: (NSInteger) anInt; + +@end + +@implementation NSObject (plext) + +- (void) _outputIndentation: (NSInteger) anInt +{ + NSInteger i; + + for (i = 0; i < anInt; i++) + printf ("%s", indentationStep); +} + +- (void) displayWithIndentation: (NSInteger) anInt +{ + printf ("(%s) %s", + [NSStringFromClass (isa) UTF8String], + [[self description] UTF8String]); +} + +@end + +@implementation NSDictionary (plext) + +- (void) displayKey: (NSString *) key + withIndentation: (NSInteger) anInt +{ + [self _outputIndentation: anInt]; + + printf ("%s ", [[key description] UTF8String]); + if ([key isKindOfClass: [NSValue class]]) + printf ("(%s: 0x%.8x) ", [(NSValue *) key objCType], [key intValue]); + + printf ("= "); +} + +- (void) displayWithIndentation: (NSInteger) anInt +{ + NSUInteger i, max; + NSArray *keys; + NSInteger subIndent; + NSString *key; + + keys = [self allKeys]; + max = [keys count]; + + printf ("{ (%ld) items\n", (long) max); + + subIndent = anInt + 1; + + for (i = 0; i < max; i++) + { + key = [keys objectAtIndex: i]; + [self displayKey: key withIndentation: subIndent]; + [[self objectForKey: key] displayWithIndentation: subIndent]; + if (i < (max - 1)) + printf (","); + printf ("\n"); + } + + [self _outputIndentation: anInt]; + printf ("}"); +} + +@end + +@implementation NSArray (plext) + +- (void) displayCount: (NSUInteger) count + withIndentation: (NSInteger) anInt +{ + [self _outputIndentation: anInt]; + printf ("%lu = ", (unsigned long) count); +} + +- (void) displayWithIndentation: (NSInteger) anInt +{ + NSUInteger i, max; + NSInteger subIndent; + + max = [self count]; + + printf ("[ (%ld) items\n", (long) max); + + subIndent = anInt + 1; + + for (i = 0; i < max; i++) + { + [self displayCount: i withIndentation: subIndent]; + [[self objectAtIndex: i] displayWithIndentation: subIndent]; + if (i < (max - 1)) + printf (","); + printf ("\n"); + } + + [self _outputIndentation: anInt]; + printf ("]"); +} + +@end + +static void +OCDumpPListData (NSData *content) +{ + NSDictionary *d; + NSPropertyListFormat format; + NSString *error = nil; + const char *formatName; + + d = [NSPropertyListSerialization propertyListFromData: content + mutabilityOption: NSPropertyListImmutable + format: &format + errorDescription: &error]; + if (d) + { + switch (format) + { + case NSPropertyListOpenStepFormat: + formatName = "OpenStep"; + break; + case NSPropertyListXMLFormat_v1_0: + formatName = "XML"; + break; + case NSPropertyListBinaryFormat_v1_0: + formatName = "Binary"; + break; + case NSPropertyListGNUstepFormat: + formatName = "GNUstep"; + break; + case NSPropertyListGNUstepBinaryFormat: + formatName = "GNUstep binary"; + break; + default: formatName = "unknown"; + } + + printf ("File format is: %s\n", formatName); + [d displayWithIndentation: 0]; + printf ("\n"); + } + else + printf ("an error occurred: %s\n", [error UTF8String]); +} diff --git a/OpenChange/SOGoMAPIFSFolder.h b/OpenChange/SOGoMAPIDBFolder.h similarity index 52% rename from OpenChange/SOGoMAPIFSFolder.h rename to OpenChange/SOGoMAPIDBFolder.h index 244094129..e2d29058f 100644 --- a/OpenChange/SOGoMAPIFSFolder.h +++ b/OpenChange/SOGoMAPIDBFolder.h @@ -1,6 +1,6 @@ -/* SOGoMAPIFSFolder.h - this file is part of SOGo +/* SOGoMAPIDBFolder.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -20,41 +20,38 @@ * Boston, MA 02111-1307, USA. */ -#ifndef SOGOMAPIFSFOLDER_H -#define SOGOMAPIFSFOLDER_H +#ifndef SOGOMAPIDBFOLDER_H +#define SOGOMAPIDBFOLDER_H -#import +#import "SOGoMAPIDBObject.h" @class NSArray; +@class NSMutableString; @class NSString; @class NSURL; @class EOQualifier; -@class SOGoMAPIFSMessage; +@class SOGoMAPIDBMessage; -@interface SOGoMAPIFSFolder : SOGoFolder +@interface SOGoMAPIDBFolder : SOGoMAPIDBObject { - NSString *directory; - BOOL directoryIsSane; + NSString *pathPrefix; /* for root folders */ + SOGoMAPIDBObject *aclMessage; } -+ (id) folderWithURL: (NSURL *) url - andTableType: (uint8_t) tableType; -- (id) initWithURL: (NSURL *) url - andTableType: (uint8_t) tableType; +- (void) setPathPrefix: (NSString *) newPathPrefix; -- (NSString *) directory; +- (NSMutableString *) pathForChild: (NSString *) childName; -- (SOGoMAPIFSMessage *) newMessage; -- (void) ensureDirectory; +- (NSArray *) toOneRelationshipKeys; +- (NSArray *) toManyRelationshipKeys; -- (NSCalendarDate *) creationTime; -- (NSCalendarDate *) lastModificationTime; - -- (NSArray *) toOneRelationshipKeysMatchingQualifier: (EOQualifier *) qualifier - andSortOrderings: (NSArray *) sortOrderings; +- (NSArray *) childKeysOfType: (MAPIDBObjectType) type + includeDeleted: (BOOL) includeDeleted + matchingQualifier: (EOQualifier *) qualifier + andSortOrderings: (NSArray *) sortOrderings; @end -#endif /* SOGOMAPIFSFOLDER_H */ +#endif /* SOGOMAPIDBFOLDER_H */ diff --git a/OpenChange/SOGoMAPIDBFolder.m b/OpenChange/SOGoMAPIDBFolder.m new file mode 100644 index 000000000..ddd6086a6 --- /dev/null +++ b/OpenChange/SOGoMAPIDBFolder.m @@ -0,0 +1,402 @@ +/* SOGoMAPIDBFolder.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import +// #import + +#import +#import +#import +#import "EOQualifier+MAPI.h" +#import "GCSSpecialQueries+OpenChange.h" +#import "SOGoMAPIDBMessage.h" + +#import "SOGoMAPIDBFolder.h" + +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include + +Class SOGoMAPIDBObjectK = Nil; + +@implementation SOGoMAPIDBFolder + ++ (void) initialize +{ + SOGoMAPIDBObjectK = [SOGoMAPIDBObject class]; +} + +- (id) init +{ + if ((self = [super init])) + { + pathPrefix = nil; + } + + return self; +} + +- (id) initWithName: (NSString *) name inContainer: (id) newContainer +{ + if ((self = [super initWithName: name inContainer: newContainer])) + { + objectType = MAPIDBObjectTypeFolder; + aclMessage = [SOGoMAPIDBObject objectWithName: @"permissions" + inContainer: self]; + [aclMessage setObjectType: MAPIDBObjectTypeInternal]; + [aclMessage retain]; + } + + return self; +} + +- (void) dealloc +{ + [aclMessage release]; + [pathPrefix release]; + [super dealloc]; +} + +- (BOOL) isFolderish +{ + return YES; +} + +- (void) setPathPrefix: (NSString *) newPathPrefix +{ + ASSIGN (pathPrefix, newPathPrefix); +} + +- (NSMutableString *) pathForChild: (NSString *) childName +{ + NSMutableString *path; + + path = [self path]; + [path appendFormat: @"/%@", childName]; + + return path; +} + +- (NSMutableString *) path +{ + NSMutableString *path; + + path = [super path]; + if (pathPrefix) + [path insertString: pathPrefix atIndex: 0]; + + return path; +} + +// - (SOGoMAPIDBMessage *) newMessage +// { +// NSString *newFilename; + +// newFilename = [NSString stringWithFormat: @"%@.plist", +// [SOGoObject globallyUniqueObjectId]]; + +// return [SOGoMAPIDBMessage objectWithName: filename inContainer: self]; +// } + +- (NSArray *) childKeysOfType: (MAPIDBObjectType) type + includeDeleted: (BOOL) includeDeleted + matchingQualifier: (EOQualifier *) qualifier + andSortOrderings: (NSArray *) sortOrderings +{ + NSMutableArray *childKeys; + NSMutableString *sql// , *qualifierClause + ; + NSString *childPathPrefix, *childPath, *childKey; + NSMutableArray *whereClause; + NSArray *records; + NSDictionary *record; + NSUInteger childPathPrefixLen, count, max; + SOGoMAPIDBObject *currentChild; + + /* query construction */ + sql = [NSMutableString stringWithCapacity: 256]; + [sql appendFormat: @"SELECT * FROM %@", [self tableName]]; + + whereClause = [NSMutableArray arrayWithCapacity: 2]; + childPathPrefix = [NSString stringWithFormat: @"%@/", [self path]]; + [whereClause addObject: [NSString stringWithFormat: @"c_path LIKE '%@%%'", + childPathPrefix]]; + [whereClause addObject: [NSString stringWithFormat: @"c_type = %d", type]]; + if (!includeDeleted) + [whereClause addObject: @"c_deleted = 0"]; + + [sql appendFormat: @" WHERE %@", + [whereClause componentsJoinedByString: @" AND "]]; + + /* results */ + records = [self performSQLQuery: sql]; + if (records) + { + max = [records count]; + childKeys = [NSMutableArray arrayWithCapacity: max]; + childPathPrefixLen = [childPathPrefix length]; + for (count = 0; count < max; count++) + { + record = [records objectAtIndex: count]; + childPath = [record objectForKey: @"c_path"]; + childKey = [childPath substringFromIndex: childPathPrefixLen]; + if ([childKey rangeOfString: @"/"].location == NSNotFound) + { + if (qualifier) + { + currentChild = [SOGoMAPIDBObject objectWithName: childKey + inContainer: self]; + [currentChild setupFromRecord: record]; + if ([qualifier evaluateSOGoMAPIDBObject: currentChild]) + [childKeys addObject: childKey]; + } + else + [childKeys addObject: childKey]; + } + } + } + else + childKeys = nil; + + return childKeys; +} + +- (NSArray *) toManyRelationshipKeys +{ + return [self childKeysOfType: MAPIDBObjectTypeFolder + includeDeleted: NO + matchingQualifier: nil + andSortOrderings: nil]; +} + +- (NSArray *) toOneRelationshipKeys +{ + return [self childKeysOfType: MAPIDBObjectTypeMessage + includeDeleted: NO + matchingQualifier: nil + andSortOrderings: nil]; +} + +// - (NSArray *) toOneRelationshipKeysMatchingQualifier: (EOQualifier *) qualifier +// andSortOrderings: (NSArray *) sortOrderings +// { +// NSArray *allKeys; +// NSMutableArray *keys; +// NSUInteger count, max; +// NSString *messageKey; +// SOGoMAPIDBMessage *message; + +// if (sortOrderings) +// [self warnWithFormat: @"sorting is not handled yet"]; + +// allKeys = [self toOneRelationshipKeys]; +// if (qualifier) +// { +// [self logWithFormat: @"%s: getting restricted FAI keys", __PRETTY_FUNCTION__]; +// max = [allKeys count]; +// keys = [NSMutableArray arrayWithCapacity: max]; +// for (count = 0; count < max; count++) +// { +// messageKey = [allKeys objectAtIndex: count]; +// message = [self lookupName: messageKey +// inContext: nil +// acquire: NO]; +// if ([qualifier evaluateMAPIVolatileMessage: message]) +// [keys addObject: messageKey]; +// } +// } +// else +// keys = (NSMutableArray *) allKeys; + +// return keys; +// } + +- (id) lookupName: (NSString *) childName + inContext: (WOContext *) woContext + acquire: (BOOL) acquire +{ + id object; + Class objectClass; + NSString *childPath; + NSDictionary *record; + + childPath = [self pathForChild: childName]; + record = [self lookupRecord: childPath newerThanVersion: -1]; + if (record) + { + if ([[record objectForKey: @"c_type"] intValue] == MAPIDBObjectTypeFolder) + objectClass = isa; + else + objectClass = SOGoMAPIDBObjectK; + + object = [objectClass objectWithName: childName + inContainer: self]; + [object setupFromRecord: record]; + } + else + object = nil; + + return object; +} + +- (id) lookupFolder: (NSString *) folderName + inContext: (WOContext *) woContext +{ + id object; + + object = [SOGoMAPIDBFolder objectWithName: folderName + inContainer: self]; + [object reloadIfNeeded]; + + return object; +} + +// - (id) _fileAttributeForKey: (NSString *) key +// { +// NSDictionary *attributes; + +// attributes = [[NSFileManager defaultManager] +// fileAttributesAtPath: directory +// traverseLink: NO]; + +// return [attributes objectForKey: key]; +// } + +// - (NSCalendarDate *) creationTime +// { +// return [self _fileAttributeForKey: NSFileCreationDate]; +// } + +// - (NSCalendarDate *) lastModificationTime +// { +// return [self _fileAttributeForKey: NSFileModificationDate]; +// } + +- (NSException *) delete +{ + [self notImplemented: _cmd]; + + // NSFileManager *fm; + // NSException *error; + + // fm = [NSFileManager defaultManager]; + + // if (![fm removeFileAtPath: directory handler: NULL]) + // error = [NSException exceptionWithName: @"MAPIStoreIOException" + // reason: @"could not delete folder" + // userInfo: nil]; + // else + // error = nil; + + // return error; + return nil; +} + +/* acl */ +- (NSString *) defaultUserID +{ + return @"default"; +} + +- (NSMutableDictionary *) _aclEntries +{ + NSMutableDictionary *aclEntries; + + [aclMessage reloadIfNeeded]; + aclEntries = [aclMessage properties]; + if (![aclEntries objectForKey: @"users"]) + [aclEntries setObject: [NSMutableArray array] forKey: @"users"]; + if (![aclEntries objectForKey: @"entries"]) + [aclEntries setObject: [NSMutableDictionary dictionary] + forKey: @"entries"]; + + return aclEntries; +} + +- (void) addUserInAcls: (NSString *) user +{ + NSMutableDictionary *acl; + NSMutableArray *users; + + acl = [self _aclEntries]; + users = [acl objectForKey: @"users"]; + [users addObjectUniquely: user]; + [aclMessage save]; +} + +- (void) removeAclsForUsers: (NSArray *) oldUsers +{ + NSDictionary *acl; + NSMutableDictionary *entries; + NSMutableArray *users; + + acl = [self _aclEntries]; + entries = [acl objectForKey: @"entries"]; + [entries removeObjectsForKeys: oldUsers]; + users = [acl objectForKey: @"users"]; + [users removeObjectsInArray: oldUsers]; + [aclMessage save]; +} + +- (NSArray *) aclUsers +{ + return [[self _aclEntries] objectForKey: @"users"]; +} + +- (NSArray *) aclsForUser: (NSString *) uid +{ + NSDictionary *entries; + + entries = [[self _aclEntries] objectForKey: @"entries"]; + + return [entries objectForKey: uid]; +} + +- (void) setRoles: (NSArray *) roles + forUser: (NSString *) uid +{ + NSMutableDictionary *acl; + NSMutableDictionary *entries; + + acl = [self _aclEntries]; + entries = [acl objectForKey: @"entries"]; + [entries setObject: roles forKey: uid]; + [aclMessage save]; +} + +@end diff --git a/OpenChange/SOGoMAPIDBObject.h b/OpenChange/SOGoMAPIDBObject.h new file mode 100644 index 000000000..ea0a7a58a --- /dev/null +++ b/OpenChange/SOGoMAPIDBObject.h @@ -0,0 +1,83 @@ +/* SOGoMAPIDBObject.h - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef SOGOMAPIDBOBJECT_H +#define SOGOMAPIDBOBJECT_H + +#import "SOGoMAPIObject.h" + +@class NSArray; +@class NSMutableDictionary; +@class NSMutableString; +@class NSString; +@class NSURL; + +@class EOAdaptor; + +typedef enum { + MAPIDBObjectTypeFolder = 1, + MAPIDBObjectTypeMessage = 2, + MAPIDBObjectTypeFAI = 3, + MAPIDBObjectTypeInternal = 99 /* object = property list */ +} MAPIDBObjectType; + +@interface SOGoMAPIDBObject : SOGoMAPIObject +{ + NSURL *tableUrl; + + BOOL initialized; /* safe guard */ + MAPIDBObjectType objectType; + NSInteger version; + BOOL deleted; +} + +/* actions */ +- (void) setupFromRecord: (NSDictionary *) record; + +- (void) reloadIfNeeded; +- (void) save; + +/* accessors */ +- (NSMutableString *) path; /* full filename */ + +- (void) setTableUrl: (NSURL *) newTableUrl; +- (NSURL *) tableUrl; +- (NSString *) tableName; + +- (NSArray *) performSQLQuery: (NSString *) sql; +- (NSDictionary *) lookupRecord: (NSString *) path + newerThanVersion: (NSInteger) startVersion; + +- (void) setObjectType: (MAPIDBObjectType) newObjectType; +- (MAPIDBObjectType) objectType; /* message, fai, folder */ + +/* automatically set from actions */ +- (BOOL) deleted; + +/* db helpers */ +- (EOAdaptor *) tableChannelAdaptor; +- (NSArray *) performSQLQuery: (NSString *) sql; + + +@end + +#endif /* SOGOMAPIDBOBJECT_H */ diff --git a/OpenChange/SOGoMAPIDBObject.m b/OpenChange/SOGoMAPIDBObject.m new file mode 100644 index 000000000..b80af8fc5 --- /dev/null +++ b/OpenChange/SOGoMAPIDBObject.m @@ -0,0 +1,483 @@ +/* SOGoMAPIDBObject.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import "GCSSpecialQueries+OpenChange.h" +#import "MAPIStoreTypes.h" +#import "SOGoMAPIDBFolder.h" + +#import "SOGoMAPIDBObject.h" + +static EOAttribute *textColumn = nil; + +@implementation SOGoMAPIDBObject + ++ (void) initialize +{ + NSDictionary *description; + + if (!textColumn) + { + /* TODO: this is a hack for providing an EOAttribute definition that is + compatible with all the backends that we support. We should make use + of EOModel instead. */ + description = [NSDictionary dictionaryWithObjectsAndKeys: + @"c_textfield", @"columnName", + @"VARCHAR", @"externalType", + nil]; + textColumn = [EOAttribute attributeFromPropertyList: description]; + [textColumn retain]; + } +} + +/* + = (@"CREATE TABLE %@ (" + @" c_path VARCHAR(255) PRIMARY KEY," + @" c_type VARCHAR(20) NOT NULL," + @" c_creationdate INT4 NOT NULL," + @" c_lastmodified INT4 NOT NULL," + @" c_version INT4 NOT NULL DEFAULT 0," + @" c_deleted SMALLINT NOT NULL DEFAULT 0," +*/ + +/* indexes: + c_path (primary key) + c_counter + c_path, c_type + c_path, c_creationdate */ + +- (id) init +{ + if ((self = [super init])) + { + tableUrl = nil; + initialized = NO; + objectType = -1; + deleted = NO; + version = 0; + } + + return self; +} + +- (void) dealloc +{ + [tableUrl release]; + [super dealloc]; +} + +- (void) setTableUrl: (NSURL *) newTableUrl +{ + ASSIGN (tableUrl, newTableUrl); +} + +- (NSURL *) tableUrl +{ + if (!tableUrl) + { + tableUrl = [container tableUrl]; + [tableUrl retain]; + if (!tableUrl) + [NSException raise: @"MAPIStoreIOException" + format: @"table url is not set for object '%@'", self]; + } + + return tableUrl; +} + +- (NSString *) tableName +{ + NSArray *parts; + + [self tableUrl]; + parts = [[tableUrl path] componentsSeparatedByString: @"/"]; + + return [parts lastObject]; +} + +- (void) setupFromRecord: (NSDictionary *) record +{ + NSInteger intValue; + NSString *propsValue, *error; + NSDictionary *newValues; + NSPropertyListFormat format; + + objectType = [[record objectForKey: @"c_type"] intValue]; + intValue = [[record objectForKey: @"c_creationdate"] intValue]; + ASSIGN (creationDate, + [NSCalendarDate + dateWithTimeIntervalSince1970: (NSTimeInterval) intValue]); + intValue = [[record objectForKey: @"c_lastmodified"] intValue]; + ASSIGN (lastModified, + [NSCalendarDate + dateWithTimeIntervalSince1970: (NSTimeInterval) intValue]); + deleted = ([[record objectForKey: @"c_deleted"] intValue] > 0); + version = [[record objectForKey: @"c_version"] intValue]; + propsValue = [record objectForKey: @"c_content"]; + if ([propsValue isNotNull]) + { + newValues = [NSPropertyListSerialization propertyListFromData: [propsValue dataByDecodingBase64] + mutabilityOption: NSPropertyListMutableContainers + format: &format + errorDescription: &error]; + [properties addEntriesFromDictionary: newValues]; + // [properties addEntriesFromDictionary: [propsValue + // objectFromJSONString]]; + } + else + [properties removeAllObjects]; + + initialized = YES; +} + +/* accessors */ +- (NSMutableString *) path +{ + NSMutableString *path; + + if (container) + path = [container pathForChild: nameInContainer]; + else + path = [NSMutableString stringWithFormat: @"/%@", nameInContainer]; + + if ([path rangeOfString: @"//"].location != NSNotFound) + [NSException raise: @"MAPIStoreIOException" + format: @"object path has not been properly set for" + " folder '%@' (%@)", + self, path]; + + return path; +} + +- (void) setObjectType: (MAPIDBObjectType) newObjectType +{ + objectType = newObjectType; +} + +- (MAPIDBObjectType) objectType /* message, fai, folder */ +{ + return objectType; +} + +- (NSCalendarDate *) creationDate +{ + if (!initialized) + [NSException raise: @"MAPIStoreIOException" + format: @"record has not been initialized: %@", self]; + + return creationDate; +} + +- (NSCalendarDate *) lastModified +{ + if (!initialized) + [NSException raise: @"MAPIStoreIOException" + format: @"record has not been initialized: %@", self]; + + return lastModified; +} + +- (BOOL) deleted +{ + return deleted; +} + +- (Class) mapistoreMessageClass +{ + NSString *className, *mapiMsgClass; + + switch (objectType) + { + case MAPIDBObjectTypeMessage: + mapiMsgClass = [properties + objectForKey: MAPIPropertyKey (PidTagMessageClass)]; + if (mapiMsgClass) + { + if ([mapiMsgClass isEqualToString: @"IPM.StickyNote"]) + className = @"MAPIStoreNotesMessage"; + else + className = @"MAPIStoreDBMessage"; + [self logWithFormat: @"PidTagMessageClass = '%@', returning '%@'", + mapiMsgClass, className]; + } + else + { + [self warnWithFormat: @"PidTagMessageClass is not set, falling back" + @" to 'MAPIStoreDBMessage'"]; + className = @"MAPIStoreDBMessage"; + } + break; + case MAPIDBObjectTypeFAI: + className = @"MAPIStoreFAIMessage"; + break; + default: + [NSException raise: @"MAPIStoreIOException" + format: @"message class should not be queried for objects" + @" of type '%d'", objectType]; + } + + return NSClassFromString (className); +} + +/* actions */ +- (EOAdaptor *) tableChannelAdaptor +{ + GCSChannelManager *cm; + EOAdaptor *adaptor; + EOAdaptorChannel *channel; + + cm = [GCSChannelManager defaultChannelManager]; + channel = [cm acquireOpenChannelForURL: [self tableUrl]]; + adaptor = [[channel adaptorContext] adaptor]; + [cm releaseChannel: channel]; + + return adaptor; +} + +- (NSArray *) performSQLQuery: (NSString *) sql +{ + NSMutableArray *records; + GCSChannelManager *cm; + EOAdaptorChannel *channel; + NSException *error; + NSArray *attrs; + NSDictionary *record; + + cm = [GCSChannelManager defaultChannelManager]; + channel = [cm acquireOpenChannelForURL: [self tableUrl]]; + + error = [channel evaluateExpressionX: sql]; + if (error) + { + records = nil; + [self logWithFormat: + @"an exception occurred when executing query '%@'", + sql]; + [self logWithFormat: @"exception is '%@'", error]; + } + else + { + records = [NSMutableArray arrayWithCapacity: 256]; + attrs = [channel describeResults: NO]; + while ((record = [channel fetchAttributes: attrs withZone: NULL])) + [records addObject: record]; + } + [cm releaseChannel: channel]; + + return records; +} + +- (NSDictionary *) lookupRecord: (NSString *) path + newerThanVersion: (NSInteger) startVersion +{ + NSDictionary *record; + NSArray *records; + NSString *tableName, *pathValue; + NSMutableString *sql; + EOAdaptor *adaptor; + + if ([path hasSuffix: @"/"]) + [NSException raise: @"MAPIStoreIOException" + format: @"path ends with a slash: %@", path]; + + tableName = [self tableName]; + adaptor = [self tableChannelAdaptor]; + pathValue = [adaptor formatValue: path + forAttribute: textColumn]; + + /* query */ + sql = [NSMutableString stringWithFormat: + @"SELECT * FROM %@ WHERE c_path = %@", + tableName, pathValue]; + if (startVersion > -1) + [sql appendFormat: @" AND c_version > %d", startVersion]; + + /* execution */ + records = [self performSQLQuery: sql]; + if ([records count] > 0) + record = [records objectAtIndex: 0]; + else + record = nil; + + return record; +} + +- (void) reloadIfNeeded +{ + /* if object is uninitialized: reload without condition, otherwise, load if + c_version > :version */ + NSDictionary *record; + + if (initialized) + { + if (!isNew) + { + record = [self lookupRecord: [self path] + newerThanVersion: version]; + if (record) + [self setupFromRecord: record]; + } + } + else + { + record = [self lookupRecord: [self path] + newerThanVersion: -1]; + if (record) + { + [self setupFromRecord: record]; + isNew = NO; + } + else + isNew = YES; + initialized = YES; + } +} + +- (NSException *) delete +{ + deleted = YES; + [properties removeAllObjects]; + [self save]; + + return nil; +} + +- (void) save +{ + NSString *sql; + NSData *content; + NSCalendarDate *now; + GCSChannelManager *cm; + EOAdaptor *adaptor; + EOAdaptorChannel *channel; + NSInteger creationDateValue, lastModifiedValue, deletedValue; + NSString *tableName, *pathValue, *propsValue; + NSException *result; + + if (!initialized) + [NSException raise: @"MAPIStoreIOException" + format: @"record has not been initialized: %@", self]; + + cm = [GCSChannelManager defaultChannelManager]; + + channel = [cm acquireOpenChannelForURL: [self tableUrl]]; + + tableName = [self tableName]; + + now = [NSCalendarDate date]; + ASSIGN (lastModified, now); + + /* +- (NSException *)insertRowX:(NSDictionary *)_row forEntity:(EOEntity *)_entity; +- (NSException *)updateRowX:(NSDictionary*)aRow + describedByQualifier:(EOSQLQualifier*)aQualifier; + */ + + adaptor = [[channel adaptorContext] adaptor]; + pathValue = [adaptor formatValue: [self path] + forAttribute: textColumn]; + + lastModifiedValue = (NSInteger) [lastModified timeIntervalSince1970]; + + if (objectType == -1) + [NSException raise: @"MAPIStoreIOException" + format: @"object type has not been set for object '%@'", + self]; + + if ([properties count] > 0) + { + content = [NSPropertyListSerialization + dataFromPropertyList: properties + format: NSPropertyListBinaryFormat_v1_0 + errorDescription: NULL]; + propsValue = [adaptor formatValue: [content stringByEncodingBase64] + forAttribute: textColumn]; + } + else + propsValue = @"NULL"; + + if (isNew) + { + ASSIGN (creationDate, now); + creationDateValue = (NSInteger) [creationDate timeIntervalSince1970]; + sql = [NSString stringWithFormat: + (@"INSERT INTO %@" + @" (c_path, c_type, c_creationdate, c_lastmodified," + @" c_deleted, c_version, c_content)" + @" VALUES (%@, %d, %d, %d, 0, 0, %@" + @")"), + tableName, + pathValue, objectType, + creationDateValue, lastModifiedValue, + propsValue]; + isNew = NO; + } + else + { + version++; + deletedValue = (deleted ? 1 : 0); + sql = [NSString stringWithFormat: + (@"UPDATE %@" + @" SET c_lastmodified = %d, c_deleted = %d," + @" c_version = %d, c_content = %@" + @" WHERE c_path = %@"), + tableName, + lastModifiedValue, deletedValue, version, propsValue, + pathValue]; + } + + result = [channel evaluateExpressionX: sql]; + if (result) + [self errorWithFormat: @"could not insert/update record for record %@" + @" in %@: %@", pathValue, tableName, result]; + // @" c_path VARCHAR(255) PRIMARY KEY," + // @" c_type SMALLINT NOT NULL," + // @" c_creationdate INT4 NOT NULL," + // @" c_lastmodified INT4 NOT NULL," + // @" c_deleted SMALLINT NOT NULL DEFAULT 0," + // @" c_content BLOB"); + + [cm releaseChannel: channel]; +} + +@end diff --git a/OpenChange/SOGoMAPIFSFolder.m b/OpenChange/SOGoMAPIFSFolder.m deleted file mode 100644 index b26e0ea9d..000000000 --- a/OpenChange/SOGoMAPIFSFolder.m +++ /dev/null @@ -1,439 +0,0 @@ -/* SOGoMAPIFSFolder.m - this file is part of SOGo - * - * Copyright (C) 2010 Inverse inc. - * - * Author: Wolfgang Sourdeau - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#import -#import -#import -#import -#import -#import -#import -#import -#import - -#import -#import - -#import "EOQualifier+MAPI.h" -#import "SOGoMAPIFSMessage.h" - -#import "SOGoMAPIFSFolder.h" - -#undef DEBUG -#include -#include -#include -#include -#include -#include -#include - -static NSString *privateDir = nil; - -@implementation SOGoMAPIFSFolder - -+ (void) initialize -{ - struct loadparm_context *lpCtx; - const char *cPrivateDir; - - if (!privateDir) - { - lpCtx = loadparm_init_global (true); - cPrivateDir = lpcfg_private_dir (lpCtx); - privateDir = [NSString stringWithUTF8String: cPrivateDir]; - [privateDir retain]; - } -} - -+ (id) folderWithURL: (NSURL *) url - andTableType: (uint8_t) tableType -{ - SOGoMAPIFSFolder *newFolder; - - newFolder = [[self alloc] initWithURL: url - andTableType: tableType]; - [newFolder autorelease]; - - return newFolder; -} - -- (id) init -{ - if ((self = [super init])) - { - directory = nil; - directoryIsSane = NO; - } - - return self; -} - -- (void) dealloc -{ - [directory release]; - [super dealloc]; -} - -- (id) initWithURL: (NSURL *) url - andTableType: (uint8_t) tableType -{ - NSString *path, *username, *tableParticle; - - if ((self = [self init])) - { - if (tableType == MAPISTORE_MESSAGE_TABLE) - tableParticle = @"message"; - else if (tableType == MAPISTORE_FAI_TABLE) - tableParticle = @"fai"; - else if (tableType == MAPISTORE_FOLDER_TABLE) - tableParticle = @"folder"; - else - { - [NSException raise: @"MAPIStoreIOException" - format: @"unsupported table type: %d", tableType]; - tableParticle = nil; - } - - path = [url path]; - if (![path hasSuffix: @"/"]) - path = [NSString stringWithFormat: @"%@/", path]; - username = [url user]; - directory = [NSString stringWithFormat: @"%@/mapistore/SOGo/%@/%@/%@%@", - privateDir, username, tableParticle, - [url host], path]; - [self setOwner: username]; - [self logWithFormat: @"directory: %@", directory]; - [directory retain]; - ASSIGN (nameInContainer, [path stringByDeletingLastPathComponent]); - } - - return self; -} - -- (id) initWithName: (NSString *) newName - inContainer: (id) newContainer -{ - if ((self = [super initWithName: newName inContainer: newContainer])) - { - directory = [[newContainer directory] - stringByAppendingPathComponent: newName]; - [directory retain]; - } - - return self; -} - -- (NSString *) directory -{ - return directory; -} - -- (SOGoMAPIFSMessage *) newMessage -{ - NSString *filename; - - filename = [NSString stringWithFormat: @"%@.plist", - [SOGoObject globallyUniqueObjectId]]; - - return [SOGoMAPIFSMessage objectWithName: filename inContainer: self]; -} - -- (void) ensureDirectory -{ - NSFileManager *fm; - NSDictionary *attributes; - BOOL isDir; - - if (!directory) - [NSException raise: @"MAPIStoreIOException" - format: @"directory is nil"]; - - fm = [NSFileManager defaultManager]; - if ([fm fileExistsAtPath: directory isDirectory: &isDir]) - { - if (!isDir) - [NSException raise: @"MAPIStoreIOException" - format: @"object at path '%@' is not a directory", - directory]; - } - else - { - attributes - = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: 0700] - forKey: NSFilePosixPermissions]; - [fm createDirectoryAtPath: directory - attributes: attributes]; - } - - directoryIsSane = YES; -} - -- (NSArray *) _objectsInDirectory: (BOOL) dirs -{ - NSFileManager *fm; - NSArray *contents; - NSMutableArray *files; - NSUInteger count, max; - NSString *file, *fullName; - BOOL isDir; - - if (!directoryIsSane) - [self ensureDirectory]; - - fm = [NSFileManager defaultManager]; - contents = [fm directoryContentsAtPath: directory]; - max = [contents count]; - files = [NSMutableArray arrayWithCapacity: max]; - for (count = 0; count < max; count++) - { - file = [contents objectAtIndex: count]; - if (![file isEqualToString: @"permissions.plist"]) - { - fullName = [directory stringByAppendingPathComponent: file]; - if ([fm fileExistsAtPath: fullName - isDirectory: &isDir] - && dirs == isDir) - [files addObject: file]; - } - } - - return files; -} - -- (NSArray *) toManyRelationshipKeys -{ - return [self _objectsInDirectory: YES]; -} - -- (NSArray *) toOneRelationshipKeys -{ - return [self _objectsInDirectory: NO]; -} - -- (NSArray *) toOneRelationshipKeysMatchingQualifier: (EOQualifier *) qualifier - andSortOrderings: (NSArray *) sortOrderings -{ - NSArray *allKeys; - NSMutableArray *keys; - NSUInteger count, max; - NSString *messageKey; - SOGoMAPIFSMessage *message; - - if (sortOrderings) - [self warnWithFormat: @"sorting is not handled yet"]; - - allKeys = [self toOneRelationshipKeys]; - if (qualifier) - { - [self logWithFormat: @"%s: getting restricted FAI keys", __PRETTY_FUNCTION__]; - max = [allKeys count]; - keys = [NSMutableArray arrayWithCapacity: max]; - for (count = 0; count < max; count++) - { - messageKey = [allKeys objectAtIndex: count]; - message = [self lookupName: messageKey - inContext: nil - acquire: NO]; - if ([qualifier evaluateMAPIVolatileMessage: message]) - [keys addObject: messageKey]; - } - } - else - keys = (NSMutableArray *) allKeys; - - return keys; -} - -- (id) lookupName: (NSString *) fileName - inContext: (WOContext *) woContext - acquire: (BOOL) acquire -{ - NSFileManager *fm; - NSString *fullName; - id object; - BOOL isDir; - - if (!directoryIsSane) - [self ensureDirectory]; - - fm = [NSFileManager defaultManager]; - fullName = [directory stringByAppendingPathComponent: fileName]; - if ([fm fileExistsAtPath: fullName - isDirectory: &isDir]) - { - if (isDir) - object = [isa objectWithName: fileName - inContainer: self]; - else - object = [SOGoMAPIFSMessage objectWithName: fileName - inContainer: self]; - } - else - object = nil; - - return object; -} - -- (id) _fileAttributeForKey: (NSString *) key -{ - NSDictionary *attributes; - - attributes = [[NSFileManager defaultManager] - fileAttributesAtPath: directory - traverseLink: NO]; - - return [attributes objectForKey: key]; -} - -- (NSCalendarDate *) creationTime -{ - return [self _fileAttributeForKey: NSFileCreationDate]; -} - -- (NSCalendarDate *) lastModificationTime -{ - return [self _fileAttributeForKey: NSFileModificationDate]; -} - -- (NSException *) delete -{ - NSFileManager *fm; - NSException *error; - - fm = [NSFileManager defaultManager]; - - if (![fm removeFileAtPath: directory handler: NULL]) - error = [NSException exceptionWithName: @"MAPIStoreIOException" - reason: @"could not delete folder" - userInfo: nil]; - else - error = nil; - - return error; -} - -/* acl */ -- (NSString *) defaultUserID -{ - return @"default"; -} - -- (NSMutableDictionary *) _aclEntries -{ - NSMutableDictionary *aclEntries; - NSData *content; - NSString *error, *filename; - NSPropertyListFormat format; - - filename = [directory stringByAppendingPathComponent: @"permissions.plist"]; - content = [NSData dataWithContentsOfFile: filename]; - if (content) - aclEntries = [NSPropertyListSerialization propertyListFromData: content - mutabilityOption: NSPropertyListMutableContainers - format: &format - errorDescription: &error]; - else - aclEntries = nil; - if (!aclEntries) - { - aclEntries = [NSMutableDictionary dictionary]; - [aclEntries setObject: [NSMutableArray array] forKey: @"users"]; - [aclEntries setObject: [NSMutableDictionary dictionary] - forKey: @"entries"]; - } - - return aclEntries; -} - -- (void) _saveAcl: (NSDictionary *) acl -{ - NSString *filename; - NSData *content; - - filename = [directory stringByAppendingPathComponent: @"permissions.plist"]; - [self ensureDirectory]; - - if (acl) - content = [NSPropertyListSerialization - dataFromPropertyList: acl - format: NSPropertyListBinaryFormat_v1_0 - errorDescription: NULL]; - else - content = [NSData data]; - if (![content writeToFile: filename atomically: NO]) - [NSException raise: @"MAPIStoreIOException" - format: @"could not save acl"]; -} - -- (void) addUserInAcls: (NSString *) user -{ - NSMutableDictionary *acl; - NSMutableArray *users; - - acl = [self _aclEntries]; - users = [acl objectForKey: @"users"]; - [users addObjectUniquely: user]; - [self _saveAcl: acl]; -} - -- (void) removeAclsForUsers: (NSArray *) oldUsers -{ - NSDictionary *acl; - NSMutableDictionary *entries; - NSMutableArray *users; - - acl = [self _aclEntries]; - entries = [acl objectForKey: @"entries"]; - [entries removeObjectsForKeys: oldUsers]; - users = [acl objectForKey: @"users"]; - [users removeObjectsInArray: oldUsers]; - [self _saveAcl: acl]; -} - -- (NSArray *) aclUsers -{ - return [[self _aclEntries] objectForKey: @"users"]; -} - -- (NSArray *) aclsForUser: (NSString *) uid -{ - NSDictionary *entries; - - entries = [[self _aclEntries] objectForKey: @"entries"]; - - return [entries objectForKey: uid]; -} - -- (void) setRoles: (NSArray *) roles - forUser: (NSString *) uid -{ - NSMutableDictionary *acl; - NSMutableDictionary *entries; - - acl = [self _aclEntries]; - entries = [acl objectForKey: @"entries"]; - [entries setObject: roles forKey: uid]; - [self _saveAcl: acl]; -} - -@end diff --git a/OpenChange/SOGoMAPIFSMessage.h b/OpenChange/SOGoMAPIFSMessage.h deleted file mode 100644 index ec6494938..000000000 --- a/OpenChange/SOGoMAPIFSMessage.h +++ /dev/null @@ -1,47 +0,0 @@ -/* SOGoMAPIFSMessage.h - this file is part of SOGo - * - * Copyright (C) 2010 Inverse inc. - * - * Author: Wolfgang Sourdeau - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef SOGOMAPIFSMESSAGE_H -#define SOGOMAPIFSMESSAGE_H - -#import "SOGoMAPIVolatileMessage.h" - -@class NSDate; -@class NSString; - -@interface SOGoMAPIFSMessage : SOGoMAPIVolatileMessage -{ - NSString *completeFilename; - NSUInteger inode; - NSData *lastModificationTime; -} - -- (void) save; - -- (NSString *) completeFilename; - -- (NSDate *) creationTime; -- (NSDate *) lastModificationTime; - -@end - -#endif /* SOGOMAPIFSMESSAGE_H */ diff --git a/OpenChange/SOGoMAPIFSMessage.m b/OpenChange/SOGoMAPIFSMessage.m deleted file mode 100644 index 8a854fa1d..000000000 --- a/OpenChange/SOGoMAPIFSMessage.m +++ /dev/null @@ -1,238 +0,0 @@ -/* SOGoMAPIFSMessage.m - this file is part of SOGo - * - * Copyright (C) 2010 Inverse inc. - * - * Author: Wolfgang Sourdeau - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#import -#import -#import -#import -#import -#import -#import - -#import - -#import "SOGoMAPIFSFolder.h" - -#import "SOGoMAPIFSMessage.h" - -@implementation SOGoMAPIFSMessage - -- (id) init -{ - if ((self = [super init])) - { - completeFilename = nil; - inode = 0; - lastModificationTime = nil; - } - - return self; -} - -- (void) dealloc -{ - [completeFilename release]; - [super dealloc]; -} - -- (Class) mapistoreMessageClass -{ - NSArray *dirMembers; - NSString *className; - - /* FIXME: this method is a bit dirty */ - dirMembers = [[container directory] componentsSeparatedByString: @"/"]; - if ([dirMembers containsObject: @"fai"]) /* should not occur as FAI message - are instantiated directly in - MAPIStoreFolder */ - className = @"MAPIStoreFAIMessage"; - else if ([dirMembers containsObject: @"notes"]) - className = @"MAPIStoreNotesMessage"; - else - className = @"MAPIStoreFSMessage"; - - return NSClassFromString (className); -} - -- (NSString *) completeFilename -{ - if (!completeFilename) - { - completeFilename = [[container directory] - stringByAppendingPathComponent: nameInContainer]; - [completeFilename retain]; - } - - return completeFilename; -} - -- (BOOL) _readFileChangesDataWithDate: (NSDate **) newLMTime - andInode: (NSUInteger *) newInode -{ - BOOL rc; - NSDictionary *attributes; - - attributes = [[NSFileManager defaultManager] - fileAttributesAtPath: [self completeFilename] - traverseLink: NO]; - if (attributes) - { - *newLMTime = [attributes fileModificationDate]; - *newInode = [attributes fileSystemFileNumber]; - rc = YES; - } - else - rc = NO; - - return rc; -} - -- (BOOL) _checkFileChangesDataWithDate: (NSDate **) newLMTime - andInode: (NSUInteger *) newInode -{ - BOOL hasChanged = NO; - NSDate *lastLMTime; - NSUInteger lastInode; - - if ([self _readFileChangesDataWithDate: &lastLMTime - andInode: &lastInode]) - { - if (inode != lastInode - || ![lastModificationTime isEqual: lastLMTime]) - { - if (lastLMTime) - *newLMTime = lastLMTime; - if (newInode) - *newInode = lastInode; - hasChanged = YES; - } - } - - return hasChanged; -} - -- (NSMutableDictionary *) properties -{ - NSData *content; - NSString *error; - NSPropertyListFormat format; - NSDate *lastLMTime; - NSUInteger lastInode; - - if ([self _checkFileChangesDataWithDate: &lastLMTime - andInode: &lastInode]) - { - [self logWithFormat: @"file '%@' new or modified: rereading properties", - [self completeFilename]]; - [properties release]; - properties = nil; - content = [NSData dataWithContentsOfFile: [self completeFilename]]; - if (content) - { - properties = [NSPropertyListSerialization propertyListFromData: content - mutabilityOption: NSPropertyListMutableContainers - format: &format - errorDescription: &error]; - [properties retain]; - if (!properties) - [self logWithFormat: @"an error occurred during deserialization" - @" of message: '%@'", error]; - } - ASSIGN (lastModificationTime, lastLMTime); - inode = lastInode; - } - - return [super properties]; -} - -- (void) save -{ - NSData *content; - NSDate *lastLMTime; - NSUInteger lastInode; - - [container ensureDirectory]; - - // [self logWithFormat: @"%d props in whole dict", [properties count]]; - - content = [NSPropertyListSerialization - dataFromPropertyList: [self properties] - format: NSPropertyListBinaryFormat_v1_0 - errorDescription: NULL]; - if (![content writeToFile: [self completeFilename] atomically: YES]) - [NSException raise: @"MAPIStoreIOException" - format: @"could not save message"]; - - [self _readFileChangesDataWithDate: &lastLMTime andInode: &lastInode]; - ASSIGN (lastModificationTime, lastLMTime); - inode = lastInode; - // [self logWithFormat: @"fs message written to '%@'", [self completeFilename]]; -} - -- (NSString *) davEntityTag -{ - NSDate *lm; - - lm = [self lastModificationTime]; - - return [NSString stringWithFormat: @"%d", (int) [lm timeIntervalSince1970]]; -} - -- (NSException *) delete -{ - NSFileManager *fm; - NSException *error; - - fm = [NSFileManager defaultManager]; - - if (![fm removeFileAtPath: [self completeFilename] handler: NULL]) - error = [NSException exceptionWithName: @"MAPIStoreIOException" - reason: @"could not delete message" - userInfo: nil]; - else - error = nil; - - return error; -} - -- (id) _fileAttributeForKey: (NSString *) key -{ - NSDictionary *attributes; - - attributes = [[NSFileManager defaultManager] - fileAttributesAtPath: [self completeFilename] - traverseLink: NO]; - - return [attributes objectForKey: key]; -} - -- (NSDate *) creationTime -{ - return [self _fileAttributeForKey: NSFileCreationDate]; -} - -- (NSDate *) lastModificationTime -{ - return [self _fileAttributeForKey: NSFileModificationDate]; -} - -@end diff --git a/OpenChange/SOGoMAPIVolatileMessage.h b/OpenChange/SOGoMAPIObject.h similarity index 63% rename from OpenChange/SOGoMAPIVolatileMessage.h rename to OpenChange/SOGoMAPIObject.h index 00596fef6..fbebaf641 100644 --- a/OpenChange/SOGoMAPIVolatileMessage.h +++ b/OpenChange/SOGoMAPIObject.h @@ -1,12 +1,12 @@ -/* SOGoMAPIVolatileMessage.h - this file is part of SOGo +/* SOGoMAPIObject.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) + * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This file is distributed in the hope that it will be useful, @@ -20,22 +20,30 @@ * Boston, MA 02111-1307, USA. */ -#ifndef SOGOMAPIVOLATILEMESSAGE_H -#define SOGOMAPIVOLATILEMESSAGE_H +#ifndef SOGOMAPIOBJECT_H +#define SOGOMAPIOBJECT_H #import -@class NSDictionary; @class NSMutableDictionary; -@interface SOGoMAPIVolatileMessage : SOGoObject +@interface SOGoMAPIObject : SOGoObject { + BOOL isNew; NSMutableDictionary *properties; + NSCalendarDate *creationDate; + NSCalendarDate *lastModified; } +- (void) setIsNew: (BOOL) newIsNew; +- (BOOL) isNew; + +- (void) adjustLastModified; + - (NSMutableDictionary *) properties; -- (void) appendProperties: (NSDictionary *) newProperties; +- (NSCalendarDate *) creationDate; +- (NSCalendarDate *) lastModified; @end -#endif /* SOGOMAPIVOLATILEMESSAGE_H */ +#endif /* SOGOMAPIOBJECT_H */ diff --git a/OpenChange/SOGoMAPIVolatileMessage.m b/OpenChange/SOGoMAPIObject.m similarity index 58% rename from OpenChange/SOGoMAPIVolatileMessage.m rename to OpenChange/SOGoMAPIObject.m index b46a81c61..ec8a9ae52 100644 --- a/OpenChange/SOGoMAPIVolatileMessage.m +++ b/OpenChange/SOGoMAPIObject.m @@ -1,6 +1,6 @@ -/* SOGoMAPIVolatileMessage.m - this file is part of SOGo +/* SOGoMAPIObject.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -20,17 +20,19 @@ * Boston, MA 02111-1307, USA. */ -#import +#import "SOGoMAPIObject.h" -#import "SOGoMAPIVolatileMessage.h" - -@implementation SOGoMAPIVolatileMessage +@implementation SOGoMAPIObject - (id) init { if ((self = [super init])) { - properties = nil; + isNew = NO; + creationDate = [NSCalendarDate date]; + [creationDate retain]; + lastModified = [creationDate copy]; + properties = [NSMutableDictionary new]; } return self; @@ -38,21 +40,45 @@ - (void) dealloc { + [creationDate release]; + [lastModified release]; [properties release]; [super dealloc]; } +- (void) setIsNew: (BOOL) newIsNew +{ + isNew = newIsNew; +} + +- (BOOL) isNew +{ + return isNew; +} + +- (void) adjustLastModified +{ + ASSIGN (lastModified, [NSCalendarDate date]); +} + +- (BOOL) isFolderish +{ + return NO; +} + - (NSMutableDictionary *) properties { - if (!properties) - properties = [NSMutableDictionary new]; - return properties; } -- (void) appendProperties: (NSDictionary *) newProperties +- (NSCalendarDate *) creationDate { - [[self properties] addEntriesFromDictionary: newProperties]; + return creationDate; +} + +- (NSCalendarDate *) lastModified +{ + return lastModified; } @end diff --git a/OpenChange/plreader.m b/OpenChange/plreader.m index 68c7a81e5..b027a987c 100644 --- a/OpenChange/plreader.m +++ b/OpenChange/plreader.m @@ -23,164 +23,19 @@ /* A format-agnostic property list dumper. Usage: plreader [filename] */ -#import #import -#import -#import +#import #import -#import -#import -#import -#import -const char *indentationStep = " "; - -@interface NSObject (plext) - -- (void) displayWithIndentation: (NSInteger) anInt; - -@end - -@implementation NSObject (plext) - -- (void) _outputIndentation: (NSInteger) anInt -{ - NSInteger i; - - for (i = 0; i < anInt; i++) - printf ("%s", indentationStep); -} - -- (void) displayWithIndentation: (NSInteger) anInt -{ - printf ("(%s) %s", - [NSStringFromClass (isa) UTF8String], - [[self description] UTF8String]); -} - -@end - -@implementation NSDictionary (plext) - -- (void) displayKey: (NSString *) key - withIndentation: (NSInteger) anInt -{ - [self _outputIndentation: anInt]; - - printf ("%s ", [[key description] UTF8String]); - if ([key isKindOfClass: [NSValue class]]) - printf ("(%s: 0x%.8x) ", [(NSValue *) key objCType], [key intValue]); - - printf ("= "); -} - -- (void) displayWithIndentation: (NSInteger) anInt -{ - NSUInteger i, max; - NSArray *keys; - NSInteger subIndent; - NSString *key; - - keys = [self allKeys]; - max = [keys count]; - - printf ("{ (%ld) items\n", (long) max); - - subIndent = anInt + 1; - - for (i = 0; i < max; i++) - { - key = [keys objectAtIndex: i]; - [self displayKey: key withIndentation: subIndent]; - [[self objectForKey: key] displayWithIndentation: subIndent]; - if (i < (max - 1)) - printf (","); - printf ("\n"); - } - - [self _outputIndentation: anInt]; - printf ("}"); -} - -@end - -@implementation NSArray (plext) - -- (void) displayCount: (NSUInteger) count - withIndentation: (NSInteger) anInt -{ - [self _outputIndentation: anInt]; - printf ("%lu = ", (unsigned long) count); -} - -- (void) displayWithIndentation: (NSInteger) anInt -{ - NSUInteger i, max; - NSInteger subIndent; - - max = [self count]; - - printf ("[ (%ld) items\n", (long) max); - - subIndent = anInt + 1; - - for (i = 0; i < max; i++) - { - [self displayCount: i withIndentation: subIndent]; - [[self objectAtIndex: i] displayWithIndentation: subIndent]; - if (i < (max - 1)) - printf (","); - printf ("\n"); - } - - [self _outputIndentation: anInt]; - printf ("]"); -} - -@end +#import "NSObject+PropertyList.m" static void PLReaderDumpPListFile (NSString *filename) { NSData *content; - NSDictionary *d; - NSPropertyListFormat format; - NSString *error = nil; - const char *formatName; content = [NSData dataWithContentsOfFile: filename]; - d = [NSPropertyListSerialization propertyListFromData: content - mutabilityOption: NSPropertyListImmutable - format: &format - errorDescription: &error]; - if (d) - { - switch (format) - { - case NSPropertyListOpenStepFormat: - formatName = "OpenStep"; - break; - case NSPropertyListXMLFormat_v1_0: - formatName = "XML"; - break; - case NSPropertyListBinaryFormat_v1_0: - formatName = "Binary"; - break; - case NSPropertyListGNUstepFormat: - formatName = "GNUstep"; - break; - case NSPropertyListGNUstepBinaryFormat: - formatName = "GNUstep binary"; - break; - default: formatName = "unknown"; - } - - printf ("File format is: %s\n", formatName); - [d displayWithIndentation: 0]; - printf ("\n"); - } - else - printf ("an error occurred: %s\n", [error UTF8String]); + OCDumpPListData (content); } int main() From a783d81528b67a1dcbdc2f19ed065684308b7a6d Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 29 Jun 2012 19:09:02 +0000 Subject: [PATCH 008/127] Monotone-Parent: 905276f295d6f28a6946297f6a7af9ad60f71842 Monotone-Revision: 4ecb95aab8f686702ff3eb186a97b1bf1f3b5531 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-06-29T19:09:02 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/MAPIStoreAttachment.h | 1 + OpenChange/MAPIStoreAttachment.m | 23 ++++++++++++++--------- OpenChange/MAPIStoreSOGo.m | 6 +++--- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index a2d6e0ffe..440ab3de1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-06-29 Wolfgang Sourdeau + * OpenChange/MAPIStoreSOGo.m + (sogo_message_attachment_open_embedded_message): added the "mode" + parameter. + * OpenChange/SOGoMAPIDBObject.m: new class module that replaced SOGoMAPIFSMessage. diff --git a/OpenChange/MAPIStoreAttachment.h b/OpenChange/MAPIStoreAttachment.h index f9716f7e7..1d4576572 100644 --- a/OpenChange/MAPIStoreAttachment.h +++ b/OpenChange/MAPIStoreAttachment.h @@ -37,6 +37,7 @@ - (uint32_t) AID; - (int) openEmbeddedMessage: (MAPIStoreEmbeddedMessage **) messagePtr + inMode: (enum OpenEmbeddedMessage_OpenModeFlags) mode withMID: (uint64_t *) mid withMAPIStoreMsg: (struct mapistore_message **) mapistoreMsgPtr inMemCtx: (TALLOC_CTX *) memCtx; diff --git a/OpenChange/MAPIStoreAttachment.m b/OpenChange/MAPIStoreAttachment.m index 59c8832df..86944436b 100644 --- a/OpenChange/MAPIStoreAttachment.m +++ b/OpenChange/MAPIStoreAttachment.m @@ -91,6 +91,7 @@ } - (int) openEmbeddedMessage: (MAPIStoreEmbeddedMessage **) messagePtr + inMode: (enum OpenEmbeddedMessage_OpenModeFlags) mode withMID: (uint64_t *) mid withMAPIStoreMsg: (struct mapistore_message **) mapistoreMsgPtr inMemCtx: (TALLOC_CTX *) memCtx @@ -103,19 +104,23 @@ mapping = [self mapping]; - attMessage = [self openEmbeddedMessage]; - if (attMessage) + if (mode == MAPI_CREATE) + attMessage = [self createEmbeddedMessage]; + else { - *mid = [mapping idFromURL: [attMessage url]]; - *messagePtr = attMessage; - *mapistoreMsgPtr = mapistoreMsg; + // if (attMessage) + // [mapping registerURL: [attMessage url] + // withID: *mid]; + attMessage = [self openEmbeddedMessage]; + if (attMessage) + { + *mid = [mapping idFromURL: [attMessage url]]; + *messagePtr = attMessage; + *mapistoreMsgPtr = mapistoreMsg; + } } // else if (flags == MAPI_CREATE) // { - // attMessage = [self createEmbeddedMessage]; - // if (attMessage) - // [mapping registerURL: [attMessage url] - // withID: *mid]; // } return (attMessage ? MAPISTORE_SUCCESS : MAPISTORE_ERROR); diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 1a5fc64d0..0a474aba7 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -963,9 +963,8 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags) static enum mapistore_error sogo_message_attachment_open_embedded_message -(void *attachment_object, - TALLOC_CTX *mem_ctx, void **message_object, - uint64_t *midP, +(void *attachment_object, enum OpenEmbeddedMessage_OpenModeFlags mode, + TALLOC_CTX *mem_ctx, void **message_object, uint64_t *midP, struct mapistore_message **msg) { struct MAPIStoreTallocWrapper *wrapper; @@ -983,6 +982,7 @@ sogo_message_attachment_open_embedded_message GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [attachment openEmbeddedMessage: &message + inMode: mode withMID: midP withMAPIStoreMsg: msg inMemCtx: mem_ctx]; From 3c6ed20f53cca33227007fd32b724f00a571cc5d Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 29 Jun 2012 19:25:31 +0000 Subject: [PATCH 009/127] Missing files Monotone-Parent: 0c4f43a27b60ff9951c52b8ab1d9309d5fc9f209 Monotone-Revision: 2eae9f47dfec8f0fc9908ebce5e7d249f21120bc Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-06-29T19:25:31 Monotone-Branch: ca.inverse.sogo --- OpenChange/SOGoMAPIDBMessage.h | 34 +++++++++++++++++++ OpenChange/SOGoMAPIDBMessage.m | 61 ++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 OpenChange/SOGoMAPIDBMessage.h create mode 100644 OpenChange/SOGoMAPIDBMessage.m diff --git a/OpenChange/SOGoMAPIDBMessage.h b/OpenChange/SOGoMAPIDBMessage.h new file mode 100644 index 000000000..29909a60a --- /dev/null +++ b/OpenChange/SOGoMAPIDBMessage.h @@ -0,0 +1,34 @@ +/* SOGoMAPIDBMessage.h - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef SOGOMAPIDBMESSAGE_H +#define SOGOMAPIDBMESSAGE_H + +#import "SOGoMAPIDBObject.h" + +@class NSDate; +@class NSString; + +@interface SOGoMAPIDBMessage : SOGoMAPIDBObject +@end + +#endif /* SOGOMAPIDBMESSAGE_H */ diff --git a/OpenChange/SOGoMAPIDBMessage.m b/OpenChange/SOGoMAPIDBMessage.m new file mode 100644 index 000000000..f17093be1 --- /dev/null +++ b/OpenChange/SOGoMAPIDBMessage.m @@ -0,0 +1,61 @@ +/* SOGoMAPIDBMessage.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import +#import +#import +#import +#import +#import + +#import + +#import "SOGoMAPIDBFolder.h" + +#import "SOGoMAPIDBMessage.h" + +@implementation SOGoMAPIDBMessage + +- (Class) mapistoreMessageClass +{ + // NSArray *dirMembers; + NSString *className; + + [NSException raise: @"whereisthisusedexception" + format: @"this exception should be triggered only for tracing"]; + // /* FIXME: this method is a bit dirty */ + // dirMembers = [[container directory] componentsSeparatedByString: @"/"]; + // if ([dirMembers containsObject: @"fai"]) /* should not occur as FAI message + // are instantiated directly in + // MAPIStoreFolder */ + // className = @"MAPIStoreFAIMessage"; + // else if ([dirMembers containsObject: @"notes"]) + // className = @"MAPIStoreNotesMessage"; + // else + // className = @"MAPIStoreDBMessage"; + + className = @"nimportequoi"; + return NSClassFromString (className); +} + +@end From 6987cba3c251db3ca2456488e95652d2f93d84bd Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 29 Jun 2012 19:37:15 +0000 Subject: [PATCH 010/127] Missing files Monotone-Parent: 2eae9f47dfec8f0fc9908ebce5e7d249f21120bc Monotone-Revision: 53c7bfdc2c357c162e23401ab5600d2cb4a1483e Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-06-29T19:37:15 Monotone-Branch: ca.inverse.sogo --- OpenChange/dbmsgreader.m | 109 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 OpenChange/dbmsgreader.m diff --git a/OpenChange/dbmsgreader.m b/OpenChange/dbmsgreader.m new file mode 100644 index 000000000..b4b4332b3 --- /dev/null +++ b/OpenChange/dbmsgreader.m @@ -0,0 +1,109 @@ +/* dbmsgreader.m - this file is part of SOGo + * + * Copyright (C) 2011 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* A format-agnostic property list readerer. + Usage: dbmsgreader [username] [filename] */ + +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import "MAPIStoreUserContext.h" +#import "SOGoMAPIDBObject.h" + +#import "NSObject+PropertyList.m" + +Class MAPIStoreUserContextK, SOGoMAPIDBObjectK; + +static void +DbDumpObject (NSString *username, NSString *path) +{ + id ctx; + NSData *content; + id dbobject; + NSDictionary *record; + + ctx = [MAPIStoreUserContextK userContextWithUsername: username + andTDBIndexing: NULL]; + dbobject = [SOGoMAPIDBObjectK new]; + [dbobject setTableUrl: [ctx folderTableURL]]; + record = [dbobject lookupRecord: path newerThanVersion: -1]; + if (record) + { + content = [[record objectForKey: @"c_content"] dataByDecodingBase64]; + OCDumpPListData (content); + } + else + NSLog (@"record not found"); + + [dbobject release]; +} + +int main (int argc, char *argv[], char *envp[]) +{ + NSAutoreleasePool *pool; + SOGoProductLoader *loader; + NSUserDefaults *ud; + SoProductRegistry *registry; + NSArray *arguments; + + /* Here we work around a bug in GNUstep which decodes XML user + defaults using the system encoding rather than honouring + the encoding specified in the file. */ + putenv ("GNUSTEP_STRING_ENCODING=NSUTF8StringEncoding"); + + pool = [NSAutoreleasePool new]; + + [SOGoSystemDefaults sharedSystemDefaults]; + + /* We force the plugin to base its configuration on the SOGo tree. */ + ud = [NSUserDefaults standardUserDefaults]; + [ud registerDefaults: [ud persistentDomainForName: @"sogod"]]; + + [NSProcessInfo initializeWithArguments: argv + count: argc + environment: envp]; + + registry = [SoProductRegistry sharedProductRegistry]; + [registry scanForProductsInDirectory: SOGO_BUNDLES_DIR]; + + loader = [SOGoProductLoader productLoader]; + [loader loadProducts: [NSArray arrayWithObject: BACKEND_BUNDLE_NAME]]; + + MAPIStoreUserContextK = NSClassFromString (@"MAPIStoreUserContext"); + SOGoMAPIDBObjectK = NSClassFromString (@"SOGoMAPIDBObject"); + + arguments = [[NSProcessInfo processInfo] arguments]; + if ([arguments count] > 2) + DbDumpObject ([arguments objectAtIndex: 1], + [arguments objectAtIndex: 2]); + + [pool release]; + + return 0; +} From 13bad20737c7ac33a8092610555df01e093a392b Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Sat, 30 Jun 2012 07:30:44 +0000 Subject: [PATCH 011/127] Monotone-Parent: 53c7bfdc2c357c162e23401ab5600d2cb4a1483e Monotone-Revision: fc5a6818c0ee3f04b21668c4b2008a9549fb34f7 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-06-30T07:30:44 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 6 +++ OpenChange/MAPIStoreSOGo.m | 66 ++++++++++++++++----------------- OpenChange/NSObject+MAPIStore.h | 2 +- OpenChange/NSObject+MAPIStore.m | 4 +- 4 files changed, 42 insertions(+), 36 deletions(-) diff --git a/ChangeLog b/ChangeLog index 884a80698..089d771c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-06-30 Wolfgang Sourdeau + + * OpenChange/NSObject+MAPIStore.h: renamed + MAPIStoreTallocWrapper.MAPIStoreSOGoObject to .instance, to avoid + confusion in certain versions of GCC with our new class type. + 2012-06-29 Wolfgang Sourdeau * OpenChange/MAPIStoreSOGo.m diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 0a474aba7..d7ba5c387 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -273,7 +273,7 @@ sogo_context_get_path(void *backend_object, TALLOC_CTX *mem_ctx, if (backend_object) { wrapper = backend_object; - context = wrapper->MAPIStoreSOGoObject; + context = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [context getPath: path ofFMID: fmid inMemCtx: mem_ctx]; @@ -303,7 +303,7 @@ sogo_context_get_root_folder(void *backend_object, TALLOC_CTX *mem_ctx, if (backend_object) { wrapper = backend_object; - context = wrapper->MAPIStoreSOGoObject; + context = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [context getRootFolder: &folder withFID: fid]; @@ -342,7 +342,7 @@ sogo_folder_open_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder openFolder: &childFolder withFID: fid]; @@ -382,7 +382,7 @@ sogo_folder_create_folder(void *folder_object, TALLOC_CTX *mem_ctx, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder createFolder: &childFolder withRow: aRow andFID: fid]; @@ -421,7 +421,7 @@ sogo_folder_delete(void *folder_object) if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder deleteFolder]; @@ -449,7 +449,7 @@ sogo_folder_get_child_count(void *folder_object, enum mapistore_table_type table if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder getChildCount: child_count ofTableType: table_type]; @@ -481,7 +481,7 @@ sogo_folder_open_message(void *folder_object, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder openMessage: &message @@ -519,7 +519,7 @@ sogo_folder_create_message(void *folder_object, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder createMessage: &message @@ -551,7 +551,7 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags) if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder deleteMessageWithMID: mid andFlags: flags]; @@ -584,10 +584,10 @@ sogo_folder_move_copy_messages(void *folder_object, if (folder_object) { wrapper = folder_object; - targetFolder = wrapper->MAPIStoreSOGoObject; + targetFolder = wrapper->instance; wrapper = source_folder_object; - sourceFolder = wrapper->MAPIStoreSOGoObject; + sourceFolder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; @@ -623,7 +623,7 @@ sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder getDeletedFMIDs: fmidsp @@ -658,7 +658,7 @@ sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder getTable: &table @@ -693,7 +693,7 @@ sogo_folder_modify_permissions(void *folder_object, uint8_t flags, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder modifyPermissions: permissions @@ -725,7 +725,7 @@ sogo_message_get_message_data(void *message_object, if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; [message getMessageData: msg_dataP @@ -756,7 +756,7 @@ sogo_message_create_attachment (void *message_object, TALLOC_CTX *mem_ctx, void if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message createAttachment: &attachment inAID: aidp]; @@ -789,7 +789,7 @@ sogo_message_open_attachment (void *message_object, TALLOC_CTX *mem_ctx, if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message getAttachment: &attachment withAID: aid]; @@ -821,7 +821,7 @@ sogo_message_get_attachment_table (void *message_object, TALLOC_CTX *mem_ctx, vo if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message getAttachmentTable: &table @@ -856,7 +856,7 @@ sogo_message_modify_recipients (void *message_object, if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message modifyRecipientsWithRecipients: recipients @@ -887,7 +887,7 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag) if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message setReadFlag: flag]; @@ -916,7 +916,7 @@ sogo_message_save (void *message_object) if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message saveMessage]; @@ -945,7 +945,7 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags) if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message submitWithFlags: flags]; @@ -978,7 +978,7 @@ sogo_message_attachment_open_embedded_message if (attachment_object) { wrapper = attachment_object; - attachment = wrapper->MAPIStoreSOGoObject; + attachment = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [attachment openEmbeddedMessage: &message @@ -1012,7 +1012,7 @@ static enum mapistore_error sogo_table_get_available_properties(void *table_obje if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [table getAvailableProperties: propertiesP inMemCtx: mem_ctx]; @@ -1040,7 +1040,7 @@ sogo_table_set_columns (void *table_object, uint16_t count, enum MAPITAGS *prope if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [table setColumns: properties @@ -1069,7 +1069,7 @@ sogo_table_set_restrictions (void *table_object, struct mapi_SRestriction *restr if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; [table setRestrictions: restrictions]; @@ -1100,7 +1100,7 @@ sogo_table_set_sort_order (void *table_object, struct SSortOrderSet *sort_order, if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; [table setSortOrder: sort_order]; @@ -1133,7 +1133,7 @@ sogo_table_get_row (void *table_object, TALLOC_CTX *mem_ctx, if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [table getRow: data withRowID: row_id andQueryType: query_type @@ -1164,7 +1164,7 @@ sogo_table_get_row_count (void *table_object, if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [table getRowCount: row_countp @@ -1193,7 +1193,7 @@ sogo_table_handle_destructor (void *table_object, uint32_t handle_id) if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; [table destroyHandle: handle_id]; @@ -1223,7 +1223,7 @@ static enum mapistore_error sogo_properties_get_available_properties(void *objec if (object) { wrapper = object; - propObject = wrapper->MAPIStoreSOGoObject; + propObject = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [propObject getAvailableProperties: propertiesP inMemCtx: mem_ctx]; @@ -1254,7 +1254,7 @@ sogo_properties_get_properties (void *object, if (object) { wrapper = object; - propObject = wrapper->MAPIStoreSOGoObject; + propObject = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [propObject getProperties: data withTags: properties @@ -1284,7 +1284,7 @@ sogo_properties_set_properties (void *object, struct SRow *aRow) if (object) { wrapper = object; - propObject = wrapper->MAPIStoreSOGoObject; + propObject = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [propObject addPropertiesFromRow: aRow]; diff --git a/OpenChange/NSObject+MAPIStore.h b/OpenChange/NSObject+MAPIStore.h index 19254456f..2e532eb8d 100644 --- a/OpenChange/NSObject+MAPIStore.h +++ b/OpenChange/NSObject+MAPIStore.h @@ -29,7 +29,7 @@ struct MAPIStoreTallocWrapper { - id MAPIStoreSOGoObject; + id instance; }; @interface NSObject (MAPIStoreTallocHelpers) diff --git a/OpenChange/NSObject+MAPIStore.m b/OpenChange/NSObject+MAPIStore.m index 475395755..c291990f4 100644 --- a/OpenChange/NSObject+MAPIStore.m +++ b/OpenChange/NSObject+MAPIStore.m @@ -50,7 +50,7 @@ MAPIStoreTallocWrapperDestroy (void *data) pool = [NSAutoreleasePool new]; wrapper = data; // NSLog (@"destroying wrapped object (wrapper: %p; object: %p)...\n", wrapper, wrapper->MAPIStoreSOGoObject); - [wrapper->MAPIStoreSOGoObject release]; + [wrapper->instance release]; [pool release]; GSUnregisterCurrentThread (); @@ -63,7 +63,7 @@ MAPIStoreTallocWrapperDestroy (void *data) wrapper = talloc_zero (tallocCtx, struct MAPIStoreTallocWrapper); talloc_set_destructor ((void *) wrapper, MAPIStoreTallocWrapperDestroy); - wrapper->MAPIStoreSOGoObject = self; + wrapper->instance = self; [self retain]; // NSLog (@"returning wrapper: %p; object: %p", wrapper, self); From 674fb1081cc25690609752aa9d11757e9e137cae Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Sun, 1 Jul 2012 20:55:54 +0000 Subject: [PATCH 012/127] Monotone-Parent: b4eb1c4ecb6343d34ed9700a15e35cd1c9dc33af Monotone-Revision: 0ad1e10fb7587b8444bd502de4908d1aabf70c96 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-01T20:55:54 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++++ OpenChange/NSDate+MAPIStore.h | 6 +++++- OpenChange/NSDate+MAPIStore.m | 21 ++++++++++++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 69098850d..0787be8c6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-07-01 Wolfgang Sourdeau + + * OpenChange/NSDate+MAPIStore.m (NSDateCompare): new comparison + function for sorting array of NSDate instances. + 2012-06-30 Wolfgang Sourdeau * OpenChange/NSObject+MAPIStore.h: renamed diff --git a/OpenChange/NSDate+MAPIStore.h b/OpenChange/NSDate+MAPIStore.h index 3c7809f79..0a01a2ddc 100644 --- a/OpenChange/NSDate+MAPIStore.h +++ b/OpenChange/NSDate+MAPIStore.h @@ -25,9 +25,11 @@ #import +@class NSCalendarDate; + @interface NSDate (MAPIStoreDataTypes) -+ (id) dateFromMinutesSince1601: (uint32_t) minutes; ++ (NSCalendarDate *) dateFromMinutesSince1601: (uint32_t) minutes; - (uint32_t) asMinutesSince1601; + (id) dateFromFileTime: (const struct FILETIME *) timeValue; @@ -37,4 +39,6 @@ @end +NSComparisonResult NSDateCompare (NSDate *date1, NSDate *date2, void *); + #endif /* NSCALENDARDATE+MAPISTORE_H */ diff --git a/OpenChange/NSDate+MAPIStore.m b/OpenChange/NSDate+MAPIStore.m index eb873978b..1e631b82b 100644 --- a/OpenChange/NSDate+MAPIStore.m +++ b/OpenChange/NSDate+MAPIStore.m @@ -51,7 +51,7 @@ _setupRefDate () timeZone: [NSTimeZone timeZoneWithName: @"UTC"]]; } -+ (id) dateFromMinutesSince1601: (uint32_t) minutes ++ (NSCalendarDate *) dateFromMinutesSince1601: (uint32_t) minutes { NSCalendarDate *result; @@ -129,3 +129,22 @@ _setupRefDate () } @end + +NSComparisonResult +NSDateCompare (NSDate *date1, NSDate *date2, void *ctx) +{ + NSTimeInterval secs1, secs2; + NSComparisonResult result; + + secs1 = [date1 timeIntervalSince1970]; + secs2 = [date2 timeIntervalSince1970]; + if (secs1 == secs2) + result = NSOrderedSame; + else if (secs1 < secs2) + result = NSOrderedAscending; + else + result = NSOrderedDescending; + + return result; +} + From b3acd2e2add97681606d1ee811282adf38c3bcdc Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Sun, 1 Jul 2012 20:58:46 +0000 Subject: [PATCH 013/127] Monotone-Parent: 0ad1e10fb7587b8444bd502de4908d1aabf70c96 Monotone-Revision: a6b977673a1cc94b1269e19c469101dca9fd17bc Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-01T20:58:46 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 8 ++ ...Native Microsoft Outlook Configuration.odt | Bin 27917 -> 27917 bytes OpenChange/MAPIStoreAppointmentWrapper.m | 86 ++++++++---------- OpenChange/MAPIStoreRecurrenceUtils.h | 11 ++- OpenChange/MAPIStoreRecurrenceUtils.m | 48 ++++++++-- 5 files changed, 98 insertions(+), 55 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0787be8c6..43598829b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2012-07-01 Wolfgang Sourdeau + * OpenChange/MAPIStoreRecurrenceUtils.m + (-setupRecurrenceWithMasterEntity:fromRecurrencePattern:): add + exception dates to master entity based on the + "DeletedInstanceDates" member of the struct. + (-fillRecurrencePattern:withEvent:inTimeZone:inMemCtx:): new name + for fillRecurrencePattern:withStartDate:andEndDate:, add exception + dates to struct. + * OpenChange/NSDate+MAPIStore.m (NSDateCompare): new comparison function for sorting array of NSDate instances. diff --git a/Documentation/SOGo Native Microsoft Outlook Configuration.odt b/Documentation/SOGo Native Microsoft Outlook Configuration.odt index a350de392a22f7c89e179aeacef624755b9329af..3761cc8329c4bc0bb68370d8af7f6d7cb5d83a0a 100644 GIT binary patch delta 19554 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 delta 19545 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 diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index 7862980aa..d306e3c8f 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -28,11 +28,8 @@ #import #import #import -#import #import #import -#import -#import #import #import #import @@ -580,7 +577,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagMessageClass: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { const char *className; @@ -633,7 +630,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagStartDate: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { NSCalendarDate *dateValue; NSInteger offset; @@ -827,7 +824,7 @@ static NSCharacterSet *hexCharacterSet = nil; /* sender (organizer) */ - (int) getPidTagSenderEmailAddress: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getEmailAddress: data forICalPerson: [event organizer] @@ -835,7 +832,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagSenderAddressType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getAddrType: data forICalPerson: [event organizer] @@ -843,7 +840,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagSenderName: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getName: data forICalPerson: [event organizer] @@ -851,7 +848,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagSenderEntryId: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getEntryId: data forICalPerson: [event organizer] @@ -860,7 +857,7 @@ static NSCharacterSet *hexCharacterSet = nil; /* attendee */ - (int) getPidTagReceivedByEmailAddress: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getEmailAddress: data forICalPerson: [event userAsAttendee: user] @@ -868,7 +865,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagReceivedByAddressType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getAddrType: data forICalPerson: [event userAsAttendee: user] @@ -876,7 +873,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagReceivedByName: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getName: data forICalPerson: [event userAsAttendee: user] @@ -884,7 +881,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagReceivedByEntryId: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getEntryId: data forICalPerson: [event userAsAttendee: user] @@ -893,7 +890,7 @@ static NSCharacterSet *hexCharacterSet = nil; /* /attendee */ - (int) getPidTagEndDate: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { NSCalendarDate *dateValue; NSInteger offset; @@ -995,7 +992,8 @@ static NSCharacterSet *hexCharacterSet = nil; return [self getPidLidLocation: data inMemCtx: memCtx]; } -- (int) getPidLidServerProcessed: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidLidServerProcessed: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { /* TODO: we need to check whether the event has been processed internally by SOGo or if it was received only by mail. We only assume the SOGo case @@ -1003,7 +1001,8 @@ static NSCharacterSet *hexCharacterSet = nil; return [self getYes: data inMemCtx: memCtx]; } -- (int) getPidLidServerProcessingActions: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidLidServerProcessingActions: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { *data = MAPILongValue (memCtx, 0x00000010 /* cpsCreatedOnPrincipal */ @@ -1020,14 +1019,14 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagSensitivity: (void **) data // not implemented, depends on CLASS - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { // normal = 0, personal?? = 1, private = 2, confidential = 3 return [self getLongZero: data inMemCtx: memCtx]; } - (int) getPidTagImportance: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { uint32_t v; if ([[event priority] isEqualToString: @"9"]) @@ -1043,7 +1042,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagBody: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { int rc = MAPISTORE_SUCCESS; NSString *stringValue; @@ -1074,29 +1073,6 @@ static NSCharacterSet *hexCharacterSet = nil; return MAPISTORE_SUCCESS; } -static void -_fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, - NSCalendarDate *startDate, NSTimeInterval duration, - NSCalendarDate * endDate, iCalRecurrenceRule *rule) -{ - uint32_t startMinutes; - - [rule fillRecurrencePattern: &arp->RecurrencePattern - withStartDate: startDate andEndDate: endDate]; - arp->ReaderVersion2 = 0x00003006; - arp->WriterVersion2 = 0x00003009; - - startMinutes = ([startDate hourOfDay] * 60 + [startDate minuteOfHour]); - arp->StartTimeOffset = startMinutes; - arp->EndTimeOffset = startMinutes + (uint32_t) (duration / 60); - - arp->ExceptionCount = 0; - arp->ReservedBlock1Size = 0; - - /* Currently ignored in property.idl: - arp->ReservedBlock2Size = 0; */ -} - - (struct SBinary_short *) _computeAppointmentRecurInMemCtx: (TALLOC_CTX *) memCtx { @@ -1105,6 +1081,7 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, struct SBinary_short *sBin; NSCalendarDate *firstStartDate; iCalRecurrenceRule *rule; + NSUInteger startMinutes; rule = [[event recurrenceRules] objectAtIndex: 0]; @@ -1114,10 +1091,27 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, [firstStartDate setTimeZone: timeZone]; arp = talloc_zero (memCtx, struct AppointmentRecurrencePattern); - _fillAppointmentRecurrencePattern (arp, firstStartDate, - [event durationAsTimeInterval], - [event lastPossibleRecurrenceStartDate], - rule); + [rule fillRecurrencePattern: &arp->RecurrencePattern + withEvent: event + inTimeZone: timeZone + inMemCtx: arp]; + arp->ReaderVersion2 = 0x00003006; + arp->WriterVersion2 = 0x00003009; + + startMinutes = ([firstStartDate hourOfDay] * 60 + + [firstStartDate minuteOfHour]); + arp->StartTimeOffset = startMinutes; + arp->EndTimeOffset = (startMinutes + + (NSUInteger) ([event durationAsTimeInterval] + / 60)); + + arp->ExceptionCount = 0; + arp->ReservedBlock1Size = 0; + + /* Currently ignored in property.idl: arp->ReservedBlock2Size = 0; */ + + + /* convert struct to blob */ sBin = talloc_zero (memCtx, struct SBinary_short); bin = set_AppointmentRecurrencePattern (sBin, arp); sBin->cb = bin->cb; diff --git a/OpenChange/MAPIStoreRecurrenceUtils.h b/OpenChange/MAPIStoreRecurrenceUtils.h index 4fdf8c54e..a72a23af8 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.h +++ b/OpenChange/MAPIStoreRecurrenceUtils.h @@ -23,10 +23,14 @@ #ifndef MAPISTORERECURRENCEUTILS_H #define MAPISTORERECURRENCEUTILS_H +#include + #import #import -@class NSCalendarDate; +@class NSTimeZone; + +@class iCalEvent; @class iCalRepeatableEntityObject; @class iCalRecurrenceRule; @@ -44,8 +48,9 @@ @interface iCalRecurrenceRule (MAPIStoreRecurrence) - (void) fillRecurrencePattern: (struct RecurrencePattern *) rp - withStartDate: (NSCalendarDate *) startDate - andEndDate: (NSCalendarDate *) endDate; + withEvent: (iCalEvent *) event + inTimeZone: (NSTimeZone *) timeZone + inMemCtx: (TALLOC_CTX *) memCtx; @end diff --git a/OpenChange/MAPIStoreRecurrenceUtils.m b/OpenChange/MAPIStoreRecurrenceUtils.m index 09d6ce793..00ddf437a 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.m +++ b/OpenChange/MAPIStoreRecurrenceUtils.m @@ -21,17 +21,22 @@ */ #import +#import #import #import #import +#import +#import +#import #import #import -#import +#import #import "NSDate+MAPIStore.h" #import "MAPIStoreRecurrenceUtils.h" +#import "MAPIStoreTypes.h" #include #include @@ -43,7 +48,7 @@ - (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity fromRecurrencePattern: (struct RecurrencePattern *) rp { - NSCalendarDate *startDate, *olEndDate, *untilDate; + NSCalendarDate *startDate, *olEndDate, *untilDate, *exDate; NSString *monthDay, *month; iCalRecurrenceRule *rule; iCalByDayMask *byDayMask; @@ -203,6 +208,17 @@ [self errorWithFormat: @"invalid value for EndType: %.4x", rp->EndType]; } + + /* exception dates */ + for (count = 0; count < rp->DeletedInstanceCount; count++) + { + exDate + = [NSDate dateFromMinutesSince1601: rp->DeletedInstanceDates[count]]; + exDate = [exDate hour: [startDate hourOfDay] + minute: [startDate minuteOfHour] + second: [startDate secondOfMinute]]; + [entity addToExceptionDates: exDate]; + } } @end @@ -210,17 +226,24 @@ @implementation iCalRecurrenceRule (MAPIStoreRecurrence) - (void) fillRecurrencePattern: (struct RecurrencePattern *) rp - withStartDate: (NSCalendarDate *) startDate - andEndDate: (NSCalendarDate *) endDate + withEvent: (iCalEvent *) event + inTimeZone: (NSTimeZone *) timeZone + inMemCtx: (TALLOC_CTX *) memCtx { iCalRecurrenceFrequency freq; iCalByDayMask *byDayMask; NSString *byMonthDay, *bySetPos; - NSCalendarDate *untilDate, *beginOfWeek, *minimumDate, *moduloDate, *midnight; + NSCalendarDate *startDate, *endDate, *untilDate, *beginOfWeek, *minimumDate, *moduloDate, *midnight; iCalWeekOccurrences *days; - NSInteger dayOfWeek, repeatInterval, repeatCount, count, firstOccurrence; + NSInteger dayOfWeek, repeatInterval, repeatCount, count, firstOccurrence, max; uint32_t nbrMonths, mask; + NSArray *exDates; + startDate = [event firstRecurrenceStartDate]; + [startDate setTimeZone: timeZone]; + endDate = [event lastPossibleRecurrenceStartDate]; + [endDate setTimeZone: timeZone]; + rp->ReaderVersion = 0x3004; rp->WriterVersion = 0x3004; @@ -370,6 +393,19 @@ [self errorWithFormat: @"rule for an event that never occurs"]; } } + + + exDates = [[event exceptionDatesWithTimeZone: utcTZ] + sortedArrayUsingFunction: NSDateCompare + context: NULL]; + max = [exDates count]; + rp->DeletedInstanceCount = max; + rp->DeletedInstanceDates = talloc_array (memCtx, uint32_t, max); + for (count = 0; count < max; count++) + { + startDate = [[exDates objectAtIndex: count] hour: 0 minute: 0 second: 0]; + *(rp->DeletedInstanceDates + count) = [startDate asMinutesSince1601]; + } } @end From 79c3eb33dcfcf029f877231de49c364dc2e1644e Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Sun, 1 Jul 2012 22:31:05 +0000 Subject: [PATCH 014/127] Monotone-Parent: a6b977673a1cc94b1269e19c469101dca9fd17bc Monotone-Revision: ebf7c7e799b00cc44e631f47d644d492cac8a9aa Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-01T22:31:05 Monotone-Branch: ca.inverse.sogo --- OpenChange/NSDate+MAPIStore.h | 2 +- OpenChange/NSDate+MAPIStore.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenChange/NSDate+MAPIStore.h b/OpenChange/NSDate+MAPIStore.h index 0a01a2ddc..93f09be37 100644 --- a/OpenChange/NSDate+MAPIStore.h +++ b/OpenChange/NSDate+MAPIStore.h @@ -39,6 +39,6 @@ @end -NSComparisonResult NSDateCompare (NSDate *date1, NSDate *date2, void *); +NSComparisonResult NSDateCompare (id date1, id date2, void *); #endif /* NSCALENDARDATE+MAPISTORE_H */ diff --git a/OpenChange/NSDate+MAPIStore.m b/OpenChange/NSDate+MAPIStore.m index 1e631b82b..06e55f1d7 100644 --- a/OpenChange/NSDate+MAPIStore.m +++ b/OpenChange/NSDate+MAPIStore.m @@ -131,7 +131,7 @@ _setupRefDate () @end NSComparisonResult -NSDateCompare (NSDate *date1, NSDate *date2, void *ctx) +NSDateCompare (id date1, id date2, void *ctx) { NSTimeInterval secs1, secs2; NSComparisonResult result; From 8bf73b73b682ccbf2c588793e00133485a86bdf4 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 2 Jul 2012 19:49:05 +0000 Subject: [PATCH 015/127] Monotone-Parent: 47874ea582a8f97d988110f4d4174d2668de0fb0 Monotone-Revision: 32541b6f161d32f977e2eaff040e594f4ef885b2 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-02T19:49:05 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 1 - 1 file changed, 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 46995e658..43598829b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,3 @@ -<<<<<<< variant A 2012-07-01 Wolfgang Sourdeau * OpenChange/MAPIStoreRecurrenceUtils.m From 19adabfa92267b39ace1f4ceb59f3d2584d5899a Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 2 Jul 2012 19:57:29 +0000 Subject: [PATCH 016/127] Monotone-Parent: 32541b6f161d32f977e2eaff040e594f4ef885b2 Monotone-Revision: f25607e5762568e3c223b1868307c8cc92bd66da Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-02T19:57:29 Monotone-Branch: ca.inverse.sogo --- SOPE/GDLContentStore/GCSSpecialQueries.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SOPE/GDLContentStore/GCSSpecialQueries.m b/SOPE/GDLContentStore/GCSSpecialQueries.m index d3c916864..e99afbaf5 100644 --- a/SOPE/GDLContentStore/GCSSpecialQueries.m +++ b/SOPE/GDLContentStore/GCSSpecialQueries.m @@ -181,7 +181,7 @@ { static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (" - @" c_id VARCHAR(255) NOT NULL PRIMARY KEY," + @" c_id VARCHAR(255) PRIMARY KEY," @" c_value VARCHAR(255) NOT NULL," @" c_creationdate INT4 NOT NULL," @" c_lastseen INT4 NOT NULL)"); From 934e15d2d0df5063f1da21da7e92aa936d71f1bd Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 10 Jul 2012 15:49:05 +0000 Subject: [PATCH 017/127] Monotone-Parent: c6b25920d896b2d19d0ef40a4cadee46c87bba2d Monotone-Revision: 1c3bb3511167199e0dc7bafa4db7fc5540648666 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-10T15:49:05 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 9 ++++++ .../Appointments/SOGoAppointmentFolder.m | 22 ++++---------- SoObjects/SOGo/SOGoObject.h | 4 +++ SoObjects/SOGo/SOGoObject.m | 30 +++++++++++++++++++ 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index f5fdab097..e1747cb15 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2012-07-10 Wolfgang Sourdeau + + * SoObjects/SOGo/SOGoObject.m (-davBooleanForResult:): new method + that returns a valid DAV boolean from a BOOL. + (-isValidDAVBoolean:): new method that validates the value as a + DAV boolean. + (-resultForDAVBoolean:): new method that returns a BOOL from a DAV + boolean. + 2012-07-09 Ludovic Marcotte * Dropped old templates (SOGoAptMailDeletionReceipt.wox diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 864d0ec26..6a79582d8 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -2250,28 +2250,18 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir - (NSString *) davCalendarShowAlarms { - NSString *boolean; - - if ([self showCalendarAlarms]) - boolean = @"true"; - else - boolean = @"false"; - - return boolean; + return [self davBooleanForResult: [self showCalendarAlarms]]; } - (NSException *) setDavCalendarShowAlarms: (id) newBoolean { NSException *error; - error = nil; - - if ([newBoolean isEqualToString: @"true"] - || [newBoolean isEqualToString: @"1"]) - [self setShowCalendarAlarms: YES]; - else if ([newBoolean isEqualToString: @"false"] - || [newBoolean isEqualToString: @"0"]) - [self setShowCalendarAlarms: NO]; + if ([self isValidDAVBoolean: newBoolean]) + { + [self setShowCalendarAlarms: [self resultForDAVBoolean: newBoolean]]; + error = nil; + } else error = [NSException exceptionWithHTTPStatus: 400 reason: @"Bad boolean value."]; diff --git a/SoObjects/SOGo/SOGoObject.h b/SoObjects/SOGo/SOGoObject.h index dc26fd78e..172f45a60 100644 --- a/SoObjects/SOGo/SOGoObject.h +++ b/SoObjects/SOGo/SOGoObject.h @@ -166,6 +166,10 @@ parameters: (NSArray *) params; /* utilities */ +- (NSString *) davBooleanForResult: (BOOL) result; +- (BOOL) isValidDAVBoolean: (NSString *) davBoolean; +- (BOOL) resultForDAVBoolean: (NSString *) davBoolean; + - (NSString *) labelForKey: (NSString *) key; /* description */ diff --git a/SoObjects/SOGo/SOGoObject.m b/SoObjects/SOGo/SOGoObject.m index b7b42ba9f..8a0f0e24d 100644 --- a/SoObjects/SOGo/SOGoObject.m +++ b/SoObjects/SOGo/SOGoObject.m @@ -27,6 +27,7 @@ #import #import #import +#import #import #import #import @@ -1585,6 +1586,35 @@ return exception; } +- (NSString *) davBooleanForResult: (BOOL) result +{ + return (result ? @"true" : @"false"); +} + +- (BOOL) isValidDAVBoolean: (NSString *) davBoolean +{ + static NSSet *validBooleans = nil; + + if (!validBooleans) + { + validBooleans = [NSSet setWithObjects: @"true", @"false", @"1", @"0", + nil]; + [validBooleans retain]; + } + + return [validBooleans containsObject: davBoolean]; +} + +- (BOOL) resultForDAVBoolean: (NSString *) davBoolean +{ + BOOL result; + + result = ([davBoolean isEqualToString: @"true"] + || [davBoolean isEqualToString: @"1"]); + + return result; +} + - (NSString *) labelForKey: (NSString *) key { return [self labelForKey: key inContext: context]; From a469952773f3c3bbec7cdbee0ab2c301a2f9b57e Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 10 Jul 2012 15:49:24 +0000 Subject: [PATCH 018/127] Monotone-Parent: 1c3bb3511167199e0dc7bafa4db7fc5540648666 Monotone-Revision: eb2ae1364da011cec8f9e025b9b53785ba2647d6 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-10T15:49:24 Monotone-Branch: ca.inverse.sogo --- SoObjects/Appointments/SOGoAppointmentFolder.m | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 6a79582d8..a271c7b22 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -455,7 +455,7 @@ static NSNumber *sharedYes = nil; // We MUST keep the 'NO' value here, because we will always // fallback to the domain defaults otherwise. // -- (BOOL) _setNotificationValue: (BOOL) b +- (void) _setNotificationValue: (BOOL) b forKey: (NSString *) theKey { [self setFolderPropertyValue: [NSNumber numberWithBool: b] @@ -1005,7 +1005,9 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir rules = [cycleinfo objectForKey: @"rules"]; exRules = [cycleinfo objectForKey: @"exRules"]; exDates = [cycleinfo objectForKey: @"exDates"]; - eventTimeZone = allDayTimeZone = tz = nil; + eventTimeZone = nil; + allDayTimeZone = nil; + tz = nil; row = [self fixupRecord: theRecord]; [row removeObjectForKey: @"c_cycleinfo"]; @@ -1062,7 +1064,9 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir } } - tz = eventTimeZone? eventTimeZone : allDayTimeZone; +#warning this code is ugly: we should not mix objects with different types as\ + it reduces readability + tz = eventTimeZone ? eventTimeZone : allDayTimeZone; if (tz) { // Adjust the exception dates From 961302407db37073606f9be1bb2507f3f7634b5e Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 10 Jul 2012 16:02:16 +0000 Subject: [PATCH 019/127] Monotone-Parent: eb2ae1364da011cec8f9e025b9b53785ba2647d6 Monotone-Revision: fcec9822c0aaee8cefba77d0f50a8582b33fa3f0 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-10T16:02:16 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 11 +++ .../Appointments/SOGoAppointmentFolder.m | 78 +++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/ChangeLog b/ChangeLog index e1747cb15..8e3df2cf8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2012-07-10 Wolfgang Sourdeau + * SoObjects/Appointments/SOGoAppointmentFolder.m + (-davNotifyOnPersonalModifications) + (-setDavNotifyOnPersonalModifications:) + (-davNotifyOnExternalModifications) + (-setDavNotifyOnExternalModifications:) + (-davNotifyUserOnPersonalModifications) + (-setDavNotifyUserOnPersonalModifications:) + (-davNotifiedUserOnPersonalModifications) + (-setDavNotifiedUserOnPersonalModifications:): new dav accessors. + + * SoObjects/SOGo/SOGoObject.m (-davBooleanForResult:): new method that returns a valid DAV boolean from a BOOL. (-isValidDAVBoolean:): new method that validates the value as a diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index a271c7b22..29a64b77b 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -2273,6 +2273,84 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir return error; } +- (NSString *) davNotifyOnPersonalModifications +{ + return [self davBooleanForResult: [self notifyOnPersonalModifications]]; +} + +- (NSException *) setDavNotifyOnPersonalModifications: (NSString *) newBoolean +{ + NSException *error; + + if ([self isValidDAVBoolean: newBoolean]) + { + [self setNotifyOnPersonalModifications: + [self resultForDAVBoolean: newBoolean]]; + error = nil; + } + else + error = [NSException exceptionWithHTTPStatus: 400 + reason: @"Bad boolean value."]; + + return error; +} + +- (NSString *) davNotifyOnExternalModifications +{ + return [self davBooleanForResult: [self notifyOnExternalModifications]]; +} + +- (NSException *) setDavNotifyOnExternalModifications: (NSString *) newBoolean +{ + NSException *error; + + if ([self isValidDAVBoolean: newBoolean]) + { + [self setNotifyOnExternalModifications: + [self resultForDAVBoolean: newBoolean]]; + error = nil; + } + else + error = [NSException exceptionWithHTTPStatus: 400 + reason: @"Bad boolean value."]; + + return error; +} + +- (NSString *) davNotifyUserOnPersonalModifications +{ + return [self davBooleanForResult: [self notifyUserOnPersonalModifications]]; +} + +- (NSException *) setDavNotifyUserOnPersonalModifications: (NSString *) newBoolean +{ + NSException *error; + + if ([self isValidDAVBoolean: newBoolean]) + { + [self setNotifyUserOnPersonalModifications: + [self resultForDAVBoolean: newBoolean]]; + error = nil; + } + else + error = [NSException exceptionWithHTTPStatus: 400 + reason: @"Bad boolean value."]; + + return error; +} + +- (NSString *) davNotifiedUserOnPersonalModifications +{ + return [self notifiedUserOnPersonalModifications]; +} + +- (NSException *) setDavNotifiedUserOnPersonalModifications: (NSString *) theUser +{ + [self setNotifiedUserOnPersonalModifications: theUser]; + + return nil; +} + /* vevent UID handling */ - (NSString *) resourceNameForEventUID: (NSString *) uid From d932f1fd475d5c482742fa8a794261ff80b06d5f Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Wed, 11 Jul 2012 14:09:37 +0000 Subject: [PATCH 020/127] Fixed merge Monotone-Parent: 6eabcf880fa6d4620fb9a1ed111b15bef9bd9877 Monotone-Revision: 2252f3047b058ea629e568aec7efb2b0432e3c0c Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2012-07-11T14:09:37 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1c4d2d23a..b5df6d237 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,9 @@ -<<<<<<< variant A 2012-07-11 Ludovic Marcotte * Finished the implementation and testing of the two new defaults. Also added documentation in the SOGo Installation and Configuration Guide. ->>>>>>> variant B 2012-07-10 Wolfgang Sourdeau * SoObjects/Appointments/SOGoAppointmentFolder.m @@ -26,8 +24,6 @@ (-resultForDAVBoolean:): new method that returns a BOOL from a DAV boolean. -####### Ancestor -======= end 2012-07-09 Ludovic Marcotte * Dropped old templates (SOGoAptMailDeletionReceipt.wox From c342d3defe58629f1b365a06ba5c0e38df77870a Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 12 Jul 2012 15:05:33 +0000 Subject: [PATCH 021/127] Monotone-Parent: f48e9e2abfb00e03cccd2aa8fd8998a415bb5ce1 Monotone-Revision: 3dfe653dfcaeadc5fe93ff1f2c0a1f9d049c1836 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-12T15:05:33 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3381a6eb5..a3ba33ddf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,7 +4,6 @@ new defaults. Also added documentation in the SOGo Installation and Configuration Guide. -<<<<<<< variant A * Updated UI/Templates/SchedulerUI/UIxCalendarProperties.wox to not show the notification options if it's a web calendar or if the active user isn't the owner of the calendar. @@ -32,29 +31,6 @@ (-resultForDAVBoolean:): new method that returns a BOOL from a DAV boolean. ->>>>>>> variant B -2012-07-10 Wolfgang Sourdeau - - * SoObjects/Appointments/SOGoAppointmentFolder.m - (-davNotifyOnPersonalModifications) - (-setDavNotifyOnPersonalModifications:) - (-davNotifyOnExternalModifications) - (-setDavNotifyOnExternalModifications:) - (-davNotifyUserOnPersonalModifications) - (-setDavNotifyUserOnPersonalModifications:) - (-davNotifiedUserOnPersonalModifications) - (-setDavNotifiedUserOnPersonalModifications:): new dav accessors. - - - * SoObjects/SOGo/SOGoObject.m (-davBooleanForResult:): new method - that returns a valid DAV boolean from a BOOL. - (-isValidDAVBoolean:): new method that validates the value as a - DAV boolean. - (-resultForDAVBoolean:): new method that returns a BOOL from a DAV - boolean. - -####### Ancestor -======= end 2012-07-09 Ludovic Marcotte * Dropped old templates (SOGoAptMailDeletionReceipt.wox From 124f3f995e60373cb78bd1e2f09066882a947c20 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 19 Jul 2012 01:25:04 +0000 Subject: [PATCH 022/127] Monotone-Parent: cd2989d3a11079dde73d3a4890b0976e1405ebaa Monotone-Revision: 2cad87365f0a0c5651f8609b76b87ed5eeb351c4 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-19T01:25:04 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 7 +++++++ OpenChange/MAPIStoreDBMessage.m | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8cb8a09a0..c76e5bad2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2012-07-18 Wolfgang Sourdeau + + * OpenChange/MAPIStoreDBMessage.m (-objectVersion): shift the + version number by 16 bits, instead of doing it in -save. + (-save): don t swap the bytes of the version number as it would + return a wrong change number and a wrong change key for DB objects. + 2012-07-18 Ludovic Marcotte * SoObjects/Appointments/SOGoAppointmentObject.m diff --git a/OpenChange/MAPIStoreDBMessage.m b/OpenChange/MAPIStoreDBMessage.m index 945b41c8e..e8610de45 100644 --- a/OpenChange/MAPIStoreDBMessage.m +++ b/OpenChange/MAPIStoreDBMessage.m @@ -91,7 +91,7 @@ [(SOGoMAPIDBMessage *) sogoObject reloadIfNeeded]; versionNbr = [properties objectForKey: @"version"]; if (versionNbr) - objectVersion = [versionNbr unsignedLongLongValue]; + objectVersion = [versionNbr unsignedLongLongValue] >> 16; else objectVersion = ULLONG_MAX; @@ -158,7 +158,7 @@ if ([attachmentKeys count] > 0) [properties setObject: attachmentParts forKey: @"attachments"]; - newVersion = exchange_globcnt ([[self context] getNewChangeNumber] >> 16); + newVersion = [[self context] getNewChangeNumber]; [properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion] forKey: @"version"]; From 3ddba08a9eea5a4270e725a50911074db7bad19e Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 19 Jul 2012 01:26:45 +0000 Subject: [PATCH 023/127] Monotone-Parent: 2cad87365f0a0c5651f8609b76b87ed5eeb351c4 Monotone-Revision: 8b81870c2b6bc608846d32e8e0b91c60d47ebb6a Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-19T01:26:45 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/MAPIApplication.m | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/ChangeLog b/ChangeLog index c76e5bad2..00401f0c2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-07-18 Wolfgang Sourdeau + * OpenChange/MAPIApplication.m (-init): a WEResourceManager is + setup for the application so that page templates can be properly + be initialized. + * OpenChange/MAPIStoreDBMessage.m (-objectVersion): shift the version number by 16 bits, instead of doing it in -save. (-save): don t swap the bytes of the version number as it would diff --git a/OpenChange/MAPIApplication.m b/OpenChange/MAPIApplication.m index 8da1c1078..ecf3bedb0 100644 --- a/OpenChange/MAPIApplication.m +++ b/OpenChange/MAPIApplication.m @@ -22,6 +22,7 @@ #import #import +#import #import #import @@ -46,12 +47,18 @@ MAPIApplication *MAPIApp = nil; { if (!MAPIApp) { + WEResourceManager *rm; + // TODO publish [iCalEntityObject initializeSOGoExtensions]; MAPIApp = [super init]; [MAPIApp retain]; + rm = [[WEResourceManager alloc] init]; + [self setResourceManager:rm]; + [rm release]; + utcTZ = [NSTimeZone timeZoneWithName: @"UTC"]; [utcTZ retain]; } From 2de531a6cb04ce66f1cda606ae0d18a502f0c41f Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 19 Jul 2012 01:30:43 +0000 Subject: [PATCH 024/127] Monotone-Parent: 8b81870c2b6bc608846d32e8e0b91c60d47ebb6a Monotone-Revision: 7a12a4fc3471976029528f54b57e6999eff2b3aa Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-19T01:30:43 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/MAPIStoreCalendarFolder.m | 3 +++ 2 files changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index 00401f0c2..3beb9b626 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-07-18 Wolfgang Sourdeau + * OpenChange/MAPIStoreCalendarFolder.m (-createMessage): attach a + WOContext to the newEntry in order to enable page templates + resolution when notifications are sent. + * OpenChange/MAPIApplication.m (-init): a WEResourceManager is setup for the application so that page templates can be properly be initialized. diff --git a/OpenChange/MAPIStoreCalendarFolder.m b/OpenChange/MAPIStoreCalendarFolder.m index 71dcddb4e..f35918596 100644 --- a/OpenChange/MAPIStoreCalendarFolder.m +++ b/OpenChange/MAPIStoreCalendarFolder.m @@ -35,6 +35,7 @@ #import "MAPIStoreCalendarContext.h" #import "MAPIStoreCalendarMessage.h" #import "MAPIStoreCalendarMessageTable.h" +#import "MAPIStoreUserContext.h" #import "NSString+MAPIStore.h" #import "MAPIStoreCalendarFolder.h" @@ -67,6 +68,8 @@ newEntry = [SOGoAppointmentObject objectWithName: name inContainer: sogoObject]; [newEntry setIsNew: YES]; + /* the WOContext is required here for resolving notification pages */ + [newEntry setContext: [[self userContext] woContext]]; newMessage = [MAPIStoreCalendarMessage mapiStoreObjectWithSOGoObject: newEntry inContainer: self]; From 4c86e1b09b83008555e8de7e8bd5af5ed83fc4ba Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 19 Jul 2012 19:06:46 +0000 Subject: [PATCH 025/127] Monotone-Parent: 7a12a4fc3471976029528f54b57e6999eff2b3aa Monotone-Revision: f43939c9f93e2ae0c474453779ec04d06a04dd8a Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-19T19:06:46 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 7 ++++ OpenChange/MAPIStoreObject.h | 6 --- OpenChange/MAPIStoreObject.m | 54 ------------------------- OpenChange/NSObject+MAPIStore.h | 11 ++++++ OpenChange/NSObject+MAPIStore.m | 70 +++++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 60 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3beb9b626..7ee21810d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2012-07-19 Wolfgang Sourdeau + + * OpenChange/NSObject+MAPIStore.m + (+getAvailableProperties:inMemCtx:) + (-getAvailableProperties:inMemCtx:, canGetProperty:): methods + moved from MAPIStoreObject.m + 2012-07-18 Wolfgang Sourdeau * OpenChange/MAPIStoreCalendarFolder.m (-createMessage): attach a diff --git a/OpenChange/MAPIStoreObject.h b/OpenChange/MAPIStoreObject.h index 709396e9f..6db864de4 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -50,8 +50,6 @@ + (id) mapiStoreObjectInContainer: (MAPIStoreObject *) newContainer; - (id) initInContainer: (MAPIStoreObject *) newContainer; -+ (int) getAvailableProperties: (struct SPropTagArray **) propertiesP - inMemCtx: (TALLOC_CTX *) memCtx; - (MAPIStoreObject *) container; @@ -61,14 +59,10 @@ /* properties */ -- (BOOL) canGetProperty: (enum MAPITAGS) propTag; - - (void) addProperties: (NSDictionary *) newProperties; - (NSMutableDictionary *) properties; /* ops */ -- (int) getAvailableProperties: (struct SPropTagArray **) propertiesP - inMemCtx: (TALLOC_CTX *) localMemCtx; - (int) getProperties: (struct mapistore_property_data *) data withTags: (enum MAPITAGS *) tags andCount: (uint16_t) columnCount diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index ac782cdc8..994a74893 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -68,35 +68,6 @@ static Class NSExceptionK, MAPIStoreFolderK; return newObject; } -+ (int) getAvailableProperties: (struct SPropTagArray **) propertiesP - inMemCtx: (TALLOC_CTX *) memCtx -{ - struct SPropTagArray *properties; - const MAPIStorePropertyGetter *classGetters; - NSUInteger count; - enum MAPITAGS propTag; - uint16_t propValue; - - properties = talloc_zero (memCtx, struct SPropTagArray); - properties->aulPropTag = talloc_array (properties, enum MAPITAGS, - MAPIStoreSupportedPropertiesCount); - classGetters = MAPIStorePropertyGettersForClass (self); - for (count = 0; count < MAPIStoreSupportedPropertiesCount; count++) - { - propTag = MAPIStoreSupportedProperties[count]; - propValue = (propTag & 0xffff0000) >> 16; - if (classGetters[propValue]) - { - properties->aulPropTag[properties->cValues] = propTag; - properties->cValues++; - } - } - - *propertiesP = properties; - - return MAPISTORE_SUCCESS; -} - - (id) init { if ((self = [super init])) @@ -204,31 +175,6 @@ static Class NSExceptionK, MAPIStoreFolderK; return MAPISTORE_SUCCESS; } -- (int) getAvailableProperties: (struct SPropTagArray **) propertiesP - inMemCtx: (TALLOC_CTX *) memCtx -{ - NSUInteger count; - struct SPropTagArray *availableProps; - enum MAPITAGS propTag; - - availableProps = talloc_zero (memCtx, struct SPropTagArray); - availableProps->aulPropTag = talloc_array (availableProps, enum MAPITAGS, - MAPIStoreSupportedPropertiesCount); - for (count = 0; count < MAPIStoreSupportedPropertiesCount; count++) - { - propTag = MAPIStoreSupportedProperties[count]; - if ([self canGetProperty: propTag]) - { - availableProps->aulPropTag[availableProps->cValues] = propTag; - availableProps->cValues++; - } - } - - *propertiesP = availableProps; - - return MAPISTORE_SUCCESS; -} - - (BOOL) canGetProperty: (enum MAPITAGS) propTag { uint16_t propValue; diff --git a/OpenChange/NSObject+MAPIStore.h b/OpenChange/NSObject+MAPIStore.h index 2e532eb8d..c5c95c26c 100644 --- a/OpenChange/NSObject+MAPIStore.h +++ b/OpenChange/NSObject+MAPIStore.h @@ -26,6 +26,7 @@ #import #include +#include struct MAPIStoreTallocWrapper { @@ -58,4 +59,14 @@ struct MAPIStoreTallocWrapper @end +@interface NSObject (MAPIStoreProperties) + ++ (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP + inMemCtx: (TALLOC_CTX *) memCtx; +- (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP + inMemCtx: (TALLOC_CTX *) memCtx; +- (BOOL) canGetProperty: (enum MAPITAGS) propTag; + +@end + #endif /* NSOBJECT_MAPISTORE_H */ diff --git a/OpenChange/NSObject+MAPIStore.m b/OpenChange/NSObject+MAPIStore.m index c291990f4..a25a65758 100644 --- a/OpenChange/NSObject+MAPIStore.m +++ b/OpenChange/NSObject+MAPIStore.m @@ -25,6 +25,7 @@ #import #import +#import "MAPIStorePropertySelectors.h" #import "MAPIStoreTypes.h" #import "NSArray+MAPIStore.h" #import "NSData+MAPIStore.h" @@ -168,3 +169,72 @@ MAPIStoreTallocWrapperDestroy (void *data) } @end + +@implementation NSObject (MAPIStoreProperties) + ++ (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP + inMemCtx: (TALLOC_CTX *) memCtx +{ + struct SPropTagArray *properties; + const MAPIStorePropertyGetter *classGetters; + NSUInteger count; + enum MAPITAGS propTag; + uint16_t propValue; + + properties = talloc_zero (memCtx, struct SPropTagArray); + properties->aulPropTag = talloc_array (properties, enum MAPITAGS, + MAPIStoreSupportedPropertiesCount); + classGetters = MAPIStorePropertyGettersForClass (self); + for (count = 0; count < MAPIStoreSupportedPropertiesCount; count++) + { + propTag = MAPIStoreSupportedProperties[count]; + propValue = (propTag & 0xffff0000) >> 16; + if (classGetters[propValue]) + { + properties->aulPropTag[properties->cValues] = propTag; + properties->cValues++; + } + } + + *propertiesP = properties; + + return MAPISTORE_SUCCESS; +} + +- (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSUInteger count; + struct SPropTagArray *availableProps; + enum MAPITAGS propTag; + + availableProps = talloc_zero (memCtx, struct SPropTagArray); + availableProps->aulPropTag = talloc_array (availableProps, enum MAPITAGS, + MAPIStoreSupportedPropertiesCount); + for (count = 0; count < MAPIStoreSupportedPropertiesCount; count++) + { + propTag = MAPIStoreSupportedProperties[count]; + if ([self canGetProperty: propTag]) + { + availableProps->aulPropTag[availableProps->cValues] = propTag; + availableProps->cValues++; + } + } + + *propertiesP = availableProps; + + return MAPISTORE_SUCCESS; +} + +- (BOOL) canGetProperty: (enum MAPITAGS) propTag +{ + uint16_t propValue; + const IMP *classGetters; + + classGetters = (IMP *) MAPIStorePropertyGettersForClass (isa); + propValue = (propTag & 0xffff0000) >> 16; + + return (classGetters[propValue] != NULL); +} + +@end From cd18ceeb6c527e0dacaa3cd8cbe9d045872542fb Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 19 Jul 2012 19:09:41 +0000 Subject: [PATCH 026/127] Monotone-Parent: f43939c9f93e2ae0c474453779ec04d06a04dd8a Monotone-Revision: be9c203f3a5b8055a08854fac75321227532ee8c Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-19T19:09:41 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreTable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreTable.h b/OpenChange/MAPIStoreTable.h index 7695c79f0..53bfbc50c 100644 --- a/OpenChange/MAPIStoreTable.h +++ b/OpenChange/MAPIStoreTable.h @@ -25,7 +25,7 @@ #include -#import +#import "NSObject+MAPIStore.h" #undef DEBUG #include From b4f8a596f571ebdc366630d898f3a861fcdb4379 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 19 Jul 2012 19:28:44 +0000 Subject: [PATCH 027/127] Monotone-Parent: be9c203f3a5b8055a08854fac75321227532ee8c Monotone-Revision: b65572c3789024ccb44bac952fa19cc6708071a0 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-19T19:28:44 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 11 ++++++ OpenChange/GNUmakefile | 1 + OpenChange/MAPIStoreObject.h | 3 ++ OpenChange/MAPIStoreObject.m | 16 ++++++++ OpenChange/MAPIStoreObjectProxy.h | 41 +++++++++++++++++++ OpenChange/MAPIStoreObjectProxy.m | 66 +++++++++++++++++++++++++++++++ 6 files changed, 138 insertions(+) create mode 100644 OpenChange/MAPIStoreObjectProxy.h create mode 100644 OpenChange/MAPIStoreObjectProxy.m diff --git a/ChangeLog b/ChangeLog index 7ee21810d..089c6bab3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2012-07-19 Wolfgang Sourdeau + * OpenChange/MAPIStoreObject.m (-addProxy:): new method that keeps + proxy objects in the new "proxies" ivar. + (-getProperty:withTag:inMemCtx:): added code that pass the request + to the available object proxies, when the property getters have + not been found in the local class. + + * OpenChange/MAPIStoreObjectProxy.[hm]: new class module that + provide a facility for providing property getters in the name of + another class, working around the fact that Objective-C does not + provide multiple-inheritance. + * OpenChange/NSObject+MAPIStore.m (+getAvailableProperties:inMemCtx:) (-getAvailableProperties:inMemCtx:, canGetProperty:): methods diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 6f4803ba9..7054f8998 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -55,6 +55,7 @@ $(SOGOBACKEND)_OBJC_FILES += \ MAPIStoreFolder.m \ MAPIStoreMessage.m \ MAPIStoreObject.m \ + MAPIStoreObjectProxy.m \ MAPIStoreSOGoObject.m \ MAPIStoreTable.m \ MAPIStoreMessageTable.m \ diff --git a/OpenChange/MAPIStoreObject.h b/OpenChange/MAPIStoreObject.h index 6db864de4..bd30a77a0 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -35,6 +35,7 @@ @class MAPIStoreContext; @class MAPIStoreMapping; +@class MAPIStoreObjectProxy; @class MAPIStoreUserContext; @class MAPIStoreSOGoObject; @@ -43,6 +44,7 @@ const IMP *classGetters; NSMutableArray *parentContainersBag; + NSMutableArray *proxies; id container; NSMutableDictionary *properties; } @@ -50,6 +52,7 @@ + (id) mapiStoreObjectInContainer: (MAPIStoreObject *) newContainer; - (id) initInContainer: (MAPIStoreObject *) newContainer; +- (void) addProxy: (MAPIStoreObjectProxy *) newProxy; - (MAPIStoreObject *) container; diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index 994a74893..b092bbe03 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -143,6 +143,7 @@ static Class NSExceptionK, MAPIStoreFolderK; SEL methodSel; id value; int rc = MAPISTORE_ERR_NOT_FOUND; + NSUInteger count, max; value = [properties objectForKey: MAPIPropertyKey (propTag)]; if (value) @@ -156,6 +157,16 @@ static Class NSExceptionK, MAPIStoreFolderK; rc = method (self, methodSel, data, memCtx); } + if (rc == MAPISTORE_ERR_NOT_FOUND) + { + max = [proxies count]; + for (count = 0; rc == MAPISTORE_ERR_NOT_FOUND && count < max; count++) + rc = [[proxies objectAtIndex: count] + getProperty: data + withTag: propTag + inMemCtx: memCtx]; + } + return rc; } @@ -200,6 +211,11 @@ static Class NSExceptionK, MAPIStoreFolderK; return MAPISTORE_SUCCESS; } +- (void) addProxy: (MAPIStoreObjectProxy *) newProxy +{ + [proxies addObject: newProxy]; +} + - (int) addPropertiesFromRow: (struct SRow *) aRow { struct SPropValue *cValue; diff --git a/OpenChange/MAPIStoreObjectProxy.h b/OpenChange/MAPIStoreObjectProxy.h new file mode 100644 index 000000000..6e9aee13e --- /dev/null +++ b/OpenChange/MAPIStoreObjectProxy.h @@ -0,0 +1,41 @@ +/* MAPIStoreObjectProxy.h - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef MAPISTOREOBJECTPROXY_H +#define MAPISTOREOBJECTPROXY_H + +#include + +#import + +@interface MAPIStoreObjectProxy : NSObject +{ + const IMP *classGetters; +} + +- (enum mapistore_error) getProperty: (void **) data + withTag: (enum MAPITAGS) propTag + inMemCtx: (TALLOC_CTX *) localMemCtx; + +@end + +#endif /* MAPISTOREOBJECTPROXY_H */ diff --git a/OpenChange/MAPIStoreObjectProxy.m b/OpenChange/MAPIStoreObjectProxy.m new file mode 100644 index 000000000..415d26df6 --- /dev/null +++ b/OpenChange/MAPIStoreObjectProxy.m @@ -0,0 +1,66 @@ +/* MAPIStoreObjectProxy.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import "MAPIStorePropertySelectors.h" + +#import "MAPIStoreObjectProxy.h" + +#undef DEBUG +#include +#include +#include +#include +#include + +@implementation MAPIStoreObjectProxy + +- (id) init +{ + if ((self = [super init])) + { + classGetters = (IMP *) MAPIStorePropertyGettersForClass (isa); + } + + return self; +} + +- (enum mapistore_error) getProperty: (void **) data + withTag: (enum MAPITAGS) propTag + inMemCtx: (TALLOC_CTX *) memCtx +{ + MAPIStorePropertyGetter method; + uint16_t propValue; + SEL methodSel; + int rc; + + propValue = (propTag & 0xffff0000) >> 16; + methodSel = MAPIStoreSelectorForPropertyGetter (propValue); + method = (MAPIStorePropertyGetter) classGetters[propValue]; + if (method) + rc = method (self, methodSel, data, memCtx); + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + +@end From 0b2f4e5c445e6a63d911403ea6779c0c9b24762e Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 19 Jul 2012 20:26:33 +0000 Subject: [PATCH 028/127] Monotone-Parent: b65572c3789024ccb44bac952fa19cc6708071a0 Monotone-Revision: fc87b2e35370aef34db8f91a54bc71a27c2ea297 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-19T20:26:33 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 7 + OpenChange/MAPIStoreAppointmentWrapper.h | 5 +- OpenChange/MAPIStoreCalendarMessage.h | 3 - OpenChange/MAPIStoreCalendarMessage.m | 347 +++-------------------- 4 files changed, 49 insertions(+), 313 deletions(-) diff --git a/ChangeLog b/ChangeLog index 089c6bab3..3a9ceb7e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2012-07-19 Wolfgang Sourdeau + * OpenChange/MAPIStoreAppointmentWrapper.m: now a subclass of + MAPIStoreObjectProxy. + + * OpenChange/MAPIStoreCalendarMessage.m + (-initWithSOGoObject:inContainer:): we now register our + appointment wrapper as a proxy. + * OpenChange/MAPIStoreObject.m (-addProxy:): new method that keeps proxy objects in the new "proxies" ivar. (-getProperty:withTag:inMemCtx:): added code that pass the request diff --git a/OpenChange/MAPIStoreAppointmentWrapper.h b/OpenChange/MAPIStoreAppointmentWrapper.h index 74b275275..bb766bf1f 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.h +++ b/OpenChange/MAPIStoreAppointmentWrapper.h @@ -23,10 +23,11 @@ #ifndef MAPISTORECALENDARWRAPPER_H #define MAPISTORECALENDARWRAPPER_H -#import #import #import +#import "MAPIStoreObjectProxy.h" + @class NSTimeZone; @class iCalAlarm; @@ -35,7 +36,7 @@ @class SOGoUser; -@interface MAPIStoreAppointmentWrapper : NSObject +@interface MAPIStoreAppointmentWrapper : MAPIStoreObjectProxy { struct mapistore_connection_info *connInfo; iCalCalendar *calendar; diff --git a/OpenChange/MAPIStoreCalendarMessage.h b/OpenChange/MAPIStoreCalendarMessage.h index 4ccab5cdd..ff942e6cf 100644 --- a/OpenChange/MAPIStoreCalendarMessage.h +++ b/OpenChange/MAPIStoreCalendarMessage.h @@ -28,9 +28,6 @@ @class MAPIStoreAppointmentWrapper; @interface MAPIStoreCalendarMessage : MAPIStoreGCSMessage -{ - MAPIStoreAppointmentWrapper *appointmentWrapper; -} @end diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index 5d2eb48a6..a4b4b33ca 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -87,51 +87,33 @@ @implementation MAPIStoreCalendarMessage -- (id) init -{ - if ((self = [super init])) - { - appointmentWrapper = nil; - } - - return self; -} - -- (void) dealloc -{ - [appointmentWrapper release]; - [super dealloc]; -} - -- (MAPIStoreAppointmentWrapper *) appointmentWrapper +- (id) initWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newFolder { iCalEvent *event; MAPIStoreContext *context; MAPIStoreUserContext *userContext; - - if (!appointmentWrapper) + MAPIStoreAppointmentWrapper *appointmentWrapper; + + if ((self = [super initWithSOGoObject: newSOGoObject + inContainer: newFolder])) { event = [sogoObject component: NO secure: YES]; context = [self context]; userContext = [self userContext]; - ASSIGN (appointmentWrapper, - [MAPIStoreAppointmentWrapper wrapperWithICalEvent: event - andUser: [userContext sogoUser] - andSenderEmail: nil - inTimeZone: [userContext timeZone] - withConnectionInfo: [context connectionInfo]]); + appointmentWrapper + = [MAPIStoreAppointmentWrapper wrapperWithICalEvent: event + andUser: [userContext sogoUser] + andSenderEmail: nil + inTimeZone: [userContext timeZone] + withConnectionInfo: [context connectionInfo]]; + [self addProxy: appointmentWrapper]; } - - return appointmentWrapper; + + return self; } /* getters */ -- (int) getPidTagIconIndex: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagIconIndex: data inMemCtx: memCtx]; -} - - (int) getPidLidFInvited: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -154,93 +136,6 @@ return MAPISTORE_SUCCESS; } -- (int) getPidTagOwnerAppointmentId: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagOwnerAppointmentId: data inMemCtx: memCtx]; -} - -- (int) getPidTagStartDate: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagStartDate: data inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentSequence: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentSequence: data - inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentStateFlags: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentStateFlags: data inMemCtx: memCtx]; -} - -- (int) getPidLidResponseStatus: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidResponseStatus: data - inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentStartWhole: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentStartWhole: data inMemCtx: memCtx]; -} - -- (int) getPidLidCommonStart: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidCommonStart: data inMemCtx: memCtx]; -} - -- (int) getPidTagEndDate: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagEndDate: data inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentEndWhole: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentEndWhole: data inMemCtx: memCtx]; -} - -- (int) getPidLidCommonEnd: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidCommonEnd: data inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentDuration: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentDuration: data inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentSubType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentSubType: data - inMemCtx: memCtx]; -} - -- (int) getPidLidBusyStatus: (void **) data // TODO - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidBusyStatus: data inMemCtx: memCtx]; -} - -- (int) getPidTagSubject: (void **) data // SUMMARY - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagSubject: data inMemCtx: memCtx]; -} - - (int) getPidLidSideEffects: (void **) data // TODO inMemCtx: (TALLOC_CTX *) memCtx { @@ -251,155 +146,48 @@ return MAPISTORE_SUCCESS; } -- (int) getPidLidLocation: (void **) data // LOCATION - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidLocation: data inMemCtx: memCtx]; -} - -- (int) getPidLidPrivate: (void **) data // private (bool), should depend on CLASS and permissions - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidPrivate: data inMemCtx: memCtx]; -} - -- (int) getPidTagSensitivity: (void **) data // not implemented, depends on CLASS - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagSensitivity: data inMemCtx: memCtx]; -} - -- (int) getPidTagImportance: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagImportance: data inMemCtx: memCtx]; -} - -- (int) getPidTagBody: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagBody: data inMemCtx: memCtx]; -} - -- (int) getPidLidIsRecurring: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidIsRecurring: data inMemCtx: memCtx]; -} - -- (int) getPidLidRecurring: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidRecurring: data inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentRecur: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentRecur: data - inMemCtx: memCtx]; -} - -- (int) getPidLidGlobalObjectId: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidGlobalObjectId: data - inMemCtx: memCtx]; -} - -- (int) getPidLidCleanGlobalObjectId: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidCleanGlobalObjectId: data - inMemCtx: memCtx]; -} - - (int) getPidTagProcessed: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getYes: data inMemCtx: memCtx]; } -- (int) getPidLidServerProcessed: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidServerProcessed: data - inMemCtx: memCtx]; -} - -- (int) getPidLidServerProcessingActions: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidServerProcessingActions: data - inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentReplyTime: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentReplyTime: data - inMemCtx: memCtx]; -} - - (void) getMessageData: (struct mapistore_message **) dataPtr inMemCtx: (TALLOC_CTX *) memCtx { struct mapistore_message *msgData; [super getMessageData: &msgData inMemCtx: memCtx]; - [[self appointmentWrapper] fillMessageData: msgData - inMemCtx: memCtx]; + /* HACK: we know the first (and only) proxy is our appointment wrapper + instance, but this might not always be true */ + [[proxies objectAtIndex: 0] fillMessageData: msgData + inMemCtx: memCtx]; *dataPtr = msgData; } -/* sender */ -- (int) getPidTagSenderEmailAddress: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagSenderEmailAddress: data - inMemCtx: memCtx]; -} - -- (int) getPidTagSenderAddressType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagSenderAddressType: data - inMemCtx: memCtx]; -} - -- (int) getPidTagSenderName: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagSenderName: data - inMemCtx: memCtx]; -} - -- (int) getPidTagSenderEntryId: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagSenderEntryId: data - inMemCtx: memCtx]; -} - /* sender representing */ -- (int) getPidTagSentRepresentingEmailAddress: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getPidTagSenderEmailAddress: data inMemCtx: memCtx]; -} +// - (int) getPidTagSentRepresentingEmailAddress: (void **) data +// inMemCtx: (TALLOC_CTX *) memCtx +// { +// return [self getPidTagSenderEmailAddress: data inMemCtx: memCtx]; +// } -- (int) getPidTagSentRepresentingAddressType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getSMTPAddrType: data inMemCtx: memCtx]; -} +// - (int) getPidTagSentRepresentingAddressType: (void **) data +// inMemCtx: (TALLOC_CTX *) memCtx +// { +// return [self getSMTPAddrType: data inMemCtx: memCtx]; +// } -- (int) getPidTagSentRepresentingName: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getPidTagSenderName: data inMemCtx: memCtx]; -} +// - (int) getPidTagSentRepresentingName: (void **) data +// inMemCtx: (TALLOC_CTX *) memCtx +// { +// return [self getPidTagSenderName: data inMemCtx: memCtx]; +// } -- (int) getPidTagSentRepresentingEntryId: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getPidTagSenderEntryId: data inMemCtx: memCtx]; -} +// - (int) getPidTagSentRepresentingEntryId: (void **) data +// inMemCtx: (TALLOC_CTX *) memCtx +// { +// return [self getPidTagSenderEntryId: data inMemCtx: memCtx]; +// } /* attendee */ // - (int) getPidTagReceivedByAddressType: (void **) data @@ -461,63 +249,6 @@ return [self getYes: data inMemCtx: memCtx]; } -/* alarms */ -- (int) getPidLidReminderSet: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderSet: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderDelta: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderDelta: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderTime: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderTime: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderSignalTime: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderSignalTime: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderOverride: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderOverride: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderType: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderPlaySound: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderPlaySound: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderFileParameter: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderFileParameter: data - inMemCtx: memCtx]; -} - /* attendee */ - (void) _setupRecurrenceInCalendar: (iCalCalendar *) calendar withEvent: (iCalEvent *) event From 7fa7630d7446180d34c556d2176d85f7b4ef8e0c Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 19 Jul 2012 20:31:15 +0000 Subject: [PATCH 029/127] Monotone-Parent: fc87b2e35370aef34db8f91a54bc71a27c2ea297 Monotone-Revision: 44c81c0fbde1cf04e0ee2064fd07a4e6b1e74fcb Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-19T20:31:15 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/MAPIStoreObject.h | 3 +++ OpenChange/MAPIStoreObject.m | 21 +++++++++++++++++++++ OpenChange/MAPIStoreSOGoObject.h | 3 --- OpenChange/MAPIStoreSOGoObject.m | 14 -------------- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3a9ceb7e7..4acd03d55 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-07-19 Wolfgang Sourdeau + * OpenChange/MAPIStoreObject.m (-nameInContainer): moved method + from MAPIStoreSOGoObject and made mandatory for subclasses. + (-url): new methed moved from MAPIStoreSOGoObject. + * OpenChange/MAPIStoreAppointmentWrapper.m: now a subclass of MAPIStoreObjectProxy. diff --git a/OpenChange/MAPIStoreObject.h b/OpenChange/MAPIStoreObject.h index bd30a77a0..e0deb91ed 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -60,6 +60,8 @@ - (MAPIStoreUserContext *) userContext; - (MAPIStoreMapping *) mapping; +- (NSString *) url; + /* properties */ - (void) addProperties: (NSDictionary *) newProperties; @@ -89,6 +91,7 @@ inMemCtx: (TALLOC_CTX *) memCtx; /* subclasses */ +- (NSString *) nameInContainer - (NSDate *) creationTime; - (NSDate *) lastModificationTime; diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index b092bbe03..0204f3a2d 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -122,6 +122,20 @@ static Class NSExceptionK, MAPIStoreFolderK; return [[self userContext] mapping]; } +- (NSString *) url +{ + NSString *containerURL, *format; + + containerURL = (NSString *) [container url]; + if ([containerURL hasSuffix: @"/"]) + format = @"%@%@"; + else + format = @"%@/%@"; + + return [NSString stringWithFormat: format, + containerURL, [self nameInContainer]]; +} + /* helpers */ - (void) addProperties: (NSDictionary *) newNewProperties @@ -293,6 +307,13 @@ static Class NSExceptionK, MAPIStoreFolderK; } /* subclasses */ +- (NSString *) nameInContainer +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + - (NSDate *) creationTime { [self subclassResponsibility: _cmd]; diff --git a/OpenChange/MAPIStoreSOGoObject.h b/OpenChange/MAPIStoreSOGoObject.h index 90524558f..cacdf23b1 100644 --- a/OpenChange/MAPIStoreSOGoObject.h +++ b/OpenChange/MAPIStoreSOGoObject.h @@ -58,14 +58,11 @@ - (id) sogoObject; -- (NSString *) nameInContainer; - - (MAPIStoreObject *) container; - (void) cleanupCaches; - (uint64_t) objectId; -- (NSString *) url; /* implemented getters */ - (int) getPidTagDisplayName: (void **) data diff --git a/OpenChange/MAPIStoreSOGoObject.m b/OpenChange/MAPIStoreSOGoObject.m index d2d3b4790..421337505 100644 --- a/OpenChange/MAPIStoreSOGoObject.m +++ b/OpenChange/MAPIStoreSOGoObject.m @@ -146,20 +146,6 @@ static Class MAPIStoreFolderK; return objectId; } -- (NSString *) url -{ - NSString *containerURL, *format; - - containerURL = (NSString *) [container url]; - if ([containerURL hasSuffix: @"/"]) - format = @"%@%@"; - else - format = @"%@/%@"; - - return [NSString stringWithFormat: format, - containerURL, [self nameInContainer]]; -} - /* getters */ - (int) getPidTagDisplayName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx From 7ec5e22f9d48a646a2b6bfc4c397b904cb130d12 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 20 Jul 2012 06:53:01 +0000 Subject: [PATCH 030/127] Monotone-Parent: 44c81c0fbde1cf04e0ee2064fd07a4e6b1e74fcb Monotone-Revision: 0bab258b30947c4b34f1e39acd0a61b7954c9958 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-20T06:53:01 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreObject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreObject.h b/OpenChange/MAPIStoreObject.h index e0deb91ed..ddb28ada0 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -91,7 +91,7 @@ inMemCtx: (TALLOC_CTX *) memCtx; /* subclasses */ -- (NSString *) nameInContainer +- (NSString *) nameInContainer; - (NSDate *) creationTime; - (NSDate *) lastModificationTime; From 2d132678cfa58f95b4c48d3734a902a8e9d90eb9 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 20 Jul 2012 14:08:03 +0000 Subject: [PATCH 031/127] Monotone-Parent: 0bab258b30947c4b34f1e39acd0a61b7954c9958 Monotone-Revision: 3bf968de90811032a5b011cf48b3e8c402aa2425 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-20T14:08:03 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreTable.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreTable.m b/OpenChange/MAPIStoreTable.m index b47ce8a72..81a4e974e 100644 --- a/OpenChange/MAPIStoreTable.m +++ b/OpenChange/MAPIStoreTable.m @@ -841,8 +841,7 @@ static Class NSDataK, NSStringK; struct mapistore_property_data *rowData; int rc; - child = [self childAtRowID: rowId - forQueryType: queryType]; + child = [self childAtRowID: rowId forQueryType: queryType]; if (child) { rowData = talloc_array(memCtx, struct mapistore_property_data, columnsCount); From e55e89c496cb005137c6098c6df9b7e443702b20 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 20 Jul 2012 14:13:50 +0000 Subject: [PATCH 032/127] Monotone-Parent: 3bf968de90811032a5b011cf48b3e8c402aa2425 Monotone-Revision: d6049f3e55fa0ac4385db63c3777aa1d84d5511c Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-20T14:13:50 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 7 +++++++ OpenChange/MAPIStoreMessage.m | 22 ++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4acd03d55..04c5e2a2e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2012-07-20 Wolfgang Sourdeau + + * OpenChange/MAPIStoreMessage.m (-getPidTagSubject:inMemCtx:): now + compute the return value based on PidTagNormalizedSubject and + PidTagSubjectPrefix as PidTagSubject is never actually set from + the client. + 2012-07-19 Wolfgang Sourdeau * OpenChange/MAPIStoreObject.m (-nameInContainer): moved method diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index 0d42eb048..1618e00c8 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -706,21 +706,35 @@ rtf2html (NSData *compressedRTF) - (int) getPidTagSubject: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - [self subclassResponsibility: _cmd]; + int rc; + TALLOC_CTX *localMemCtx; + char *prefix, *normalizedSubject; - return MAPISTORE_ERR_NOT_FOUND; + localMemCtx = talloc_zero (NULL, TALLOC_CTX); + if ([self getProperty: (void **) &prefix + withTag: PidTagSubjectPrefix + inMemCtx: localMemCtx] + != MAPISTORE_SUCCESS) + prefix = ""; + rc = [self getProperty: (void **) &normalizedSubject + withTag: PidTagNormalizedSubject + inMemCtx: localMemCtx]; + if (rc == MAPISTORE_SUCCESS) + *data = talloc_asprintf (memCtx, "%s%s", prefix, normalizedSubject); + + return rc; } - (int) getPidTagNormalizedSubject: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidTagSubject: data inMemCtx: memCtx]; + return MAPISTORE_ERR_NOT_FOUND; } - (int) getPidTagOriginalSubject: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidTagNormalizedSubject: data inMemCtx: memCtx]; + return [self getPidTagSubject: data inMemCtx: memCtx]; } - (int) getPidTagConversationTopic: (void **) data From 7bb437021aa300a08e78108bf04973b94fb42828 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 20 Jul 2012 14:13:56 +0000 Subject: [PATCH 033/127] Monotone-Parent: d6049f3e55fa0ac4385db63c3777aa1d84d5511c Monotone-Revision: 3fdbf80f4c1de08138ff9435f54fd9f663ef5b8f Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-20T14:13:56 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreAppointmentWrapper.h | 4 ++-- OpenChange/MAPIStoreAppointmentWrapper.m | 4 ++-- OpenChange/MAPIStoreContactsMessage.m | 4 ++-- OpenChange/MAPIStoreDBMessage.m | 17 ----------------- OpenChange/MAPIStoreMailMessage.m | 13 ------------- OpenChange/MAPIStoreMailVolatileMessage.m | 7 ------- OpenChange/MAPIStoreTasksMessage.m | 4 ++-- 7 files changed, 8 insertions(+), 45 deletions(-) diff --git a/OpenChange/MAPIStoreAppointmentWrapper.h b/OpenChange/MAPIStoreAppointmentWrapper.h index bb766bf1f..ba3377965 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.h +++ b/OpenChange/MAPIStoreAppointmentWrapper.h @@ -121,8 +121,8 @@ inMemCtx: (TALLOC_CTX *) memCtx; - (int) getPidLidIndentedBusyStatus: (void **) data // TODO inMemCtx: (TALLOC_CTX *) memCtx; -- (int) getPidTagSubject: (void **) data // SUMMARY - inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidTagNormalizedSubject: (void **) data // SUMMARY + inMemCtx: (TALLOC_CTX *) memCtx; - (int) getPidLidLocation: (void **) data // LOCATION inMemCtx: (TALLOC_CTX *) memCtx; - (int) getPidLidPrivate: (void **) data // private (bool), should depend on CLASS and permissions diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index d306e3c8f..e813287c8 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -963,8 +963,8 @@ static NSCharacterSet *hexCharacterSet = nil; return [self getPidLidBusyStatus: data inMemCtx: memCtx]; } -- (int) getPidTagSubject: (void **) data // SUMMARY - inMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidTagNormalizedSubject: (void **) data // SUMMARY + inMemCtx: (TALLOC_CTX *) memCtx { *data = [[event summary] asUnicodeInMemCtx: memCtx]; diff --git a/OpenChange/MAPIStoreContactsMessage.m b/OpenChange/MAPIStoreContactsMessage.m index 99f297ea1..bc8d3a6d4 100644 --- a/OpenChange/MAPIStoreContactsMessage.m +++ b/OpenChange/MAPIStoreContactsMessage.m @@ -180,8 +180,8 @@ return MAPISTORE_SUCCESS; } -- (int) getPidTagSubject: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidTagNormalizedSubject: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { return [self getPidTagDisplayName: data inMemCtx: memCtx]; } diff --git a/OpenChange/MAPIStoreDBMessage.m b/OpenChange/MAPIStoreDBMessage.m index e8610de45..3ea3704d0 100644 --- a/OpenChange/MAPIStoreDBMessage.m +++ b/OpenChange/MAPIStoreDBMessage.m @@ -127,23 +127,6 @@ return rc; } -- (int) getPidTagSubject: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - id value; - int rc; - - value = [properties - objectForKey: MAPIPropertyKey (PidTagNormalizedSubject)]; - if (value) - rc = [value getValue: data forTag: PidTagNormalizedSubject - inMemCtx: memCtx]; - else - rc = MAPISTORE_ERR_NOT_FOUND; - - return rc; -} - - (void) addProperties: (NSDictionary *) newNewProperties { [sogoObject reloadIfNeeded]; diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 8e8070ae2..d035810ac 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -448,19 +448,6 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) return MAPISTORE_SUCCESS; } -- (int) getPidTagSubject: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - NSString *stringValue; - - stringValue = [self subject]; - if (!stringValue) - stringValue = @""; - *data = [stringValue asUnicodeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - - (int) getPidTagSubjectPrefix: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index b3bb2145f..ec33c54dd 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -285,13 +285,6 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" }; : ULLONG_MAX); } -- (int) getPidTagSubject: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - /* if we get here, it means that the properties file didn't contain a - relevant value */ - return [self getEmptyString: data inMemCtx: memCtx]; -} - - (int) getPidTagMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { *data = [@"IPM.Note" asUnicodeInMemCtx: memCtx]; diff --git a/OpenChange/MAPIStoreTasksMessage.m b/OpenChange/MAPIStoreTasksMessage.m index e1a5a9df4..08b580085 100644 --- a/OpenChange/MAPIStoreTasksMessage.m +++ b/OpenChange/MAPIStoreTasksMessage.m @@ -91,8 +91,8 @@ return MAPISTORE_SUCCESS; } -- (int) getPidTagSubject: (void **) data // SUMMARY - inMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidTagNormalizedSubject: (void **) data // SUMMARY + inMemCtx: (TALLOC_CTX *) memCtx { iCalToDo *task; From 63c2d62b0bc5879e23cd09371872396f6bb78556 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 20 Jul 2012 14:36:05 +0000 Subject: [PATCH 034/127] Monotone-Parent: 3fdbf80f4c1de08138ff9435f54fd9f663ef5b8f Monotone-Revision: 3bc92406543042dce09f1c096eb8a19107b42eb2 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-20T14:36:05 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 12 ++++++++++++ OpenChange/MAPIStoreCalendarMessage.m | 16 ++++++++++++++++ OpenChange/MAPIStoreObject.m | 13 +++++++++++-- OpenChange/NSObject+MAPIStore.h | 3 +++ OpenChange/NSObject+MAPIStore.m | 24 ++++++++++++++++++++++++ 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 04c5e2a2e..eca66124c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,17 @@ 2012-07-20 Wolfgang Sourdeau + * OpenChange/NSObject+MAPIStore.m + (+fillAvailableProperties:withExclusions:): new method that fills + an existing array of properties with properties existing in + another class, as long as they are not listed in the array of + exclusions. + + * OpenChange/MAPIStoreObject.m (-init): assigned a mutable array + to "proxies" + (-canGetProperty:): test the proxies for the availability of + properties so that -getAvailableProperties:inMemCtx: can return an + accurate result. + * OpenChange/MAPIStoreMessage.m (-getPidTagSubject:inMemCtx:): now compute the return value based on PidTagNormalizedSubject and PidTagSubjectPrefix as PidTagSubject is never actually set from diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index a4b4b33ca..904887098 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -87,6 +87,22 @@ @implementation MAPIStoreCalendarMessage ++ (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP + inMemCtx: (TALLOC_CTX *) memCtx +{ + BOOL listedProperties[65536]; + NSUInteger count; + + memset (listedProperties, NO, 65536 * sizeof (BOOL)); + [super getAvailableProperties: propertiesP inMemCtx: memCtx]; + for (count = 0; count < (*propertiesP)->cValues; count++) + listedProperties[(*propertiesP)->aulPropTag[count] >> 16] = YES; + [MAPIStoreAppointmentWrapper fillAvailableProperties: *propertiesP + withExclusions: listedProperties]; + + return MAPISTORE_SUCCESS; +} + - (id) initWithSOGoObject: (id) newSOGoObject inContainer: (MAPIStoreObject *) newFolder { diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index 0204f3a2d..eba69c966 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -76,6 +76,7 @@ static Class NSExceptionK, MAPIStoreFolderK; parentContainersBag = [NSMutableArray new]; container = nil; properties = [NSMutableDictionary new]; + proxies = [NSMutableArray new]; } // [self logWithFormat: @"-init"]; @@ -96,6 +97,7 @@ static Class NSExceptionK, MAPIStoreFolderK; - (void) dealloc { // [self logWithFormat: @"-dealloc"]; + [proxies release]; [properties release]; [parentContainersBag release]; [container release]; @@ -203,11 +205,18 @@ static Class NSExceptionK, MAPIStoreFolderK; - (BOOL) canGetProperty: (enum MAPITAGS) propTag { uint16_t propValue; + BOOL canGetProperty; + NSUInteger count, max; propValue = (propTag & 0xffff0000) >> 16; - return (classGetters[propValue] - || [properties objectForKey: MAPIPropertyKey (propTag)]); + canGetProperty = (classGetters[propValue] + || [properties objectForKey: MAPIPropertyKey (propTag)]); + max = [proxies count]; + for (count = 0; !canGetProperty && count < max; count++) + canGetProperty = [[proxies objectAtIndex: count] canGetProperty: propTag]; + + return canGetProperty; } - (int) getProperties: (struct mapistore_property_data *) data diff --git a/OpenChange/NSObject+MAPIStore.h b/OpenChange/NSObject+MAPIStore.h index c5c95c26c..e73a983a0 100644 --- a/OpenChange/NSObject+MAPIStore.h +++ b/OpenChange/NSObject+MAPIStore.h @@ -63,6 +63,9 @@ struct MAPIStoreTallocWrapper + (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP inMemCtx: (TALLOC_CTX *) memCtx; ++ (void) fillAvailableProperties: (struct SPropTagArray *) properties + withExclusions: (BOOL *) exclusions; + - (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP inMemCtx: (TALLOC_CTX *) memCtx; - (BOOL) canGetProperty: (enum MAPITAGS) propTag; diff --git a/OpenChange/NSObject+MAPIStore.m b/OpenChange/NSObject+MAPIStore.m index a25a65758..2c35521b3 100644 --- a/OpenChange/NSObject+MAPIStore.m +++ b/OpenChange/NSObject+MAPIStore.m @@ -201,6 +201,30 @@ MAPIStoreTallocWrapperDestroy (void *data) return MAPISTORE_SUCCESS; } ++ (void) fillAvailableProperties: (struct SPropTagArray *) properties + withExclusions: (BOOL *) exclusions +{ + TALLOC_CTX *localMemCtx; + struct SPropTagArray *subProperties; + uint16_t propId; + NSUInteger count; + + localMemCtx = talloc_zero (NULL, TALLOC_CTX); + [self getAvailableProperties: &subProperties inMemCtx: localMemCtx]; + for (count = 0; count < subProperties->cValues; count++) + { + propId = (subProperties->aulPropTag[count] >> 16); + if (!exclusions[propId]) + { + properties->aulPropTag[properties->cValues] + = subProperties->aulPropTag[count]; + properties->cValues++; + exclusions[propId] = YES; + } + } + talloc_free (localMemCtx); +} + - (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP inMemCtx: (TALLOC_CTX *) memCtx { From 649b6fb90ff62a6b87e30eb89fb06451fbe365db Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 20 Jul 2012 15:21:11 +0000 Subject: [PATCH 035/127] Monotone-Parent: 3bc92406543042dce09f1c096eb8a19107b42eb2 Monotone-Revision: 0a2c134a89861c564e6bc97bf789ca4a39adcf4a Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-20T15:21:11 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 3 ++ OpenChange/MAPIStoreAttachment.h | 4 ++- OpenChange/MAPIStoreAttachment.m | 43 ++++++++++++++---------- OpenChange/MAPIStoreEmbeddedMessage.h | 7 ---- OpenChange/MAPIStoreEmbeddedMessage.m | 43 ++++++++++++++++-------- OpenChange/MAPIStoreSOGo.m | 47 ++++++++++++++++++++++++--- 6 files changed, 103 insertions(+), 44 deletions(-) diff --git a/ChangeLog b/ChangeLog index eca66124c..e11f32d66 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2012-07-20 Wolfgang Sourdeau + * OpenChange/MAPIStoreSOGo.m + (sogo_message_attachment_create_embedded_message): new backend method. + * OpenChange/NSObject+MAPIStore.m (+fillAvailableProperties:withExclusions:): new method that fills an existing array of properties with properties existing in diff --git a/OpenChange/MAPIStoreAttachment.h b/OpenChange/MAPIStoreAttachment.h index 1d4576572..76afd8539 100644 --- a/OpenChange/MAPIStoreAttachment.h +++ b/OpenChange/MAPIStoreAttachment.h @@ -37,10 +37,12 @@ - (uint32_t) AID; - (int) openEmbeddedMessage: (MAPIStoreEmbeddedMessage **) messagePtr - inMode: (enum OpenEmbeddedMessage_OpenModeFlags) mode withMID: (uint64_t *) mid withMAPIStoreMsg: (struct mapistore_message **) mapistoreMsgPtr inMemCtx: (TALLOC_CTX *) memCtx; +- (int) createEmbeddedMessage: (MAPIStoreEmbeddedMessage **) messagePtr + withMAPIStoreMsg: (struct mapistore_message **) mapistoreMsgPtr + inMemCtx: (TALLOC_CTX *) memCtx; /* helpers */ - (NSData *) mimeAttachTag; diff --git a/OpenChange/MAPIStoreAttachment.m b/OpenChange/MAPIStoreAttachment.m index 86944436b..9e1551eb0 100644 --- a/OpenChange/MAPIStoreAttachment.m +++ b/OpenChange/MAPIStoreAttachment.m @@ -91,7 +91,6 @@ } - (int) openEmbeddedMessage: (MAPIStoreEmbeddedMessage **) messagePtr - inMode: (enum OpenEmbeddedMessage_OpenModeFlags) mode withMID: (uint64_t *) mid withMAPIStoreMsg: (struct mapistore_message **) mapistoreMsgPtr inMemCtx: (TALLOC_CTX *) memCtx @@ -104,24 +103,34 @@ mapping = [self mapping]; - if (mode == MAPI_CREATE) - attMessage = [self createEmbeddedMessage]; - else + // if (attMessage) + attMessage = [self openEmbeddedMessage]; + if (attMessage) { - // if (attMessage) - // [mapping registerURL: [attMessage url] - // withID: *mid]; - attMessage = [self openEmbeddedMessage]; - if (attMessage) - { - *mid = [mapping idFromURL: [attMessage url]]; - *messagePtr = attMessage; - *mapistoreMsgPtr = mapistoreMsg; - } + *mid = [mapping idFromURL: [attMessage url]]; + [mapping registerURL: [attMessage url] + withID: *mid]; + *messagePtr = attMessage; + *mapistoreMsgPtr = mapistoreMsg; + } + + return (attMessage ? MAPISTORE_SUCCESS : MAPISTORE_ERROR); +} + +- (int) createEmbeddedMessage: (MAPIStoreEmbeddedMessage **) messagePtr + withMAPIStoreMsg: (struct mapistore_message **) mapistoreMsgPtr + inMemCtx: (TALLOC_CTX *) memCtx +{ + MAPIStoreEmbeddedMessage *attMessage; + struct mapistore_message *mapistoreMsg; + + mapistoreMsg = talloc_zero (memCtx, struct mapistore_message); + attMessage = [self createEmbeddedMessage]; + if (attMessage) + { + *messagePtr = attMessage; + *mapistoreMsgPtr = mapistoreMsg; } - // else if (flags == MAPI_CREATE) - // { - // } return (attMessage ? MAPISTORE_SUCCESS : MAPISTORE_ERROR); } diff --git a/OpenChange/MAPIStoreEmbeddedMessage.h b/OpenChange/MAPIStoreEmbeddedMessage.h index 431f60e80..62c9431ba 100644 --- a/OpenChange/MAPIStoreEmbeddedMessage.h +++ b/OpenChange/MAPIStoreEmbeddedMessage.h @@ -26,13 +26,6 @@ #import "MAPIStoreMessage.h" @interface MAPIStoreEmbeddedMessage : MAPIStoreMessage -{ - id attachment; -} - -+ (id) embeddedMessageWithAttachment: (id) newAttachment; - -- (id) initWithAttachment: (id) newAttachment; @end diff --git a/OpenChange/MAPIStoreEmbeddedMessage.m b/OpenChange/MAPIStoreEmbeddedMessage.m index fe0e28105..63f093095 100644 --- a/OpenChange/MAPIStoreEmbeddedMessage.m +++ b/OpenChange/MAPIStoreEmbeddedMessage.m @@ -26,6 +26,8 @@ #import "MAPIStoreEmbeddedMessage.h" +#include + static Class MAPIStoreAttachmentK; @implementation MAPIStoreEmbeddedMessage @@ -35,25 +37,28 @@ static Class MAPIStoreAttachmentK; MAPIStoreAttachmentK = [MAPIStoreAttachment class]; } -+ (id) embeddedMessageWithAttachment: (id) newAttachment +- (int) getPidTagFolderId: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { - MAPIStoreEmbeddedMessage *newMessage; - - newMessage = [[self alloc] initWithAttachment: newAttachment]; - [newMessage autorelease]; - - return newMessage; + return MAPISTORE_ERR_NOT_FOUND; } -- (id) initWithAttachment: (id) newAttachment +- (int) getPidTagChangeKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { - if ((self = [self init])) - { - if ([newAttachment isKindOfClass: MAPIStoreAttachmentK]) - ASSIGN (container, newAttachment); - } + return MAPISTORE_ERR_NOT_FOUND; +} - return self; +- (int) getPidTagParentSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagChangeNumber: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; } - (NSString *) nameInContainer @@ -61,4 +66,14 @@ static Class MAPIStoreAttachmentK; return @"as-message"; } +- (uint64_t) objectVersion +{ + return ULLONG_MAX; +} + +- (void) save +{ + [self subclassResponsibility: _cmd]; +} + @end diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index d7ba5c387..2dd78074b 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -962,10 +962,11 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags) } static enum mapistore_error -sogo_message_attachment_open_embedded_message -(void *attachment_object, enum OpenEmbeddedMessage_OpenModeFlags mode, - TALLOC_CTX *mem_ctx, void **message_object, uint64_t *midP, - struct mapistore_message **msg) +sogo_message_attachment_open_embedded_message (void *attachment_object, + TALLOC_CTX *mem_ctx, + void **message_object, + uint64_t *midP, + struct mapistore_message **msg) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; @@ -982,7 +983,6 @@ sogo_message_attachment_open_embedded_message GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [attachment openEmbeddedMessage: &message - inMode: mode withMID: midP withMAPIStoreMsg: msg inMemCtx: mem_ctx]; @@ -999,6 +999,42 @@ sogo_message_attachment_open_embedded_message return rc; } +static enum mapistore_error +sogo_message_attachment_create_embedded_message (void *attachment_object, + TALLOC_CTX *mem_ctx, + void **message_object, + struct mapistore_message **msg) +{ + struct MAPIStoreTallocWrapper *wrapper; + NSAutoreleasePool *pool; + MAPIStoreAttachment *attachment; + MAPIStoreEmbeddedMessage *message; + int rc; + + DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + + if (attachment_object) + { + wrapper = attachment_object; + attachment = wrapper->instance; + GSRegisterCurrentThread (); + pool = [NSAutoreleasePool new]; + rc = [attachment createEmbeddedMessage: &message + withMAPIStoreMsg: msg + inMemCtx: mem_ctx]; + if (rc == MAPISTORE_SUCCESS) + *message_object = [message tallocWrapper: mem_ctx]; + [pool release]; + GSUnregisterCurrentThread (); + } + else + { + rc = sogo_backend_unexpected_error(); + } + + return rc; +} + static enum mapistore_error sogo_table_get_available_properties(void *table_object, TALLOC_CTX *mem_ctx, struct SPropTagArray **propertiesP) { @@ -1386,6 +1422,7 @@ int mapistore_init_backend(void) backend.message.get_attachment_table = sogo_message_get_attachment_table; backend.message.open_attachment = sogo_message_open_attachment; backend.message.open_embedded_message = sogo_message_attachment_open_embedded_message; + backend.message.create_embedded_message = sogo_message_attachment_create_embedded_message; backend.message.get_message_data = sogo_message_get_message_data; backend.message.modify_recipients = sogo_message_modify_recipients; backend.message.set_read_flag = sogo_message_set_read_flag; From 3b745879eba23d40d7e138aa9f689ff01895a747 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 20 Jul 2012 15:26:15 +0000 Subject: [PATCH 036/127] Monotone-Parent: 0a2c134a89861c564e6bc97bf789ca4a39adcf4a Monotone-Revision: 3a6e0507a35f90e7be4467763bd26ef4fb15cf80 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-20T15:26:15 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 3 +++ OpenChange/MAPIStoreMessage.h | 3 --- OpenChange/MAPIStoreMessage.m | 8 -------- OpenChange/NSObject+MAPIStore.h | 1 + OpenChange/NSObject+MAPIStore.m | 7 +++++++ 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index e11f32d66..863a0a4a6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2012-07-20 Wolfgang Sourdeau + * OpenChange/NSObject+MAPIStore.m (-getSMTPAddrType:inMemCtx:): + new helper getter. + * OpenChange/MAPIStoreSOGo.m (sogo_message_attachment_create_embedded_message): new backend method. diff --git a/OpenChange/MAPIStoreMessage.h b/OpenChange/MAPIStoreMessage.h index b7ba24ae7..51fa56ec3 100644 --- a/OpenChange/MAPIStoreMessage.h +++ b/OpenChange/MAPIStoreMessage.h @@ -66,9 +66,6 @@ - (int) setReadFlag: (uint8_t) flag; - (enum mapistore_error) saveMessage; -/* helper getters */ -- (int) getSMTPAddrType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; - (NSArray *) activeContainerMessageTables; - (NSArray *) activeUserRoles; diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index 1618e00c8..957cf8789 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -505,14 +505,6 @@ rtf2html (NSData *compressedRTF) return rc; } -/* helper getters */ -- (int) getSMTPAddrType: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - *data = [@"SMTP" asUnicodeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - /* getters */ - (int) getPidTagInstID: (void **) data // TODO: DOUBT inMemCtx: (TALLOC_CTX *) memCtx diff --git a/OpenChange/NSObject+MAPIStore.h b/OpenChange/NSObject+MAPIStore.h index e73a983a0..8e992f958 100644 --- a/OpenChange/NSObject+MAPIStore.h +++ b/OpenChange/NSObject+MAPIStore.h @@ -50,6 +50,7 @@ struct MAPIStoreTallocWrapper - (int) getLongZero: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; - (int) getYes: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; - (int) getNo: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getSMTPAddrType: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; @end diff --git a/OpenChange/NSObject+MAPIStore.m b/OpenChange/NSObject+MAPIStore.m index 2c35521b3..7eb14a768 100644 --- a/OpenChange/NSObject+MAPIStore.m +++ b/OpenChange/NSObject+MAPIStore.m @@ -168,6 +168,13 @@ MAPIStoreTallocWrapperDestroy (void *data) return MAPISTORE_SUCCESS; } +- (int) getSMTPAddrType: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [@"SMTP" asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + @end @implementation NSObject (MAPIStoreProperties) From 965cd9379e90fba9f2e1ff5e1f6e77e09ae1c0f8 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 20 Jul 2012 15:42:52 +0000 Subject: [PATCH 037/127] Monotone-Parent: 3a6e0507a35f90e7be4467763bd26ef4fb15cf80 Monotone-Revision: 5b4e61e92b3d68b92ea25f1513eb120e502250a1 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-20T15:42:52 Monotone-Branch: ca.inverse.sogo --- OpenChange/GNUmakefile | 7 +- OpenChange/MAPIStoreAppointmentWrapper.m | 117 +++- OpenChange/MAPIStoreCalendarAttachment.h | 10 +- OpenChange/MAPIStoreCalendarAttachment.m | 56 +- OpenChange/MAPIStoreCalendarEmbeddedMessage.h | 34 ++ OpenChange/MAPIStoreCalendarEmbeddedMessage.m | 162 ++++++ OpenChange/MAPIStoreCalendarMessage.h | 6 + OpenChange/MAPIStoreCalendarMessage.m | 527 ++---------------- OpenChange/iCalEvent+MAPIStore.h | 41 ++ OpenChange/iCalEvent+MAPIStore.m | 523 +++++++++++++++++ 10 files changed, 980 insertions(+), 503 deletions(-) create mode 100644 OpenChange/MAPIStoreCalendarEmbeddedMessage.h create mode 100644 OpenChange/MAPIStoreCalendarEmbeddedMessage.m create mode 100644 OpenChange/iCalEvent+MAPIStore.h create mode 100644 OpenChange/iCalEvent+MAPIStore.m diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 7054f8998..91b75ec0e 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -80,6 +80,7 @@ $(SOGOBACKEND)_OBJC_FILES += \ MAPIStoreCalendarContext.m \ MAPIStoreCalendarFolder.m \ MAPIStoreCalendarMessage.m \ + MAPIStoreCalendarEmbeddedMessage.m \ MAPIStoreCalendarMessageTable.m \ MAPIStoreRecurrenceUtils.m \ \ @@ -114,11 +115,13 @@ $(SOGOBACKEND)_OBJC_FILES += \ NSString+MAPIStore.m \ NSValue+MAPIStore.m \ \ - EOBitmaskQualifier.m \ + iCalEvent+MAPIStore.m \ \ GCSSpecialQueries+OpenChange.m\ \ - EOQualifier+MAPI.m + EOQualifier+MAPI.m \ + \ + EOBitmaskQualifier.m $(SOGOBACKEND)_RESOURCE_FILES += \ diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index e813287c8..c6c707694 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -1,6 +1,6 @@ /* MAPIStoreAppointmentWrapper.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011, 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -26,6 +26,7 @@ #import #import #import +#import #import #import #import @@ -432,7 +433,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagIconIndex: (void **) data // TODO - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { uint32_t longValue; @@ -855,6 +856,31 @@ static NSCharacterSet *hexCharacterSet = nil; inMemCtx: memCtx]; } +/* sender representing */ +- (int) getPidTagSentRepresentingEmailAddress: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidTagSenderEmailAddress: data inMemCtx: memCtx]; +} + +- (int) getPidTagSentRepresentingAddressType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getSMTPAddrType: data inMemCtx: memCtx]; +} + +- (int) getPidTagSentRepresentingName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidTagSenderName: data inMemCtx: memCtx]; +} + +- (int) getPidTagSentRepresentingEntryId: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidTagSenderEntryId: data inMemCtx: memCtx]; +} + /* attendee */ - (int) getPidTagReceivedByEmailAddress: (void **) data inMemCtx: (TALLOC_CTX *) memCtx @@ -1057,14 +1083,6 @@ static NSCharacterSet *hexCharacterSet = nil; return rc; } -- (int) getPidLidIsRecurring: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - *data = MAPIBoolValue (memCtx, [event isRecurrent]); - - return MAPISTORE_SUCCESS; -} - - (int) getPidLidRecurring: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -1073,15 +1091,57 @@ static NSCharacterSet *hexCharacterSet = nil; return MAPISTORE_SUCCESS; } -- (struct SBinary_short *) _computeAppointmentRecurInMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidLidIsRecurring: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = MAPIBoolValue (memCtx, + [event isRecurrent] + || ([event recurrenceId] != nil)); + return MAPISTORE_SUCCESS; +} + +- (int) getPidLidIsException: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = MAPIBoolValue (memCtx, [event recurrenceId] != nil); + + return MAPISTORE_SUCCESS; +} + +- (void) _fillExceptionInfo: (struct ExceptionInfo *) exceptionInfo + withException: (iCalEvent *) exceptionEvent +{ + memset (exceptionInfo, 0, sizeof (struct ExceptionInfo)); + exceptionInfo->OverrideFlags = 0; + exceptionInfo->StartDateTime = [[exceptionEvent startDate] asMinutesSince1601]; + exceptionInfo->EndDateTime = [[exceptionEvent endDate] asMinutesSince1601]; + exceptionInfo->OriginalStartDate = [[[exceptionEvent recurrenceId] hour: 0 + minute: 0 + second: 0] + asMinutesSince1601]; +} + +- (void) _fillExtendedException: (struct ExtendedException *) extendedException + withException: (iCalEvent *) exceptionEvent +{ + memset (extendedException, 0, sizeof (struct ExtendedException)); + extendedException->ChangeHighlight.Size = sizeof (uint32_t); + extendedException->ChangeHighlight.Value = 1 << 31 | 1 << 30; +} + +// - (struct SBinary_short *) _computeAppointmentRecurInMemCtx: (TALLOC_CTX *) memCtx +- (struct Binary_r *) _computeAppointmentRecurInMemCtx: (TALLOC_CTX *) memCtx { struct AppointmentRecurrencePattern *arp; struct Binary_r *bin; - struct SBinary_short *sBin; + // struct SBinary_short *sBin; NSCalendarDate *firstStartDate; iCalRecurrenceRule *rule; NSUInteger startMinutes; + NSArray *events, *exceptions; + iCalEvent *exceptionEvent; + NSUInteger count, max; rule = [[event recurrenceRules] objectAtIndex: 0]; @@ -1090,7 +1150,7 @@ static NSCharacterSet *hexCharacterSet = nil; { [firstStartDate setTimeZone: timeZone]; - arp = talloc_zero (memCtx, struct AppointmentRecurrencePattern); + arp = talloc_zero (NULL, struct AppointmentRecurrencePattern); [rule fillRecurrencePattern: &arp->RecurrencePattern withEvent: event inTimeZone: timeZone @@ -1105,17 +1165,31 @@ static NSCharacterSet *hexCharacterSet = nil; + (NSUInteger) ([event durationAsTimeInterval] / 60)); - arp->ExceptionCount = 0; + events = [[event parent] events]; + exceptions + = [events subarrayWithRange: NSMakeRange (1, [events count] - 1)]; + max = [exceptions count]; + arp->ExceptionCount = max; + arp->ExceptionInfo = talloc_array (memCtx, struct ExceptionInfo, max); + arp->ExtendedException = talloc_array (memCtx, struct ExtendedException, max); + for (count = 0; count < max; count++) + { + exceptionEvent = [exceptions objectAtIndex: count]; + [self _fillExceptionInfo: arp->ExceptionInfo + count + withException: exceptionEvent]; + [self _fillExtendedException: arp->ExtendedException + count + withException: exceptionEvent]; + } arp->ReservedBlock1Size = 0; + arp->ReservedBlock2Size = 0; /* Currently ignored in property.idl: arp->ReservedBlock2Size = 0; */ - /* convert struct to blob */ - sBin = talloc_zero (memCtx, struct SBinary_short); - bin = set_AppointmentRecurrencePattern (sBin, arp); - sBin->cb = bin->cb; - sBin->lpb = bin->lpb; + // sBin = talloc_zero (memCtx, struct SBinary_short); + bin = set_AppointmentRecurrencePattern (memCtx, arp); + // sBin->cb = bin->cb; + // sBin->lpb = bin->lpb; talloc_free (arp); // DEBUG(5, ("To client:\n")); @@ -1124,10 +1198,11 @@ static NSCharacterSet *hexCharacterSet = nil; else { [self errorWithFormat: @"no first occurrence found in rule: %@", rule]; - sBin = NULL; + // bin = NULL; + bin = NULL; } - return sBin; + return bin; } - (int) getPidLidAppointmentRecur: (void **) data diff --git a/OpenChange/MAPIStoreCalendarAttachment.h b/OpenChange/MAPIStoreCalendarAttachment.h index d95c3f560..c97f752d5 100644 --- a/OpenChange/MAPIStoreCalendarAttachment.h +++ b/OpenChange/MAPIStoreCalendarAttachment.h @@ -25,7 +25,15 @@ #import "MAPIStoreAttachment.h" -@interface MAPIStoreCalendarAttachment : MAPIStoreAttachment +@class iCalEvent; + +@interface MAPIStoreCalendarAttachment : MAPIStoreAttachment +{ + iCalEvent *event; +} + +- (void) setEvent: (iCalEvent *) newEvent; +- (iCalEvent *) event; @end diff --git a/OpenChange/MAPIStoreCalendarAttachment.m b/OpenChange/MAPIStoreCalendarAttachment.m index 1ba40ac17..a6d7848a2 100644 --- a/OpenChange/MAPIStoreCalendarAttachment.m +++ b/OpenChange/MAPIStoreCalendarAttachment.m @@ -20,9 +20,14 @@ * Boston, MA 02111-1307, USA. */ -#import "MAPIStoreTypes.h" +#import -#import "MAPIStoreEmbeddedMessage.h" +#import +#import + +#import "iCalEvent+MAPIStore.h" +#import "MAPIStoreTypes.h" +#import "MAPIStoreCalendarEmbeddedMessage.h" #import "MAPIStoreCalendarAttachment.h" @@ -34,6 +39,32 @@ @implementation MAPIStoreCalendarAttachment +- (id) init +{ + if ((self = [super init])) + { + event = nil; + } + + return self; +} + +- (void) dealloc +{ + [event release]; + [super dealloc]; +} + +- (void) setEvent: (iCalEvent *) newEvent +{ + ASSIGN (event, newEvent); +} + +- (iCalEvent *) event +{ + return event; +} + - (int) getPidTagAttachmentHidden: (void **) data inMemCtx: (TALLOC_CTX *) localMemCtx { @@ -53,7 +84,7 @@ - (int) getPidTagAttachMethod: (void **) data inMemCtx: (TALLOC_CTX *) localMemCtx { - *data = MAPILongValue (localMemCtx, 0x00000005); /* afEmbeddedMessage */ + *data = MAPILongValue (localMemCtx, afEmbeddedMessage); return MAPISTORE_SUCCESS; } @@ -63,21 +94,24 @@ // case PidTagExceptionReplaceTime: /* subclasses */ -- (MAPIStoreEmbeddedMessage *) openEmbeddedMessage +- (MAPIStoreCalendarEmbeddedMessage *) openEmbeddedMessage { - MAPIStoreEmbeddedMessage *msg; + MAPIStoreCalendarEmbeddedMessage *msg; - // if (isNew) - msg = nil; - // else - // msg = nil; + msg = [MAPIStoreCalendarEmbeddedMessage + mapiStoreObjectInContainer: self]; return msg; } -- (MAPIStoreEmbeddedMessage *) createEmbeddedMessage +- (MAPIStoreCalendarEmbeddedMessage *) createEmbeddedMessage { - return [MAPIStoreEmbeddedMessage embeddedMessageWithAttachment: self]; + MAPIStoreCalendarEmbeddedMessage *msg; + + msg = [self openEmbeddedMessage]; + [msg setIsNew: YES]; + + return msg; } @end diff --git a/OpenChange/MAPIStoreCalendarEmbeddedMessage.h b/OpenChange/MAPIStoreCalendarEmbeddedMessage.h new file mode 100644 index 000000000..3e27c575c --- /dev/null +++ b/OpenChange/MAPIStoreCalendarEmbeddedMessage.h @@ -0,0 +1,34 @@ +/* MAPIStoreCalendarEmbeddedMessage.h - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef MAPISTORECALENDAREMBEDDEDMESSAGE_H +#define MAPISTORECALENDAREMBEDDEDMESSAGE_H + +#import "MAPIStoreEmbeddedMessage.h" + +@class MAPIStoreAppointmentWrapper; + +@interface MAPIStoreCalendarEmbeddedMessage : MAPIStoreEmbeddedMessage + +@end + +#endif /* MAPISTORECALENDAREMBEDDEDMESSAGE_H */ diff --git a/OpenChange/MAPIStoreCalendarEmbeddedMessage.m b/OpenChange/MAPIStoreCalendarEmbeddedMessage.m new file mode 100644 index 000000000..361b10d6f --- /dev/null +++ b/OpenChange/MAPIStoreCalendarEmbeddedMessage.m @@ -0,0 +1,162 @@ +/* MAPIStoreCalendarEmbeddedMessage.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#import +#import + +#import + +#import +#import "iCalEvent+MAPIStore.h" + +#import "MAPIStoreAppointmentWrapper.h" +#import "MAPIStoreCalendarAttachment.h" +#import "MAPIStoreContext.h" +#import "MAPIStoreUserContext.h" +#import "MAPIStoreTypes.h" +#import "NSObject+MAPIStore.h" + +#import "MAPIStoreCalendarEmbeddedMessage.h" + +#include + +@implementation MAPIStoreCalendarEmbeddedMessage + +- (id) initInContainer: (id) newContainer +{ + MAPIStoreContext *context; + MAPIStoreUserContext *userContext; + MAPIStoreAppointmentWrapper *appointmentWrapper; + + if ((self = [super initInContainer: newContainer])) + { + context = [self context]; + userContext = [self userContext]; + appointmentWrapper + = [MAPIStoreAppointmentWrapper + wrapperWithICalEvent: [newContainer event] + andUser: [userContext sogoUser] + andSenderEmail: nil + inTimeZone: [userContext timeZone] + withConnectionInfo: [context connectionInfo]]; + [self addProxy: appointmentWrapper]; + } + + return self; +} + +- (NSDate *) creationTime +{ + return [[container event] created]; +} + +- (NSDate *) lastModificationTime +{ + return [[container event] lastModified]; +} + +- (void) getMessageData: (struct mapistore_message **) dataPtr + inMemCtx: (TALLOC_CTX *) memCtx +{ + struct mapistore_message *msgData; + + [super getMessageData: &msgData inMemCtx: memCtx]; + + /* HACK: we know the first (and only) proxy is our appointment wrapper + instance, but this might not always be true */ + [[proxies objectAtIndex: 0] fillMessageData: msgData + inMemCtx: memCtx]; + *dataPtr = msgData; +} + +- (int) getPidTagMessageClass: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = talloc_strdup (memCtx, "IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}"); + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagProcessed: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getYes: data inMemCtx: memCtx]; +} + +- (int) getPidTagResponseRequested: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getYes: data inMemCtx: memCtx]; +} + +- (void) save +{ +// (gdb) po embeddedMessage->properties +// 2442592320 = "2012-07-11 22:30:00 +0000"; +// 2448359488 = "2012-07-11 22:30:00 +0000"; +// 2442723392 = "2012-07-11 22:30:00 +0000"; +// 2442068032 = "2012-07-11 22:30:00 +0000"; +// 2441740352 = "2012-07-11 23:00:00 +0000"; +// 131083 = 1; 2442330115 = 2; +// 235339779 = 9; +// 6291520 = "2012-07-11 16:00:00 +0000"; +// 2442526784 = "2012-07-11 23:00:00 +0000"; +// 2818059 = 0; +// 1703967 = "IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}"; +// 3538947 = 0; +// 1071513603 = 28591; 805830720 = "2012-07-10 16:42:00 +0000"; +// 2485977346 = <02013000 02001500 45006100 73007400 +// 65007200 6e002000 53007400 61006e00 64006100 72006400 20005400 69006d00 +// 65000200 02013e00 0000d607 00000000 00000000 00000000 00002c01 00000000 +// 0000c4ff ffff0000 0a000000 05000200 00000000 00000000 04000000 01000200 +// 00000000 00000201 3e000200 d7070000 00000000 00000000 00000000 2c010000 +// 00000000 c4ffffff 00000b00 00000100 02000000 00000000 00000300 00000200 +// 02000000 00000000>; 2454257728 = "2012-07-11 16:00:00 +0000"; 2442985475 = +// 118330; 1507331 = 1; 805765184 = "2012-07-09 18:32:00 +0000"; 2442657856 = +// "2012-07-11 23:00:00 +0000"; 2443051039 = "11.0"; 236912651 = 1; 2485911810 = +// <02013000 02001500 45006100 73007400 65007200 6e002000 53007400 61006e00 +// 64006100 72006400 20005400 69006d00 65000200 02013e00 0000d607 00000000 +// 00000000 00000000 00002c01 00000000 0000c4ff ffff0000 0a000000 05000200 +// 00000000 00000000 04000000 01000200 00000000 00000201 3e000200 d7070000 +// 00000000 00000000 00000000 2c010000 00000000 c4ffffff 00000b00 00000100 +// 02000000 00000000 00000300 00000200 02000000 00000000>; 2441543683 = 30; +// 2442068032 = "2012-07-11 22:30:00 +0000"; +// 1073348639 = "OpenChange User"; +// 806027522 = <2d64f6f5 89a59243 992d29d1 49173b3a>; 6357056 = "2012-07-11 +// 16:30:00 +0000"; +// */ + +// // 0x92490040 = 2454257728 + +// } + + SOGoUser *activeUser; + + activeUser = [[self context] activeUser]; + + [[container event] updateFromMAPIProperties: properties + inUserContext: [self userContext] + withActiveUser: activeUser]; +} + +@end diff --git a/OpenChange/MAPIStoreCalendarMessage.h b/OpenChange/MAPIStoreCalendarMessage.h index ff942e6cf..a98149ac2 100644 --- a/OpenChange/MAPIStoreCalendarMessage.h +++ b/OpenChange/MAPIStoreCalendarMessage.h @@ -25,9 +25,15 @@ #import "MAPIStoreGCSMessage.h" +@class iCalCalendar; +@class iCalEvent; @class MAPIStoreAppointmentWrapper; @interface MAPIStoreCalendarMessage : MAPIStoreGCSMessage +{ + iCalCalendar *calendar; + iCalEvent *masterEvent; +} @end diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index 904887098..2ad110bbb 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -49,6 +49,7 @@ #import #import +#import "iCalEvent+MAPIStore.h" #import "MAPIStoreAppointmentWrapper.h" #import "MAPIStoreCalendarAttachment.h" #import "MAPIStoreCalendarFolder.h" @@ -103,32 +104,63 @@ return MAPISTORE_SUCCESS; } +- (id) init +{ + if ((self = [super init])) + { + calendar = nil; + masterEvent = nil; + } + + return self; +} + - (id) initWithSOGoObject: (id) newSOGoObject inContainer: (MAPIStoreObject *) newFolder { - iCalEvent *event; MAPIStoreContext *context; MAPIStoreUserContext *userContext; + iCalCalendar *origCalendar; MAPIStoreAppointmentWrapper *appointmentWrapper; - + if ((self = [super initWithSOGoObject: newSOGoObject inContainer: newFolder])) { - event = [sogoObject component: NO secure: YES]; + if ([newSOGoObject isNew]) + { + ASSIGN (calendar, [iCalCalendar groupWithTag: @"vcalendar"]); + [calendar setVersion: @"2.0"]; + [calendar setProdID: @"-//Inverse inc.//OpenChange+SOGo//EN"]; + masterEvent = [iCalEvent groupWithTag: @"vevent"]; + [calendar addChild: masterEvent]; + [masterEvent setCreated: [NSCalendarDate date]]; + } + else + { + origCalendar = [sogoObject calendar: YES secure: YES]; + calendar = [origCalendar mutableCopy]; + masterEvent = [[calendar events] objectAtIndex: 0]; + } context = [self context]; userContext = [self userContext]; appointmentWrapper - = [MAPIStoreAppointmentWrapper wrapperWithICalEvent: event + = [MAPIStoreAppointmentWrapper wrapperWithICalEvent: masterEvent andUser: [userContext sogoUser] andSenderEmail: nil inTimeZone: [userContext timeZone] withConnectionInfo: [context connectionInfo]]; [self addProxy: appointmentWrapper]; } - + return self; } +- (void) dealloc +{ + [calendar release]; + [super dealloc]; +} + /* getters */ - (int) getPidLidFInvited: (void **) data inMemCtx: (TALLOC_CTX *) memCtx @@ -177,6 +209,7 @@ instance, but this might not always be true */ [[proxies objectAtIndex: 0] fillMessageData: msgData inMemCtx: memCtx]; + *dataPtr = msgData; } @@ -209,28 +242,28 @@ // - (int) getPidTagReceivedByAddressType: (void **) data // inMemCtx: (TALLOC_CTX *) memCtx // { -// return [[self appointmentWrapper] getPidTagReceivedByAddressType: data +// return [appointmentWrapper getPidTagReceivedByAddressType: data // inMemCtx: memCtx]; // } // - (int) getPidTagReceivedByEmailAddress: (void **) data // inMemCtx: (TALLOC_CTX *) memCtx // { -// return [[self appointmentWrapper] getPidTagReceivedByEmailAddress: data +// return [appointmentWrapper getPidTagReceivedByEmailAddress: data // inMemCtx: memCtx]; // } // - (int) getPidTagReceivedByName: (void **) data // inMemCtx: (TALLOC_CTX *) memCtx // { -// return [[self appointmentWrapper] getPidTagReceivedByName: data +// return [appointmentWrapper getPidTagReceivedByName: data // inMemCtx: memCtx]; // } // - (int) getPidTagReceivedByEntryId: (void **) data // inMemCtx: (TALLOC_CTX *) memCtx // { -// return [[self appointmentWrapper] getPidTagReceivedByEntryId: data +// return [appointmentWrapper getPidTagReceivedByEntryId: data // inMemCtx: memCtx]; // } @@ -265,28 +298,6 @@ return [self getYes: data inMemCtx: memCtx]; } -/* attendee */ -- (void) _setupRecurrenceInCalendar: (iCalCalendar *) calendar - withEvent: (iCalEvent *) event - fromData: (NSData *) mapiRecurrenceData -{ - struct Binary_r *blob; - struct AppointmentRecurrencePattern *pattern; - NSMutableArray *otherEvents; - - /* cleanup */ - otherEvents = [[calendar events] mutableCopy]; - [otherEvents removeObject: event]; - [calendar removeChildren: otherEvents]; - [otherEvents release]; - - blob = [mapiRecurrenceData asBinaryInMemCtx: NULL]; - pattern = get_AppointmentRecurrencePattern (blob, blob); - [calendar setupRecurrenceWithMasterEntity: event - fromRecurrencePattern: &pattern->RecurrencePattern]; - talloc_free (blob); -} - - (NSString *) _uidFromGlobalObjectId { NSData *objectId; @@ -296,7 +307,8 @@ /* NOTE: we only handle the generic case at the moment, see MAPIStoreAppointmentWrapper */ - objectId = [properties objectForKey: MAPIPropertyKey (PidLidGlobalObjectId)]; + objectId = [properties + objectForKey: MAPIPropertyKey (PidLidGlobalObjectId)]; if (objectId) { length = [objectId length]; @@ -360,50 +372,6 @@ ASSIGN (sogoObject, newObject); } -- (void) _setupAlarmDataInEvent: (iCalEvent *) newEvent -{ - NSArray *alarms; - iCalAlarm *currentAlarm, *alarm = nil; - iCalTrigger *trigger; - NSNumber *delta; - NSString *action; - NSUInteger count, max; - - /* find and remove first display alarm */ - alarms = [newEvent alarms]; - max = [alarms count]; - for (count = 0; !alarm && count < max; count++) - { - currentAlarm = [alarms objectAtIndex: count]; - action = [[currentAlarm action] lowercaseString]; - if (!action || [action isEqualToString: @"display"]) - alarm = currentAlarm; - } - - if (alarm) - [newEvent removeChild: alarm]; - - if ([[properties objectForKey: MAPIPropertyKey (PidLidReminderSet)] - boolValue]) - { - delta - = [properties objectForKey: MAPIPropertyKey (PidLidReminderDelta)]; - if (delta) - { - alarm = [iCalAlarm new]; - [alarm setAction: @"DISPLAY"]; - trigger = [iCalTrigger elementWithTag: @"trigger"]; - [trigger setValueType: @"DURATION"]; - [trigger - setSingleValue: [NSString stringWithFormat: @"-PT%@M", delta] - forKey: @""]; - [alarm setTrigger: trigger]; - [newEvent addToAlarms: alarm]; - [alarm release]; - } - } -} - - (BOOL) subscriberCanReadMessage { NSArray *roles; @@ -429,20 +397,9 @@ return rc; } -- (void) save { - iCalCalendar *vCalendar; - BOOL isAllDay; - iCalDateTime *start, *end; - iCalTimeZone *tz; - NSCalendarDate *now; - NSString *uid, *content, *tzName, *priority, *newParticipationStatus = nil; iCalEvent *newEvent; // iCalPerson *userPerson; - NSUInteger responseStatus = 0; - NSInteger tzOffset; - SOGoUser *activeUser, *ownerUser; - id value; if (isNew) { @@ -450,397 +407,31 @@ if (uid) { /* Hack required because of what's explained in oxocal 3.1.4.7.1: - basically, Outlook creates a copy of the event and then removes the - old instance. We perform a trickery to avoid performing those - operations in the backend, in a way that enables us to recover the - initial instance and act solely on it. */ + basically, Outlook creates a copy of the event and then removes + the old instance. We perform a trickery to avoid performing those + operations in the backend, in a way that enables us to recover + the initial instance and act solely on it. */ [self _fixupAppointmentObjectWithUID: uid]; } else uid = [SOGoObject globallyUniqueObjectId]; + [masterEvent setUid: uid]; + [sogoObject setNameInContainer: + [NSString stringWithFormat: @"%@.ics", uid]]; } - [self logWithFormat: @"-save, event props:"]; + // [self logWithFormat: @"-save, event props:"]; // MAPIStoreDumpMessageProperties (newProperties); - now = [NSCalendarDate date]; + // now = [NSCalendarDate date]; - content = [sogoObject contentAsString]; - if (![content length]) - { - newEvent = [sogoObject component: YES secure: NO]; - vCalendar = [newEvent parent]; - [vCalendar setProdID: @"-//Inverse inc.//OpenChange+SOGo//EN"]; - [newEvent setCreated: now]; - // CREATED = PidTagCreationTime - value = [properties objectForKey: MAPIPropertyKey (PidTagCreationTime)]; - if (value) - [newEvent setCreated: value]; - [newEvent setUid: uid]; - content = [vCalendar versitString]; - } + activeUser = [[self context] activeUser]; + [masterEvent updateFromMAPIProperties: properties + inUserContext: [self userContext] + withActiveUser: activeUser]; + [sogoObject updateContentWithCalendar: calendar + fromRequest: nil]; - vCalendar = [iCalCalendar parseSingleFromSource: content]; - newEvent = [[vCalendar events] objectAtIndex: 0]; - - // DTSTAMP = PidLidOwnerCriticalChange or PidLidAttendeeCriticalChange - value = [properties objectForKey: MAPIPropertyKey (PidLidOwnerCriticalChange)]; - if (!value || [value isNever]) - value = now; - [newEvent setTimeStampAsDate: value]; - - // LAST-MODIFIED = PidTagLastModificationTime - value = [properties objectForKey: MAPIPropertyKey (PidTagLastModificationTime)]; - if (!value) - value = now; - [newEvent setLastModified: value]; - - // summary - value = [properties - objectForKey: MAPIPropertyKey (PR_NORMALIZED_SUBJECT_UNICODE)]; - if (value) - [newEvent setSummary: value]; - - // Location - value = [properties objectForKey: MAPIPropertyKey (PidLidLocation)]; - if (value) - [newEvent setLocation: value]; - - isAllDay = [newEvent isAllDay]; - value = [properties - objectForKey: MAPIPropertyKey (PidLidAppointmentSubType)]; - if (value) - isAllDay = [value boolValue]; - if (!isAllDay) - { - tzName = [[[self userContext] timeZone] name]; - tz = [iCalTimeZone timeZoneForName: tzName]; - [vCalendar addTimeZone: tz]; - } - else - tz = nil; - - // start - value = [properties objectForKey: MAPIPropertyKey (PR_START_DATE)]; - if (!value) - value = [properties - objectForKey: MAPIPropertyKey (PidLidAppointmentStartWhole)]; - if (value) - { - start = (iCalDateTime *) [newEvent uniqueChildWithTag: @"dtstart"]; - [start setTimeZone: tz]; - if (isAllDay) - { - [start setDate: value]; - [start setTimeZone: nil]; - } - else - { - tzOffset = [[value timeZone] secondsFromGMTForDate: value]; - value = [value dateByAddingYears: 0 months: 0 days: 0 - hours: 0 minutes: 0 - seconds: tzOffset]; - [start setDateTime: value]; - } - } - - /* end */ - value = [properties objectForKey: MAPIPropertyKey (PR_END_DATE)]; - if (!value) - value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentEndWhole)]; - if (value) - { - end = (iCalDateTime *) [newEvent uniqueChildWithTag: @"dtend"]; - [end setTimeZone: tz]; - if (isAllDay) - { - [end setDate: value]; - [end setTimeZone: nil]; - } - else - { - tzOffset = [[value timeZone] secondsFromGMTForDate: value]; - value = [value dateByAddingYears: 0 months: 0 days: 0 - hours: 0 minutes: 0 - seconds: tzOffset]; - [end setDateTime: value]; - } - } - - /* priority */ - value = [properties objectForKey: MAPIPropertyKey(PR_IMPORTANCE)]; - if (value) - { - switch ([value intValue]) - { - case 0: // IMPORTANCE_LOW - priority = @"9"; - break; - case 2: // IMPORTANCE_HIGH - priority = @"1"; - break; - default: // IMPORTANCE_NORMAL - priority = @"5"; - } - } - else - priority = @"0"; // None - [newEvent setPriority: priority]; - - /* show time as free/busy/tentative/out of office. Possible values are: - 0x00000000 - olFree - 0x00000001 - olTentative - 0x00000002 - olBusy - 0x00000003 - olOutOfOffice */ - value = [properties objectForKey: MAPIPropertyKey(PidLidBusyStatus)]; - if (value) - { - switch ([value intValue]) - { - case 0: - [newEvent setTransparency: @"TRANSPARENT"]; - break; - case 1: - case 2: - case 3: - default: - [newEvent setTransparency: @"OPAQUE"]; - } - } - - /* Comment */ - value = [properties objectForKey: MAPIPropertyKey (PR_BODY_UNICODE)]; - if (!value) - { - value = [properties objectForKey: MAPIPropertyKey (PR_HTML)]; - if (value) - { - value = [[NSString alloc] initWithData: value - encoding: NSUTF8StringEncoding]; - [value autorelease]; - value = [value htmlToText]; - } - } - if (value) - { - if ([value length] == 0 || [value isEqualToString: @"\\n"]) - value = nil; - [newEvent setComment: value]; - } - - /* recurrence */ - value = [properties - objectForKey: MAPIPropertyKey (PidLidAppointmentRecur)]; - if (value) - [self _setupRecurrenceInCalendar: vCalendar - withEvent: newEvent - fromData: value]; - - /* alarm */ - [self _setupAlarmDataInEvent: newEvent]; - - // Organizer - value = [properties objectForKey: @"recipients"]; - if (value) - { - NSArray *recipients; - NSDictionary *dict; - NSString *orgEmail, *sentBy, *attEmail; - iCalPerson *person; - iCalPersonPartStat newPartStat; - NSNumber *flags, *trackStatus; - int i, effective; - BOOL organizerIsSet = NO; - - [newEvent setOrganizer: nil]; - [newEvent removeAllAttendees]; - - recipients = [value objectForKey: @"to"]; - effective = 0; - for (i = 0; i < [recipients count]; i++) - { - dict = [recipients objectAtIndex: i]; - person = [iCalPerson new]; - [person setCn: [dict objectForKey: @"fullName"]]; - attEmail = [dict objectForKey: @"email"]; - [person setEmail: attEmail]; - - flags = [dict objectForKey: MAPIPropertyKey (PR_RECIPIENT_FLAGS)]; - if (!flags) - { - [self logWithFormat: - @"no recipient flags specified: skipping recipient"]; - continue; - } - - if (([flags unsignedIntValue] & 0x0002)) /* recipOrganizer */ - { - [newEvent setOrganizer: person]; - organizerIsSet = YES; - [self logWithFormat: @"organizer set via recipient flags"]; - } - else - { - BOOL isOrganizer = NO; - - // /* Work-around: it happens that Outlook still passes the - // organizer as a recipient, maybe because of a feature - // documented in a pre-mesozoic PDF still buried in a - // cavern... In that case we remove it, and we keep the - // number of effective recipients in "effective". If the - // total is 0, we remove the "ORGANIZER" too. */ - // if ([attEmail isEqualToString: orgEmail]) - // { - // [self logWithFormat: - // @"avoiding setting organizer as recipient"]; - // continue; - // } - - trackStatus = [dict objectForKey: MAPIPropertyKey (PidTagRecipientTrackStatus)]; - if (trackStatus) - { - /* FIXME: we should provide a data converter between OL - partstats and SOGo */ - switch ([trackStatus unsignedIntValue]) - { - case 0x01: /* respOrganized */ - isOrganizer = YES; - break; - case 0x02: /* respTentative */ - newPartStat = iCalPersonPartStatTentative; - break; - case 0x03: /* respAccepted */ - newPartStat = iCalPersonPartStatAccepted; - break; - case 0x04: /* respDeclined */ - newPartStat = iCalPersonPartStatDeclined; - break; - default: - newPartStat = iCalPersonPartStatNeedsAction; - } - - if (isOrganizer) - { - [newEvent setOrganizer: person]; - organizerIsSet = YES; - [self logWithFormat: @"organizer set via track status"]; - } - else - { - [person setParticipationStatus: newPartStat]; - [person setRsvp: @"TRUE"]; - [person setRole: @"REQ-PARTICIPANT"]; - [newEvent addToAttendees: person]; - effective++; - } - } - else - [self errorWithFormat: @"skipped recipient due" - @" to missing track status"]; - } - - [person release]; - } - - if (effective == 0) /* See work-around above */ - [newEvent setOrganizer: nil]; - else - { - // SEQUENCE = PidLidAppointmentSequence - value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentSequence)]; - if (value) - [newEvent setSequence: value]; - - ownerUser = [[self userContext] sogoUser]; - if (organizerIsSet) - { - /* We must reset the participation status to the value - obtained from PidLidResponseStatus as the value in - PidTagRecipientTrackStatus is not correct. Note (hack): - the method used here requires that the user directory - from LDAP and Samba matches perfectly. This can be solved - more appropriately by making use of the sender - properties... */ - person = [newEvent userAsAttendee: ownerUser]; - if (person) - { - value - = [properties objectForKey: MAPIPropertyKey (PidLidResponseStatus)]; - if (value) - responseStatus = [value unsignedLongValue]; - - /* FIXME: we should provide a data converter between OL partstats and - SOGo */ - switch (responseStatus) - { - case 0x02: /* respTentative */ - newPartStat = iCalPersonPartStatTentative; - break; - case 0x03: /* respAccepted */ - newPartStat = iCalPersonPartStatAccepted; - break; - case 0x04: /* respDeclined */ - newPartStat = iCalPersonPartStatDeclined; - break; - default: - newPartStat = iCalPersonPartStatNeedsAction; - } - [person setParticipationStatus: newPartStat]; - newParticipationStatus = [person partStatWithDefault]; - - value = [properties objectForKey: MAPIPropertyKey (PidLidAttendeeCriticalChange)]; - if (value && ![value isNever]) - [newEvent setTimeStampAsDate: value]; - // if (newPartStat // != iCalPersonPartStatUndefined - // ) - // { - // // iCalPerson *participant; - - // // participant = [newEvent userAsAttendee: ownerUser]; - // // [participant setParticipationStatus: newPartStat]; - // // [sogoObject saveComponent: newEvent]; - - // [sogoObject changeParticipationStatus: newPartStat - // withDelegate: nil]; - // // [[self context] tearDownRequest]; - // } - // // }1005 - - // // else - // // { - } - } - else - { - [self errorWithFormat: @"organizer was not set although a" - @" recipient list was specified"]; - /* We must set the organizer preliminarily here because, unlike what - the doc states, Outlook does not always pass the real organizer - in the recipients list. */ - dict = [ownerUser primaryIdentity]; - person = [iCalPerson new]; - [person setCn: [dict objectForKey: @"fullName"]]; - orgEmail = [dict objectForKey: @"email"]; - [person setEmail: orgEmail]; - - activeUser = [[self context] activeUser]; - if (![activeUser isEqual: ownerUser]) - { - dict = [activeUser primaryIdentity]; - sentBy = [NSString stringWithFormat: @"mailto:%@", - [dict objectForKey: @"email"]]; - [person setSentBy: sentBy]; - } - [newEvent setOrganizer: person]; - [person release]; - } - } - } - - [sogoObject saveComponent: newEvent]; - if (newParticipationStatus) - [sogoObject changeParticipationStatus: newParticipationStatus - withDelegate: nil]; [self updateVersions]; } diff --git a/OpenChange/iCalEvent+MAPIStore.h b/OpenChange/iCalEvent+MAPIStore.h new file mode 100644 index 000000000..171813e2b --- /dev/null +++ b/OpenChange/iCalEvent+MAPIStore.h @@ -0,0 +1,41 @@ +/* iCalEvent+MAPIStore.h - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef ICALEVENT_MAPISTORE_H +#define ICALEVENT_MAPISTORE_H + +#import + +@class MAPIStoreUserContext; +@class NSDictionary; +@class NSString; +@class SOGoUser; + +@interface iCalEvent (MAPIStoreProperties) + +- (void) updateFromMAPIProperties: (NSDictionary *) properties + inUserContext: (MAPIStoreUserContext *) userContext + withActiveUser: (SOGoUser *) activeUser; + +@end + +#endif /* ICALEVENT_MAPISTORE_H */ diff --git a/OpenChange/iCalEvent+MAPIStore.m b/OpenChange/iCalEvent+MAPIStore.m new file mode 100644 index 000000000..82785046a --- /dev/null +++ b/OpenChange/iCalEvent+MAPIStore.m @@ -0,0 +1,523 @@ +/* iCalEvent+MAPIStore.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import "MAPIStoreAppointmentWrapper.h" +#import "MAPIStoreCalendarAttachment.h" +#import "MAPIStoreCalendarFolder.h" +#import "MAPIStoreContext.h" +#import "MAPIStoreMapping.h" +#import "MAPIStoreRecurrenceUtils.h" +#import "MAPIStoreTypes.h" +#import "MAPIStoreUserContext.h" +#import "NSDate+MAPIStore.h" +#import "NSData+MAPIStore.h" +#import "NSObject+MAPIStore.h" +#import "NSString+MAPIStore.h" +#import "NSValue+MAPIStore.h" + +#import "MAPIStoreCalendarMessage.h" + +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include + +#import "iCalEvent+MAPIStore.h" + +@implementation iCalEvent (MAPIStoreProperties) + +- (void) _setupEventRecurrence: (NSData *) mapiRecurrenceData +{ + struct Binary_r *blob; + struct AppointmentRecurrencePattern *pattern; + + blob = [mapiRecurrenceData asBinaryInMemCtx: NULL]; + pattern = get_AppointmentRecurrencePattern (blob, blob); + [(iCalCalendar *) parent + setupRecurrenceWithMasterEntity: self + fromRecurrencePattern: &pattern->RecurrencePattern]; + talloc_free (blob); +} + +- (void) _setupEventAlarmFromProperties: (NSDictionary *) properties +{ + NSArray *alarms; + iCalAlarm *currentAlarm, *alarm = nil; + iCalTrigger *trigger; + NSNumber *delta; + NSString *action; + NSUInteger count, max; + + /* find and remove first display alarm */ + alarms = [self alarms]; + max = [alarms count]; + for (count = 0; !alarm && count < max; count++) + { + currentAlarm = [alarms objectAtIndex: count]; + action = [[currentAlarm action] lowercaseString]; + if (!action || [action isEqualToString: @"display"]) + alarm = currentAlarm; + } + + if (alarm) + [self removeChild: alarm]; + + if ([[properties objectForKey: MAPIPropertyKey (PidLidReminderSet)] + boolValue]) + { + delta + = [properties objectForKey: MAPIPropertyKey (PidLidReminderDelta)]; + if (delta) + { + alarm = [iCalAlarm new]; + [alarm setAction: @"DISPLAY"]; + trigger = [iCalTrigger elementWithTag: @"trigger"]; + [trigger setValueType: @"DURATION"]; + [trigger + setSingleValue: [NSString stringWithFormat: @"-PT%@M", delta] + forKey: @""]; + [alarm setTrigger: trigger]; + [self addToAlarms: alarm]; + [alarm release]; + } + } +} + +- (void) updateFromMAPIProperties: (NSDictionary *) properties + inUserContext: (MAPIStoreUserContext *) userContext + withActiveUser: (SOGoUser *) activeUser +{ + BOOL isAllDay; + iCalDateTime *start, *end; + iCalTimeZone *tz; + NSTimeZone *userTimeZone; + NSString *priority; + NSUInteger responseStatus = 0; + NSInteger tzOffset; + SOGoUser *ownerUser; + id value; + + // value = [properties objectForKey: MAPIPropertyKey (PidTagMessageClass)]; + // if (value) + // isException = [value isEqualToString: @"IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}"]; + // else + // isException = NO; + + userTimeZone = [userContext timeZone]; + + /* CREATED */ + value = [properties objectForKey: MAPIPropertyKey (PidTagCreationTime)]; + if (value) + [self setCreated: value]; + + // LAST-MODIFIED = PidTagLastModificationTime + value = [properties objectForKey: MAPIPropertyKey (PidTagLastModificationTime)]; + if (value) + [self setLastModified: value]; + + /* DTSTAMP = PidLidOwnerCriticalChange or PidLidAttendeeCriticalChange */ + value = [properties objectForKey: MAPIPropertyKey (PidLidOwnerCriticalChange)]; + if (value) + [self setTimeStampAsDate: value]; + + /* SUMMARY */ + value = [properties + objectForKey: MAPIPropertyKey (PR_NORMALIZED_SUBJECT_UNICODE)]; + if (value) + [self setSummary: value]; + + // Location + value = [properties objectForKey: MAPIPropertyKey (PidLidLocation)]; + if (value) + [self setLocation: value]; + + isAllDay = [self isAllDay]; + value = [properties + 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) + { + if (!isAllDay) + { + tzOffset = [userTimeZone secondsFromGMTForDate: value]; + value = [value dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: tzOffset]; + } + [self setRecurrenceId: value]; + } + + // start + value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentStartWhole)]; + if (!value) + value = [properties objectForKey: MAPIPropertyKey (PR_START_DATE)]; + if (value) + { + start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"]; + [start setTimeZone: tz]; + if (isAllDay) + { + [start setDate: value]; + [start setTimeZone: nil]; + } + else + { + tzOffset = [userTimeZone secondsFromGMTForDate: value]; + value = [value dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: tzOffset]; + [start setDateTime: value]; + } + } + + /* end */ + value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentEndWhole)]; + if (!value) + value = [properties objectForKey: MAPIPropertyKey (PR_END_DATE)]; + if (value) + { + end = (iCalDateTime *) [self uniqueChildWithTag: @"dtend"]; + [end setTimeZone: tz]; + if (isAllDay) + { + [end setDate: value]; + [end setTimeZone: nil]; + } + else + { + tzOffset = [[value timeZone] secondsFromGMTForDate: value]; + value = [value dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: tzOffset]; + [end setDateTime: value]; + } + } + + /* priority */ + value = [properties objectForKey: MAPIPropertyKey(PR_IMPORTANCE)]; + if (value) + { + switch ([value intValue]) + { + case 0: // IMPORTANCE_LOW + priority = @"9"; + break; + case 2: // IMPORTANCE_HIGH + priority = @"1"; + break; + default: // IMPORTANCE_NORMAL + priority = @"5"; + } + } + else + priority = @"0"; // None + [self setPriority: priority]; + + /* show time as free/busy/tentative/out of office. Possible values are: + 0x00000000 - olFree + 0x00000001 - olTentative + 0x00000002 - olBusy + 0x00000003 - olOutOfOffice */ + value = [properties objectForKey: MAPIPropertyKey(PidLidBusyStatus)]; + if (value) + { + switch ([value intValue]) + { + case 0: + [self setTransparency: @"TRANSPARENT"]; + break; + case 1: + case 2: + case 3: + default: + [self setTransparency: @"OPAQUE"]; + } + } + + /* Comment */ + value = [properties objectForKey: MAPIPropertyKey (PR_BODY_UNICODE)]; + if (!value) + { + value = [properties objectForKey: MAPIPropertyKey (PR_HTML)]; + if (value) + { + value = [[NSString alloc] initWithData: value + encoding: NSUTF8StringEncoding]; + [value autorelease]; + value = [value htmlToText]; + } + } + if (value) + { + if ([value length] == 0 || [value isEqualToString: @"\\n"]) + value = nil; + [self setComment: value]; + } + + /* recurrence */ + value = [properties + objectForKey: MAPIPropertyKey (PidLidAppointmentRecur)]; + if (value) + [self _setupEventRecurrence: value]; + + /* alarm */ + [self _setupEventAlarmFromProperties: properties]; + + // Organizer + value = [properties objectForKey: @"recipients"]; + if (value) + { + NSArray *recipients; + NSDictionary *dict; + NSString *orgEmail, *sentBy, *attEmail; + iCalPerson *person; + iCalPersonPartStat newPartStat; + NSNumber *flags, *trackStatus; + int i, effective; + BOOL organizerIsSet = NO; + + [self setOrganizer: nil]; + [self removeAllAttendees]; + + recipients = [value objectForKey: @"to"]; + effective = 0; + for (i = 0; i < [recipients count]; i++) + { + dict = [recipients objectAtIndex: i]; + person = [iCalPerson new]; + [person setCn: [dict objectForKey: @"fullName"]]; + attEmail = [dict objectForKey: @"email"]; + [person setEmail: attEmail]; + + flags = [dict objectForKey: MAPIPropertyKey (PR_RECIPIENT_FLAGS)]; + if (!flags) + { + [self logWithFormat: + @"no recipient flags specified: skipping recipient"]; + continue; + } + + if (([flags unsignedIntValue] & 0x0002)) /* recipOrganizer */ + { + [self setOrganizer: person]; + organizerIsSet = YES; + [self logWithFormat: @"organizer set via recipient flags"]; + } + else + { + BOOL isOrganizer = NO; + + // /* Work-around: it happens that Outlook still passes the + // organizer as a recipient, maybe because of a feature + // documented in a pre-mesozoic PDF still buried in a + // cavern... In that case we remove it, and we keep the + // number of effective recipients in "effective". If the + // total is 0, we remove the "ORGANIZER" too. */ + // if ([attEmail isEqualToString: orgEmail]) + // { + // [self logWithFormat: + // @"avoiding setting organizer as recipient"]; + // continue; + // } + + trackStatus = [dict objectForKey: MAPIPropertyKey (PidTagRecipientTrackStatus)]; + if (trackStatus) + { + /* FIXME: we should provide a data converter between OL + partstats and SOGo */ + switch ([trackStatus unsignedIntValue]) + { + case 0x01: /* respOrganized */ + isOrganizer = YES; + break; + case 0x02: /* respTentative */ + newPartStat = iCalPersonPartStatTentative; + break; + case 0x03: /* respAccepted */ + newPartStat = iCalPersonPartStatAccepted; + break; + case 0x04: /* respDeclined */ + newPartStat = iCalPersonPartStatDeclined; + break; + default: + newPartStat = iCalPersonPartStatNeedsAction; + } + + if (isOrganizer) + { + [self setOrganizer: person]; + organizerIsSet = YES; + [self logWithFormat: @"organizer set via track status"]; + } + else + { + [person setParticipationStatus: newPartStat]; + [person setRsvp: @"TRUE"]; + [person setRole: @"REQ-PARTICIPANT"]; + [self addToAttendees: person]; + effective++; + } + } + else + [self errorWithFormat: @"skipped recipient due" + @" to missing track status"]; + } + + [person release]; + } + + if (effective == 0) /* See work-around above */ + [self setOrganizer: nil]; + else + { + // SEQUENCE = PidLidAppointmentSequence + value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentSequence)]; + if (value) + [self setSequence: value]; + + ownerUser = [userContext sogoUser]; + if (organizerIsSet) + { + /* We must reset the participation status to the value + obtained from PidLidResponseStatus as the value in + PidTagRecipientTrackStatus is not correct. Note (hack): + the method used here requires that the user directory + from LDAP and Samba matches perfectly. This can be solved + more appropriately by making use of the sender + properties... */ + person = [self userAsAttendee: ownerUser]; + if (person) + { + value + = [properties objectForKey: MAPIPropertyKey (PidLidResponseStatus)]; + if (value) + responseStatus = [value unsignedLongValue]; + + /* FIXME: we should provide a data converter between OL partstats and + SOGo */ + switch (responseStatus) + { + case 0x02: /* respTentative */ + newPartStat = iCalPersonPartStatTentative; + break; + case 0x03: /* respAccepted */ + newPartStat = iCalPersonPartStatAccepted; + break; + case 0x04: /* respDeclined */ + newPartStat = iCalPersonPartStatDeclined; + break; + default: + newPartStat = iCalPersonPartStatNeedsAction; + } + [person setParticipationStatus: newPartStat]; + + value = [properties objectForKey: MAPIPropertyKey (PidLidAttendeeCriticalChange)]; + if (value && ![value isNever]) + [self setTimeStampAsDate: value]; + // if (newPartStat // != iCalPersonPartStatUndefined + // ) + // { + // // iCalPerson *participant; + + // // participant = [self userAsAttendee: ownerUser]; + // // [participant setParticipationStatus: newPartStat]; + // // [sogoObject saveComponent: self]; + + // [sogoObject changeParticipationStatus: newPartStat + // withDelegate: nil]; + // // [[self context] tearDownRequest]; + // } + // // }1005 + + // // else + // // { + } + } + else + { + [self errorWithFormat: @"organizer was not set although a" + @" recipient list was specified"]; + /* We must set the organizer preliminarily here because, unlike what + the doc states, Outlook does not always pass the real organizer + in the recipients list. */ + dict = [ownerUser primaryIdentity]; + person = [iCalPerson new]; + [person setCn: [dict objectForKey: @"fullName"]]; + orgEmail = [dict objectForKey: @"email"]; + [person setEmail: orgEmail]; + + if (![activeUser isEqual: ownerUser]) + { + dict = [activeUser primaryIdentity]; + sentBy = [NSString stringWithFormat: @"mailto:%@", + [dict objectForKey: @"email"]]; + [person setSentBy: sentBy]; + } + [self setOrganizer: person]; + [person release]; + } + } + } +} + +@end From 1476b93a45221667a0ae5d00cd71f77e745f894d Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 20 Jul 2012 15:44:25 +0000 Subject: [PATCH 038/127] Monotone-Parent: 5b4e61e92b3d68b92ea25f1513eb120e502250a1 Monotone-Revision: 1e529d97ad640de07982d342ce216985cba625f7 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-20T15:44:25 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreCalendarMessage.m | 68 ++++++++++++++++ OpenChange/MAPIStoreDBFolder.m | 48 ++++++++++- OpenChange/MAPIStoreMessage.m | 111 +++++++++++++++----------- OpenChange/MAPIStoreObjectProxy.m | 1 + OpenChange/MAPIStoreRecurrenceUtils.m | 71 +++++++++++++--- 5 files changed, 238 insertions(+), 61 deletions(-) diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index 2ad110bbb..f4dd3fbd6 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -115,6 +115,30 @@ return self; } +- (void) _setupAttachmentParts +{ + NSUInteger count, max; + NSArray *events; + NSString *newKey; + MAPIStoreCalendarAttachment *attachment; + NSUInteger aid; + + events = [calendar events]; + max = [events count]; + for (count = 1; count < max; count++) + { + attachment = [MAPIStoreCalendarAttachment + mapiStoreObjectInContainer: self]; + /* we now that there are no attachments yet, so we can assume that the + right AID is 0 from the start */ + aid = count - 1; + [attachment setAID: aid]; + [attachment setEvent: [events objectAtIndex: count]]; + newKey = [NSString stringWithFormat: @"%ul", aid]; + [attachmentParts setObject: attachment forKey: newKey]; + } +} + - (id) initWithSOGoObject: (id) newSOGoObject inContainer: (MAPIStoreObject *) newFolder { @@ -140,6 +164,7 @@ origCalendar = [sogoObject calendar: YES secure: YES]; calendar = [origCalendar mutableCopy]; masterEvent = [[calendar events] objectAtIndex: 0]; + [self _setupAttachmentParts]; } context = [self context]; userContext = [self userContext]; @@ -397,9 +422,51 @@ return rc; } +- (void) _updateAttachedEvent: (MAPIStoreCalendarAttachment *) attachment + withUID: (NSString *) uid { iCalEvent *newEvent; + SOGoUser *activeUser; + + newEvent = [iCalEvent groupWithTag: @"vevent"]; + [calendar addToEvents: newEvent]; + activeUser = [[self context] activeUser]; + [newEvent setUid: uid]; + [newEvent updateFromMAPIProperties: [attachment properties] + inUserContext: [self userContext] + withActiveUser: activeUser]; +} + +- (void) _updateAttachedEvents +{ + NSMutableArray *otherEvents; + NSArray *allAttachments; + NSUInteger count, max; + NSString *uid; + + /* cleanup all recurring events */ + otherEvents = [[calendar events] mutableCopy]; + [otherEvents removeObject: masterEvent]; + [calendar removeChildren: otherEvents]; + [otherEvents release]; + + uid = [masterEvent uid]; + + allAttachments = [attachmentParts allValues]; + max = [allAttachments count]; + for (count = 0; count < max; count++) + [self _updateAttachedEvent: [allAttachments objectAtIndex: count] + withUID: uid]; +} + +- (void) save +{ + // iCalCalendar *vCalendar; + // NSCalendarDate *now; + NSString *uid; + // iCalEvent *newEvent; // iCalPerson *userPerson; + SOGoUser *activeUser; if (isNew) { @@ -429,6 +496,7 @@ [masterEvent updateFromMAPIProperties: properties inUserContext: [self userContext] withActiveUser: activeUser]; + [self _updateAttachedEvents]; [sogoObject updateContentWithCalendar: calendar fromRequest: nil]; diff --git a/OpenChange/MAPIStoreDBFolder.m b/OpenChange/MAPIStoreDBFolder.m index 641b9dc59..06dead460 100644 --- a/OpenChange/MAPIStoreDBFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -24,6 +24,7 @@ #import #import +#import #import #import #import @@ -45,7 +46,7 @@ #include #include -static Class EOKeyValueQualifierK; +static Class EOKeyValueQualifierK, SOGoMAPIDBFolderK; static NSString *MAPIStoreRightReadItems = @"RightsReadItems"; static NSString *MAPIStoreRightCreateItems = @"RightsCreateItems"; @@ -62,6 +63,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; + (void) initialize { EOKeyValueQualifierK = [EOKeyValueQualifier class]; + SOGoMAPIDBFolderK = [SOGoMAPIDBFolder class]; } - (void) setupAuxiliaryObjects @@ -84,9 +86,40 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; withFID: (uint64_t) newFID andKey: (NSString **) newKeyP { - *newKeyP = [NSString stringWithFormat: @"0x%.16"PRIx64, (unsigned long long) newFID]; + enum mapistore_error rc; + NSString *folderName, *nameInContainer; + SOGoMAPIDBFolder *newFolder; + struct SPropValue *value; - return MAPISTORE_SUCCESS; + value = get_SPropValue_SRow (aRow, PidTagDisplayName); + if (value) + folderName = [NSString stringWithUTF8String: value->value.lpszW]; + else + { + value = get_SPropValue_SRow (aRow, PidTagDisplayName_string8); + if (value) + folderName = [NSString stringWithUTF8String: value->value.lpszA]; + else + folderName = nil; + } + + if (folderName) + { + nameInContainer = [NSString stringWithFormat: @"0x%.16"PRIx64, + (unsigned long long) newFID]; + newFolder = [SOGoMAPIDBFolderK objectWithName: nameInContainer + inContainer: sogoObject]; + [newFolder setIsNew: YES]; + [[newFolder properties] setObject: folderName + forKey: MAPIPropertyKey (PidTagDisplayName)]; + [newFolder save]; + *newKeyP = nameInContainer; + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_INVALID_PARAMETER; + + return rc; } - (MAPIStoreMessage *) createMessage @@ -134,6 +167,15 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; andSortOrderings: sortOrderings]; } +/* TODO: now that we are DB-based, this method can easily be implemented + +- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum + andCN: (NSNumber **) cnNbrs + inTableType: (enum mapistore_table_type) tableType +{ +} +*/ + - (NSDate *) lastMessageModificationTime { NSUInteger count, max; diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index 957cf8789..1217d295e 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -56,6 +56,7 @@ #include static NSString *resourcesDir = nil; +static Class MAPIStoreFolderK = nil; /* rtf conversion via unrtf */ static int @@ -130,6 +131,7 @@ rtf2html (NSData *compressedRTF) resourcesDir = [[NSBundle bundleForClass: self] resourcePath]; [resourcesDir retain]; } + MAPIStoreFolderK = [MAPIStoreFolder class]; } - (id) init @@ -442,61 +444,68 @@ rtf2html (NSData *compressedRTF) || (!isNew && [self subscriberCanModifyMessage]))) { /* notifications */ - folderId = [(MAPIStoreFolder *) container objectId]; - mstoreCtx = [[self context] connectionInfo]->mstore_ctx; - - /* folder modified */ - notif_parameters - = talloc_zero(NULL, struct mapistore_object_notification_parameters); - notif_parameters->object_id = folderId; - if (isNew) + if ([container isKindOfClass: MAPIStoreFolderK]) { - notif_parameters->tag_count = 3; - notif_parameters->tags = talloc_array (notif_parameters, - enum MAPITAGS, 3); - notif_parameters->tags[0] = PR_CONTENT_COUNT; - notif_parameters->tags[1] = PR_MESSAGE_SIZE; - notif_parameters->tags[2] = PR_NORMAL_MESSAGE_SIZE; - notif_parameters->new_message_count = true; - notif_parameters->message_count - = [[(MAPIStoreFolder *) container messageKeys] count] + 1; - } - mapistore_push_notification (mstoreCtx, - MAPISTORE_FOLDER, MAPISTORE_OBJECT_MODIFIED, - notif_parameters); - talloc_free (notif_parameters); + folderId = [(MAPIStoreFolder *) container objectId]; + mstoreCtx = [[self context] connectionInfo]->mstore_ctx; - /* message created */ - if (isNew) - { + /* folder modified */ notif_parameters - = talloc_zero(NULL, - struct mapistore_object_notification_parameters); - notif_parameters->object_id = [self objectId]; - notif_parameters->folder_id = folderId; - - notif_parameters->tag_count = 0xffff; + = talloc_zero(NULL, struct mapistore_object_notification_parameters); + notif_parameters->object_id = folderId; + if (isNew) + { + notif_parameters->tag_count = 3; + notif_parameters->tags = talloc_array (notif_parameters, + enum MAPITAGS, 3); + notif_parameters->tags[0] = PR_CONTENT_COUNT; + notif_parameters->tags[1] = PR_MESSAGE_SIZE; + notif_parameters->tags[2] = PR_NORMAL_MESSAGE_SIZE; + notif_parameters->new_message_count = true; + notif_parameters->message_count + = [[(MAPIStoreFolder *) container messageKeys] count] + 1; + } mapistore_push_notification (mstoreCtx, - MAPISTORE_MESSAGE, MAPISTORE_OBJECT_CREATED, + MAPISTORE_FOLDER, + MAPISTORE_OBJECT_MODIFIED, notif_parameters); talloc_free (notif_parameters); - } - /* we ensure the table caches are loaded so that old and new state - can be compared */ - containerTables = [self activeContainerMessageTables]; - max = [containerTables count]; - for (count = 0; count < max; count++) - [[containerTables objectAtIndex: count] restrictedChildKeys]; + /* message created */ + if (isNew) + { + notif_parameters + = talloc_zero(NULL, + struct mapistore_object_notification_parameters); + notif_parameters->object_id = [self objectId]; + notif_parameters->folder_id = folderId; + + notif_parameters->tag_count = 0xffff; + mapistore_push_notification (mstoreCtx, + MAPISTORE_MESSAGE, MAPISTORE_OBJECT_CREATED, + notif_parameters); + talloc_free (notif_parameters); + } + + /* we ensure the table caches are loaded so that old and new state + can be compared */ + containerTables = [self activeContainerMessageTables]; + max = [containerTables count]; + for (count = 0; count < max; count++) + [[containerTables objectAtIndex: count] restrictedChildKeys]; + } [self save]; - /* table modified */ - for (count = 0; count < max; count++) - [[containerTables objectAtIndex: count] - notifyChangesForChild: self]; + if ([container isKindOfClass: MAPIStoreFolderK]) + { + /* table modified */ + for (count = 0; count < max; count++) + [[containerTables objectAtIndex: count] + notifyChangesForChild: self]; + [container cleanupCaches]; + } [self setIsNew: NO]; - [container cleanupCaches]; rc = MAPISTORE_SUCCESS; } else @@ -645,9 +654,19 @@ rtf2html (NSData *compressedRTF) - (int) getPidTagMid: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = MAPILongLongValue (memCtx, [self objectId]); + int rc; + uint64_t obId; - return MAPISTORE_SUCCESS; + obId = [self objectId]; + if (obId == ULLONG_MAX) + rc = MAPISTORE_ERR_NOT_FOUND; + else + { + *data = MAPILongLongValue (memCtx, obId); + rc = MAPISTORE_SUCCESS; + } + + return rc; } - (int) getPidTagMessageLocaleId: (void **) data diff --git a/OpenChange/MAPIStoreObjectProxy.m b/OpenChange/MAPIStoreObjectProxy.m index 415d26df6..945d16167 100644 --- a/OpenChange/MAPIStoreObjectProxy.m +++ b/OpenChange/MAPIStoreObjectProxy.m @@ -21,6 +21,7 @@ */ #import "MAPIStorePropertySelectors.h" +#import "NSString+MAPIStore.h" #import "MAPIStoreObjectProxy.h" diff --git a/OpenChange/MAPIStoreRecurrenceUtils.m b/OpenChange/MAPIStoreRecurrenceUtils.m index 00ddf437a..d07d640f6 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.m +++ b/OpenChange/MAPIStoreRecurrenceUtils.m @@ -22,6 +22,7 @@ #import #import +#import #import #import @@ -50,11 +51,13 @@ { NSCalendarDate *startDate, *olEndDate, *untilDate, *exDate; NSString *monthDay, *month; + NSMutableSet *exceptionDates; + NSArray *realExDates; iCalRecurrenceRule *rule; iCalByDayMask *byDayMask; iCalWeekOccurrence weekOccurrence; iCalWeekOccurrences dayMaskDays; - NSUInteger count; + NSUInteger count, max; NSInteger bySetPos; unsigned char maskValue; @@ -209,7 +212,12 @@ rp->EndType]; } - /* exception dates */ + /* exception dates: + - take all deleted instances + - remove all modified instances from the above set + - add remaining instances, in chronological order + */ + exceptionDates = [NSMutableSet set]; for (count = 0; count < rp->DeletedInstanceCount; count++) { exDate @@ -217,8 +225,23 @@ exDate = [exDate hour: [startDate hourOfDay] minute: [startDate minuteOfHour] second: [startDate secondOfMinute]]; - [entity addToExceptionDates: exDate]; + [exceptionDates addObject: exDate]; } + for (count = 0; count < rp->ModifiedInstanceCount; count++) + { + exDate + = [NSDate dateFromMinutesSince1601: rp->ModifiedInstanceDates[count]]; + exDate = [exDate hour: [startDate hourOfDay] + minute: [startDate minuteOfHour] + second: [startDate secondOfMinute]]; + [exceptionDates removeObject: exDate]; + } + + realExDates = [[exceptionDates allObjects] + sortedArrayUsingSelector: @selector (compare:)]; + max = [realExDates count]; + for (count = 0; count < max; count++) + [entity addToExceptionDates: [realExDates objectAtIndex: count]]; } @end @@ -233,11 +256,14 @@ iCalRecurrenceFrequency freq; iCalByDayMask *byDayMask; NSString *byMonthDay, *bySetPos; - NSCalendarDate *startDate, *endDate, *untilDate, *beginOfWeek, *minimumDate, *moduloDate, *midnight; + NSCalendarDate *startDate, *endDate, *untilDate, *beginOfWeek, *minimumDate, + *moduloDate, *midnight; iCalWeekOccurrences *days; - NSInteger dayOfWeek, repeatInterval, repeatCount, count, firstOccurrence, max; + NSInteger dayOfWeek, repeatInterval, repeatCount, count, firstOccurrence, + max; uint32_t nbrMonths, mask; - NSArray *exDates; + NSArray *events; + NSMutableArray *deletedDates, *modifiedDates; startDate = [event firstRecurrenceStartDate]; [startDate setTimeZone: timeZone]; @@ -394,16 +420,37 @@ } } - - exDates = [[event exceptionDatesWithTimeZone: utcTZ] - sortedArrayUsingFunction: NSDateCompare - context: NULL]; - max = [exDates count]; + events = [[event parent] events]; + max = [events count]; + modifiedDates = [NSMutableArray arrayWithCapacity: max]; + for (count = 1; count < max; count++) + { + startDate = [[events objectAtIndex: count] recurrenceId]; + [modifiedDates addObject: startDate]; + } + max = [modifiedDates count]; + rp->ModifiedInstanceCount = max; + rp->ModifiedInstanceDates = talloc_array (memCtx, uint32_t, max); + for (count = 0; count < max; count++) + { + startDate = [[modifiedDates objectAtIndex: count] + hour: 0 minute: 0 second: 0]; + *(rp->ModifiedInstanceDates + count) = [startDate asMinutesSince1601]; + } + + deletedDates = [modifiedDates mutableCopy]; + [deletedDates autorelease]; + [deletedDates + addObjectsFromArray: [event exceptionDatesWithTimeZone: utcTZ]]; + [deletedDates sortUsingFunction: NSDateCompare context: NULL]; + + max = [deletedDates count]; rp->DeletedInstanceCount = max; rp->DeletedInstanceDates = talloc_array (memCtx, uint32_t, max); for (count = 0; count < max; count++) { - startDate = [[exDates objectAtIndex: count] hour: 0 minute: 0 second: 0]; + startDate = [[deletedDates objectAtIndex: count] + hour: 0 minute: 0 second: 0]; *(rp->DeletedInstanceDates + count) = [startDate asMinutesSince1601]; } } From fdec2c5d7b7c990b0aa2c2b268527cec11d35b91 Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Fri, 20 Jul 2012 18:23:33 +0000 Subject: [PATCH 039/127] Fixed merge Monotone-Parent: 89c8046bde59d4d200a7f039c310086919d53cfd Monotone-Revision: 9e0909dcbb77a5837442df736d80607b0a3fb383 Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2012-07-20T18:23:33 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 2 -- 1 file changed, 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2e0ed1af3..92cad4a05 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,3 @@ -<<<<<<< variant A 2012-07-20 Francis Lachapelle * UI/WebServerResources/MailerUI.js (onEmailTo): append the email @@ -81,7 +80,6 @@ (-save): don t swap the bytes of the version number as it would return a wrong change number and a wrong change key for DB objects. ->>>>>>> variant B 2012-07-20 Wolfgang Sourdeau * OpenChange/NSObject+MAPIStore.m (-getSMTPAddrType:inMemCtx:): From 136c6dd92dc81678d0f18429a35409125454f749 Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Fri, 20 Jul 2012 18:24:52 +0000 Subject: [PATCH 040/127] Fixed merge Monotone-Parent: bfc3cb63453015f444ec1a1fd20faeece6be2042 Monotone-Revision: bdb3c86bf127fecd411885ad5bcf84eb8af9f672 Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2012-07-20T18:24:52 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 2 -- 1 file changed, 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2f98d22ad..03159f886 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,9 @@ -<<<<<<< variant A 2012-07-20 Ludovic Marcotte * UI/MailPartViewers/UIxMailRenderingContext.m (_shouldDisplayAsAttachment:): refactored to consider the "bodyId" parameter only for non text/* parts. ->>>>>>> variant B 2012-07-20 Francis Lachapelle * UI/WebServerResources/MailerUI.js (onEmailTo): append the email From 2f42766717cc9792c61e7346a230b12848a17a4f Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 24 Jul 2012 20:43:06 +0000 Subject: [PATCH 041/127] Monotone-Parent: bdb3c86bf127fecd411885ad5bcf84eb8af9f672 Monotone-Revision: b226b4ac380c34d6adb7ee8a0fab3a0632d83b37 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-24T20:43:06 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++++ OpenChange/samba-get-config.py | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100755 OpenChange/samba-get-config.py diff --git a/ChangeLog b/ChangeLog index 03159f886..d09c9c0d0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-07-24 Wolfgang Sourdeau + + * OpenChange/samba-get-config.py: new utility taking a samba + configuration variable and prints the value on stdout + 2012-07-20 Ludovic Marcotte * UI/MailPartViewers/UIxMailRenderingContext.m diff --git a/OpenChange/samba-get-config.py b/OpenChange/samba-get-config.py new file mode 100755 index 000000000..c91c3ed44 --- /dev/null +++ b/OpenChange/samba-get-config.py @@ -0,0 +1,8 @@ +#!/usr/bin/python + +import sys +import samba.param + +a = samba.param.LoadParm() +a.load_default() +print a.get(sys.argv[1]) From 3cdf0347d55587dc4a908f252e641ea859974dbc Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 24 Jul 2012 20:43:40 +0000 Subject: [PATCH 042/127] Monotone-Parent: b226b4ac380c34d6adb7ee8a0fab3a0632d83b37 Monotone-Revision: 204d5491d1eef2c2a95ac2f31f32e5ab833a3ad8 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-24T20:43:40 Monotone-Branch: ca.inverse.sogo --- OpenChange/iCalEvent+MAPIStore.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OpenChange/iCalEvent+MAPIStore.m b/OpenChange/iCalEvent+MAPIStore.m index 82785046a..cacec6ea2 100644 --- a/OpenChange/iCalEvent+MAPIStore.m +++ b/OpenChange/iCalEvent+MAPIStore.m @@ -169,8 +169,7 @@ [self setTimeStampAsDate: value]; /* SUMMARY */ - value = [properties - objectForKey: MAPIPropertyKey (PR_NORMALIZED_SUBJECT_UNICODE)]; + value = [properties objectForKey: MAPIPropertyKey (PidTagNormalizedSubject)]; if (value) [self setSummary: value]; From 5aa0db4d7b71fc17f4bbff747fdefd241c9263f0 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 24 Jul 2012 20:45:03 +0000 Subject: [PATCH 043/127] Monotone-Parent: 204d5491d1eef2c2a95ac2f31f32e5ab833a3ad8 Monotone-Revision: 63de63b9d1691f5af7ec1b790f5201ae73cfa036 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-24T20:45:03 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/GNUmakefile | 3 +++ OpenChange/MAPIStoreUserContext.m | 35 ++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index d09c9c0d0..b04d654d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-07-24 Wolfgang Sourdeau + * OpenChange/MAPIStoreUserContext.m + (-initWithUsername:andTDBIndexing:): attempt to read the user + password from a property list. + * OpenChange/samba-get-config.py: new utility taking a samba configuration variable and prints the value on stdout diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 91b75ec0e..afed24ce2 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -26,6 +26,8 @@ BUNDLE_INSTALL_DIR = $(SOGO_LIBDIR) UNRTF_DIR = unrtf-$(UNRTF_VERSION) +SAMBA_PRIVATE_DIR = $(shell ./samba-get-config.py "private dir") + $(SOGOBACKEND)_SUBPROJECTS += $(UNRTF_DIR)/src $(SOGOBACKEND)_PRINCIPAL_CLASS = MAPIApplication @@ -190,6 +192,7 @@ $(SOGOBACKEND)_LIB_DIRS += \ ADDITIONAL_INCLUDE_DIRS += \ -Werror -Wall \ + -DSAMBA_PRIVATE_DIR=@"\"$(SAMBA_PRIVATE_DIR)\"" \ $(LIBMAPI_CFLAGS) \ $(LIBMAPISTORE_CFLAGS) \ -I$(UNRTF_DIR)/src \ diff --git a/OpenChange/MAPIStoreUserContext.m b/OpenChange/MAPIStoreUserContext.m index bf5d97f0c..7e6f7ec5a 100644 --- a/OpenChange/MAPIStoreUserContext.m +++ b/OpenChange/MAPIStoreUserContext.m @@ -20,8 +20,10 @@ * Boston, MA 02111-1307, USA. */ +#import #import #import +#import #import #import @@ -95,9 +97,37 @@ static NSMapTable *contextsTable = nil; return self; } +- (NSString *) _readUserPassword: (NSString *) newUsername +{ + NSString *password; + NSData *content; + id plist; + NSPropertyListFormat plistFormat; + NSString *error; + + password = nil; + + content = [NSData dataWithContentsOfFile: SAMBA_PRIVATE_DIR + @"/mapistore/SOGo/userpwds.plist"]; + if (content) + { + plist = [NSPropertyListSerialization + propertyListFromData: content + mutabilityOption: NSPropertyListImmutable + format: &plistFormat + errorDescription: &error]; + if ([plist respondsToSelector: @selector (objectForKey:)]) + password = [plist objectForKey: newUsername]; + } + + return password; +} + - (id) initWithUsername: (NSString *) newUsername andTDBIndexing: (struct tdb_wrap *) indexingTdb { + NSString *userPassword; + if ((self = [self init])) { /* "username" will be retained by table */ @@ -109,7 +139,10 @@ static NSMapTable *contextsTable = nil; authenticator = [MAPIStoreAuthenticator new]; [authenticator setUsername: username]; /* TODO: very hackish (IMAP access) */ - [authenticator setPassword: username]; + userPassword = [self _readUserPassword: newUsername]; + if ([userPassword length] == 0) + userPassword = username; + [authenticator setPassword: userPassword]; } return self; From 7557403b62032d9efa56268cd34cbc766be3ded6 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 25 Jul 2012 17:44:35 +0000 Subject: [PATCH 044/127] Monotone-Parent: 8062273942a9de3fcd13c9bb3307488c9a67ec68 Monotone-Revision: d6e6af11a4430fc14c38e245fbaa322775b7b5d7 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-25T17:44:35 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 6 ++++++ OpenChange/MAPIStoreDBFolder.m | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 729cbc2bc..39e369629 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-07-25 Wolfgang Sourdeau + + * OpenChange/MAPIStoreDBFolder.m (-createFolder:withFID:andKey:): + invoke "reloadIfNeeded" on the created folder object in order to + initialize it. + 2012-07-24 Wolfgang Sourdeau * OpenChange/MAPIStoreUserContext.m diff --git a/OpenChange/MAPIStoreDBFolder.m b/OpenChange/MAPIStoreDBFolder.m index 06dead460..d8af710ad 100644 --- a/OpenChange/MAPIStoreDBFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -109,7 +109,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; (unsigned long long) newFID]; newFolder = [SOGoMAPIDBFolderK objectWithName: nameInContainer inContainer: sogoObject]; - [newFolder setIsNew: YES]; + [newFolder reloadIfNeeded]; [[newFolder properties] setObject: folderName forKey: MAPIPropertyKey (PidTagDisplayName)]; [newFolder save]; @@ -133,6 +133,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; fsObject = [SOGoMAPIDBMessage objectWithName: newKey inContainer: sogoObject]; [fsObject setObjectType: MAPIDBObjectTypeMessage]; + [fsObject reloadIfNeeded]; newMessage = [MAPIStoreDBMessage mapiStoreObjectWithSOGoObject: fsObject inContainer: self]; From 15f1b39979675844c49ae51106fef023f72c4ba6 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 25 Jul 2012 20:25:01 +0000 Subject: [PATCH 045/127] Make use of python2.6 when regular executable is not good enough Monotone-Parent: 5482c2b5518f1f90b17ae8222dc1fa7c48830345 Monotone-Revision: cacefec02204aa8b679c093b97728a347f35d630 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-25T20:25:01 Monotone-Branch: ca.inverse.sogo --- OpenChange/GNUmakefile | 11 ++++++++++- OpenChange/GNUmakefile.preamble | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index afed24ce2..03002e1c1 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -26,7 +26,16 @@ BUNDLE_INSTALL_DIR = $(SOGO_LIBDIR) UNRTF_DIR = unrtf-$(UNRTF_VERSION) -SAMBA_PRIVATE_DIR = $(shell ./samba-get-config.py "private dir") +PYTHON = /usr/bin/python +PYTHON_IS_GOOD = $(shell $(PYTHON) -c 'from sys import version_info; a=version_info; print a.major == 2 and a.minor >= 6') +ifeq (${PYTHON_IS_GOOD},False) +PYTHON = /usr/bin/python2.6 +endif + +all:: + @echo " Python executable: ${PYTHON}" + +SAMBA_PRIVATE_DIR = $(shell $(PYTHON) ./samba-get-config.py "private dir") $(SOGOBACKEND)_SUBPROJECTS += $(UNRTF_DIR)/src diff --git a/OpenChange/GNUmakefile.preamble b/OpenChange/GNUmakefile.preamble index 74046108b..27b4b5692 100644 --- a/OpenChange/GNUmakefile.preamble +++ b/OpenChange/GNUmakefile.preamble @@ -2,4 +2,4 @@ all:: MAPIStorePropertySelectors.m MAPIStorePropertySelectors.h MAPIStorePropertySelectors.m MAPIStorePropertySelectors.h: gen-property-selectors.py code-MAPIStorePropertySelectors.m code-MAPIStorePropertySelectors.h @echo " Auto-generating MAPIStorePropertySelectors.[hm]..." - @./gen-property-selectors.py -o MAPIStorePropertySelectors $(LIBMAPISTORE_CFLAGS) + @$(PYTHON) ./gen-property-selectors.py -o MAPIStorePropertySelectors $(LIBMAPISTORE_CFLAGS) From db3d0b56981903383f1167626b23c1d5ce0dc6b5 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 25 Jul 2012 20:25:35 +0000 Subject: [PATCH 046/127] Restored debian builds of sogo-openchange Monotone-Parent: cacefec02204aa8b679c093b97728a347f35d630 Monotone-Revision: 36bc18c04836a73e009f9b01d9fde7dfad557dbe Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-25T20:25:35 Monotone-Branch: ca.inverse.sogo --- debian-multiarch/control | 14 ++++++++++++++ debian-multiarch/rules | 22 ++++++++++++++++++++++ debian/control | 12 ++++++++++++ debian/rules | 22 ++++++++++++++++++++++ debian/sogo-openchange.install | 2 ++ 5 files changed, 72 insertions(+) create mode 100644 debian/sogo-openchange.install diff --git a/debian-multiarch/control b/debian-multiarch/control index 0f1790b3e..1f861a83f 100644 --- a/debian-multiarch/control +++ b/debian-multiarch/control @@ -35,6 +35,20 @@ Description: a modern and scalable groupware - development files . This package contains the development files for developing SOGo modules. +Package: sogo-openchange +Pre-Depends: ${misc:Pre-Depends} +Multi-Arch: same +Section: net +Priority: extra +Architecture: any +Depends: sogo (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: a modern and scalable groupware - OpenChange backend + SOGo is a groupware server built around OpenGroupware.org (OGo) and + the SOPE application server with focus on scalability. + . + This package contains the backend plugin for using SOGo as a backend + to OpenChange. + Package: sogo-dbg Section: debug Priority: extra diff --git a/debian-multiarch/rules b/debian-multiarch/rules index edfc67f6f..6f06fb1ac 100755 --- a/debian-multiarch/rules +++ b/debian-multiarch/rules @@ -20,6 +20,9 @@ build-arch: build-arch-stamp build-arch-stamp: config.make # Add here commands to compile the arch part of the package. $(MAKE) + if pkg-config --atleast-version=1.0 libmapi; \ + then (cd OpenChange; $(MAKE)); \ + fi touch $@ clean: @@ -31,8 +34,15 @@ clean: -find Tests -name "*.pyc" -exec rm -f {} \; if [ -f config.make ]; \ then \ + if pkg-config --atleast-version=1.0 libmapi; \ + then \ + (cd OpenChange; make clean); \ + fi; \ make clean; \ fi + -rm -f OpenChange/MAPIStorePropertySelectors.* + -find OpenChange -type d -name "unrtf-*" -exec rm -rf {} \; + -rm -f OpenChange/unrtf*-stamp -rm -f config.make dh_clean @@ -50,6 +60,18 @@ install-arch: build-arch # dh_installdirs -s $(MAKE) DESTDIR=$(DESTDIR) GNUSTEP_INSTALLATION_DOMAIN=SYSTEM install + if pkg-config --atleast-version=1.0 libmapi; \ + then \ + (cd OpenChange; \ + $(MAKE) \ + DESTDIR=$(DESTDIR) \ + GNUSTEP_INSTALLATION_DOMAIN=SYSTEM \ + install); \ + rm -f $(DESTDIR)/usr/lib/$(DEB_HOST_MULTIARCH)/mapistore_backends/libMAPIStoreSOGo.so.1; \ + rm -f $(DESTDIR)/usr/lib/$(DEB_HOST_MULTIARCH)/mapistore_backends/libMAPIStoreSOGo.so; \ + mv -f $(DESTDIR)/usr/lib/$(DEB_HOST_MULTIARCH)/mapistore_backends/libMAPIStoreSOGo.so.1.0.0 \ + $(DESTDIR)/usr/lib/$(DEB_HOST_MULTIARCH)/mapistore_backends/SOGo.so; \ + fi mkdir -p debian/tmp/etc/default cp Scripts/sogo-default debian/tmp/etc/default/sogo diff --git a/debian/control b/debian/control index 6642d7fb3..b7d3e1890 100644 --- a/debian/control +++ b/debian/control @@ -33,6 +33,18 @@ Description: a modern and scalable groupware - development files . This package contains the development files for developing SOGo modules. +Package: sogo-openchange +Section: net +Priority: extra +Architecture: any +Depends: sogo (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: a modern and scalable groupware - OpenChange backend + SOGo is a groupware server built around OpenGroupware.org (OGo) and + the SOPE application server with focus on scalability. + . + This package contains the backend plugin for using SOGo as a backend + to OpenChange. + Package: sogo-dbg Section: debug Priority: extra diff --git a/debian/rules b/debian/rules index 4f2ffd513..b3b41ce65 100755 --- a/debian/rules +++ b/debian/rules @@ -19,6 +19,9 @@ build-arch: build-arch-stamp build-arch-stamp: config.make # Add here commands to compile the arch part of the package. $(MAKE) + if pkg-config --atleast-version=1.0 libmapi; \ + then (cd OpenChange; $(MAKE)); \ + fi touch $@ clean: @@ -30,8 +33,15 @@ clean: -find Tests -name "*.pyc" -exec rm -f {} \; if [ -f config.make ]; \ then \ + if pkg-config --atleast-version=1.0 libmapi; \ + then \ + (cd OpenChange; make clean); \ + fi; \ make clean; \ fi + -rm -f OpenChange/MAPIStorePropertySelectors.* + -find OpenChange -type d -name "unrtf-*" -exec rm -rf {} \; + -rm -f OpenChange/unrtf*-stamp -rm -f config.make dh_clean @@ -49,6 +59,18 @@ install-arch: build-arch # dh_installdirs -s $(MAKE) DESTDIR=$(DESTDIR) GNUSTEP_INSTALLATION_DOMAIN=SYSTEM install + if pkg-config --atleast-version=1.0 libmapi; \ + then \ + (cd OpenChange; \ + $(MAKE) \ + DESTDIR=$(DESTDIR) \ + GNUSTEP_INSTALLATION_DOMAIN=SYSTEM \ + install); \ + rm -f $(DESTDIR)/usr/lib/mapistore_backends/libMAPIStoreSOGo.so.1; \ + rm -f $(DESTDIR)/usr/lib/mapistore_backends/libMAPIStoreSOGo.so; \ + mv -f $(DESTDIR)/usr/lib/mapistore_backends/libMAPIStoreSOGo.so.1.0.0 \ + $(DESTDIR)/usr/lib/mapistore_backends/SOGo.so; \ + fi mkdir -p debian/tmp/etc/default cp Scripts/sogo-default debian/tmp/etc/default/sogo diff --git a/debian/sogo-openchange.install b/debian/sogo-openchange.install new file mode 100644 index 000000000..dcae5f4e2 --- /dev/null +++ b/debian/sogo-openchange.install @@ -0,0 +1,2 @@ +usr/lib/mapistore_backends/* +usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore From 55dbf42b768dc3dc89659a39700d5eaa70994a97 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 26 Jul 2012 14:07:00 +0000 Subject: [PATCH 047/127] missing file Monotone-Parent: 36bc18c04836a73e009f9b01d9fde7dfad557dbe Monotone-Revision: 1e25427624932fb9417220f5b278ba55ed52da6c Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-26T14:07:00 Monotone-Branch: ca.inverse.sogo --- debian-multiarch/sogo-openchange.install | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 debian-multiarch/sogo-openchange.install diff --git a/debian-multiarch/sogo-openchange.install b/debian-multiarch/sogo-openchange.install new file mode 100644 index 000000000..d3f119d33 --- /dev/null +++ b/debian-multiarch/sogo-openchange.install @@ -0,0 +1,2 @@ +usr/lib/*/mapistore_backends/* +usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore From 70911dc5180fdf76605ff80484960dcbaeac15af Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 26 Jul 2012 14:19:56 +0000 Subject: [PATCH 048/127] Remove openchange from build Monotone-Parent: 1e25427624932fb9417220f5b278ba55ed52da6c Monotone-Revision: a77c26240c765963ea4295dc50c295c08809953e Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-26T14:19:56 Monotone-Branch: ca.inverse.sogo --- debian/control | 12 ------------ debian/sogo-openchange.install | 2 -- 2 files changed, 14 deletions(-) delete mode 100644 debian/sogo-openchange.install diff --git a/debian/control b/debian/control index b7d3e1890..6642d7fb3 100644 --- a/debian/control +++ b/debian/control @@ -33,18 +33,6 @@ Description: a modern and scalable groupware - development files . This package contains the development files for developing SOGo modules. -Package: sogo-openchange -Section: net -Priority: extra -Architecture: any -Depends: sogo (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} -Description: a modern and scalable groupware - OpenChange backend - SOGo is a groupware server built around OpenGroupware.org (OGo) and - the SOPE application server with focus on scalability. - . - This package contains the backend plugin for using SOGo as a backend - to OpenChange. - Package: sogo-dbg Section: debug Priority: extra diff --git a/debian/sogo-openchange.install b/debian/sogo-openchange.install deleted file mode 100644 index dcae5f4e2..000000000 --- a/debian/sogo-openchange.install +++ /dev/null @@ -1,2 +0,0 @@ -usr/lib/mapistore_backends/* -usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore From 581d94aa1f3ee2345f0cf330ba13018a9b9636e8 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Thu, 26 Jul 2012 14:46:19 +0000 Subject: [PATCH 049/127] Changed the vacation status icon in the top menu. Monotone-Parent: 36bc18c04836a73e009f9b01d9fde7dfad557dbe Monotone-Revision: edf9b648fb75a0ecc4621f16c8ba57b6bffd0ee2 Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2012-07-26T14:46:19 Monotone-Branch: ca.inverse.sogo --- UI/WebServerResources/status.vacation-msg.png | Bin 1642 -> 298 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/UI/WebServerResources/status.vacation-msg.png b/UI/WebServerResources/status.vacation-msg.png index 81502b0b3b531e9e94a6630c0ef4f2c7459f09c3..5648fc3929cf1b667247ceef9e88e0f57f03eb4f 100644 GIT binary patch literal 298 zcmV+_0oDGAP)3`jzY@j1B zLN|~RZ~`5{5g4H(I0D_k5pV*0G)F~psKl3iA@s_-J2(+S5Dh3`xmYLKbp#IV@{c{Z zd^qHRr8U={%tl&8EUTv2!T>awfMfpgV2rJ8;tqZ@FhwPjs@eX~?kQDtD=trmHcgz7 zY&5wpO)*BcxF?mxOktu^tY`W?(4Fb^MP5q#2T#bc w(qO&~WQ%GERwMak!b{1T(E!fk4?P7K07_$8&pTI^0RR9107*qoM6N<$g7M6BH2?qr literal 1642 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`Jj+tIX_n~5oC^DMQ#CujeSKy zVsdtBi9%9pdS;%jl7fPQl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3a#eP+Wr~u$9hXgo z6;N|-YDuC(MQ%=Bu~mhw64*>DAR8pCucQE0Qj%?}1aWkPZ-9bxeo?A|iJqZuvVpOQ zf{B@)k-3qjxtWeaaAJvqS7M%mk-37AfdP;(vNANZGBE@?1`L$!xPY`xQA(Oskc%7C zP9V=#DWjyMz)D}gyu4hm+*mKaC|%#s($Z4jz)0W7NEfI=x41H|B(Xv_uUHvk2+SOp z)Z*l#%mQ$5fy_-z$}cUkRZ;?31P4&hB^JOf$}5Hj9xxd7D-sLz4fPE4;U)t$+5iQu zz!8yO6q28xV}~WqY(P3u6d`Oy=udS?EJ?KkhKGf&fswAEd5D3Lm9d$XiD?v)euyG8 z?Y{XbnQ4_s+KqLMOhODTtqcsTOpKt~krY9-+vtM=0x4j?p$_sBnz#ai082@RhgU&q zQ4Tm-Qj+ykb5e6t^Gb?=VP=RLW+};5Y57IDi6wTKxryni`UQFEHu?xbyzYaz8kj7A z$x02?vTCt2h3x_EyCr zbJjJVIXW!jP1><5xXsJrYZP zZ}Wwy1K(@A7BMWinIpu)$nf~1L~QnhO1TfWg{H3WSbv1&pw0bn`;&ScT?7Q16cXMZ zcCKQcZ@@Ei_4&}w8V13GmhHuTPnVu95u5(=&r@M9?O%WG7_3h=gljwHKUh3vmC%c# z#gk96G?@6lEZe>1cJ3mLMdlVezc}*gzdx(czB)MX{$69|h-}YEEDd3+Ll1h{?p1xl zS5|*uW9#qml?qY{r;Q$2*nNJsnCXrP7x&KQ_93ekV7*Dc$)n4Eg dG|T&dzxqkX8%7i7i2}=e22WQ%mvv4FO#qjA|Iq*d From 3e3d8b261f5a51cae0ad88ba73cfda56ff7da377 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Thu, 26 Jul 2012 14:46:42 +0000 Subject: [PATCH 050/127] Updated NEWS file. Monotone-Parent: edf9b648fb75a0ecc4621f16c8ba57b6bffd0ee2 Monotone-Revision: 218517d78ee9b6165cb4f85aff8eee3481b75972 Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2012-07-26T14:46:42 Monotone-Branch: ca.inverse.sogo --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index def66a3cc..df97bd74f 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -1.3.17 (2012-07-25) +1.3.17 (2012-07-26) ------------------- New Features - new contextual menu to view the raw content of events, tasks and contacts From ac6e45f1e9b94ae8d48c991e064f018167bfc3f9 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 26 Jul 2012 20:50:36 +0000 Subject: [PATCH 051/127] Monotone-Parent: a77c26240c765963ea4295dc50c295c08809953e Monotone-Revision: d9e87057688d279c42a3fde582339d3eb6cc2f10 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-26T20:50:36 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 10 ++ OpenChange/GNUmakefile | 1 + OpenChange/MAPIStoreAppointmentWrapper.m | 22 +++++ OpenChange/iCalTimeZone+MAPIStore.h | 35 +++++++ OpenChange/iCalTimeZone+MAPIStore.m | 115 +++++++++++++++++++++++ 5 files changed, 183 insertions(+) create mode 100644 OpenChange/iCalTimeZone+MAPIStore.h create mode 100644 OpenChange/iCalTimeZone+MAPIStore.m diff --git a/ChangeLog b/ChangeLog index 4e45209ef..be41ab6aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2012-07-26 Wolfgang Sourdeau + + * OpenChange/iCalTimeZone+MAPIStore.[hm]: new category module. + (-asTimeZoneStructInMemCtx:): new method that returns a struct + TimeZoneStruct as a binary blob from an iCalTimeZone object. + + * OpenChange/MAPIStoreAppointmentWrapper.m + (-getPidLidTimeZoneStruct:inMemCtx:): new property getter that + returns the equivalent of the iCalTimeZone of the current event. + 2012-07-25 Wolfgang Sourdeau * OpenChange/MAPIStoreDBFolder.m (-createFolder:withFID:andKey:): diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 03002e1c1..39fd7d826 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -127,6 +127,7 @@ $(SOGOBACKEND)_OBJC_FILES += \ NSValue+MAPIStore.m \ \ iCalEvent+MAPIStore.m \ + iCalTimeZone+MAPIStore.m \ \ GCSSpecialQueries+OpenChange.m\ \ diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index c6c707694..f545b443d 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -20,6 +20,8 @@ * Boston, MA 02111-1307, USA. */ +#include + #import #import #import @@ -29,6 +31,7 @@ #import #import #import +#import #import #import #import @@ -36,6 +39,7 @@ #import #import +#import "iCalTimeZone+MAPIStore.h" #import "MAPIStoreRecurrenceUtils.h" #import "MAPIStoreSamDBUtils.h" #import "MAPIStoreTypes.h" @@ -1584,4 +1588,22 @@ static NSCharacterSet *hexCharacterSet = nil; return MAPISTORE_ERR_NOT_FOUND; } +- (int) getPidLidTimeZoneStruct: (void **) data + 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; + + return rc; +} + @end diff --git a/OpenChange/iCalTimeZone+MAPIStore.h b/OpenChange/iCalTimeZone+MAPIStore.h new file mode 100644 index 000000000..d476869c5 --- /dev/null +++ b/OpenChange/iCalTimeZone+MAPIStore.h @@ -0,0 +1,35 @@ +/* iCalTimeZone+MAPIStore.h - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef ICALTIMEZONE_MAPISTORE_H +#define ICALTIMEZONE_MAPISTORE_H + +#import + +@interface iCalTimeZone (MAPIStoreProperties) + +- (struct Binary_r *) asTimeZoneStructInMemCtx: (TALLOC_CTX *) memCtx; + +@end + + +#endif /* ICALTIMEZONE_MAPISTORE_H */ diff --git a/OpenChange/iCalTimeZone+MAPIStore.m b/OpenChange/iCalTimeZone+MAPIStore.m new file mode 100644 index 000000000..d15447233 --- /dev/null +++ b/OpenChange/iCalTimeZone+MAPIStore.m @@ -0,0 +1,115 @@ +/* iCalTimeZone+MAPIStore.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import +#import +#import +#import +#import + +#include +#include +#include +#undef DEBUG +#include + +#import "iCalTimeZone+MAPIStore.h" + +@interface iCalTimeZonePeriod (MAPIStorePropertiesPrivate) + +- (void) _fillTZDate: (struct SYSTEMTIME *) tzData; + +@end + +@implementation iCalTimeZonePeriod (MAPIStorePropertiesPrivate) + +- (void) _fillTZDate: (struct SYSTEMTIME *) tzData +{ + iCalRecurrenceRule *rrule; + NSArray *byMonth; + iCalByDayMask *mask; + NSCalendarDate *dateValue; + + rrule = [self recurrenceRule]; + byMonth = [rrule byMonth]; + if ([byMonth count] > 0) + { + tzData->wMonth = [[byMonth objectAtIndex: 0] intValue]; + mask = [rrule byDayMask]; + tzData->wDayOfWeek = [mask firstDay]; + tzData->wDay = [mask firstOccurrence]; + + dateValue = [self startDate]; + tzData->wHour = [dateValue hourOfDay]; + tzData->wMinute = [dateValue minuteOfHour]; + tzData->wSecond = [dateValue secondOfMinute]; + } +} + +@end + +@implementation iCalTimeZone (MAPIStoreProperties) + +- (iCalTimeZonePeriod *) _mostRecentPeriodWithName: (NSString *) periodName +{ + NSArray *periods; + iCalTimeZonePeriod *period; + NSUInteger max; + + periods = [self childrenWithTag: periodName]; + max = [periods count]; + if (max > 0) + { + periods = [periods sortedArrayUsingSelector: @selector (compare:)]; + period = (iCalTimeZonePeriod *) [periods objectAtIndex: (max - 1)]; + } + else + period = nil; + + return period; +} + +- (struct Binary_r *) asTimeZoneStructInMemCtx: (TALLOC_CTX *) memCtx +{ + iCalTimeZonePeriod *period; + struct TimeZoneStruct tz; + int lBias, dlBias; + + memset (&tz, 0, sizeof (struct TimeZoneStruct)); + period = [self _mostRecentPeriodWithName: @"STANDARD"]; + lBias = -[period secondsOffsetFromGMT] / 60; + tz.lBias = (uint32_t) 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); + [period _fillTZDate: &tz.stDaylightDate]; + tz.wStandardYear = tz.stStandardDate.wYear; + tz.wDaylightYear = tz.stDaylightDate.wYear; + + return set_TimeZoneStruct (memCtx, &tz); +} + +@end From b622a433e92d81c9b4ae6d87a914b0ddd0f305f0 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 26 Jul 2012 20:56:33 +0000 Subject: [PATCH 052/127] Monotone-Parent: 3c0814786842608f4b2aea659b16c3eb7e694f9d Monotone-Revision: bc3ed474ad46d79c92b1456be764f4803b264d92 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-26T20:56:33 Monotone-Branch: ca.inverse.sogo --- SOPE/NGCards/ChangeLog | 9 +++++++++ SOPE/NGCards/iCalTimeZonePeriod.h | 9 +++++++++ SOPE/NGCards/iCalTimeZonePeriod.m | 10 ++++++++++ 3 files changed, 28 insertions(+) diff --git a/SOPE/NGCards/ChangeLog b/SOPE/NGCards/ChangeLog index 00e9c352b..c3d36d07a 100644 --- a/SOPE/NGCards/ChangeLog +++ b/SOPE/NGCards/ChangeLog @@ -1,3 +1,12 @@ +2012-07-26 Wolfgang Sourdeau + + * iCalTimeZonePeriod.m (-recurrenceRule): new accessor for the + "rrule" element. + (-startDate): made method public. + (-compare:): new method that compare two periods based on their + startDate, for timezone definitions which have a "standard" or + "daylight" period for more that one years. + 2012-05-30 Francis Lachapelle * iCalRepeatableEntityObject.m (-exceptionDatesWithTimeZone:) diff --git a/SOPE/NGCards/iCalTimeZonePeriod.h b/SOPE/NGCards/iCalTimeZonePeriod.h index a710630df..838176804 100644 --- a/SOPE/NGCards/iCalTimeZonePeriod.h +++ b/SOPE/NGCards/iCalTimeZonePeriod.h @@ -25,11 +25,20 @@ #import "CardGroup.h" +@class NSCalendarDate; + +@class iCalRecurrenceRule; + @interface iCalTimeZonePeriod : CardGroup +- (NSCalendarDate *) startDate; +- (iCalRecurrenceRule *) recurrenceRule; + - (NSCalendarDate *) occurenceForDate: (NSCalendarDate *) refDate; - (int) secondsOffsetFromGMT; +- (NSComparisonResult) compare: (iCalTimeZonePeriod *) otherPeriod; + @end #endif /* ICALTIMEZONEPERIOD_H */ diff --git a/SOPE/NGCards/iCalTimeZonePeriod.m b/SOPE/NGCards/iCalTimeZonePeriod.m index b161f55ab..f3613ee68 100644 --- a/SOPE/NGCards/iCalTimeZonePeriod.m +++ b/SOPE/NGCards/iCalTimeZonePeriod.m @@ -109,6 +109,11 @@ dateTime]; } +- (iCalRecurrenceRule *) recurrenceRule +{ + return (iCalRecurrenceRule *) [self firstChildWithTag: @"rrule"]; +} + /** * This method returns the date corresponding for to the start of the period * in the year of the reference date. @@ -184,4 +189,9 @@ return [self _secondsOfOffset: @"tzoffsetto"]; } +- (NSComparisonResult) compare: (iCalTimeZonePeriod *) otherPeriod +{ + return [[self startDate] compare: [otherPeriod startDate]]; +} + @end From 9be1c93f8406bcd420a3eb9b9f27aebe5255e221 Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Thu, 2 Aug 2012 13:18:09 +0000 Subject: [PATCH 053/127] See ChangeLog Monotone-Parent: 7a464f08b5ba1b713a0beec23ddfa576c9023439 Monotone-Revision: 22735bbc1319155936115d59c7f2699c32dc60f1 Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2012-08-02T13:18:09 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 6 ++++++ OpenChange/MAPIStoreUserContext.m | 24 ++++++++++-------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 662d98648..632c7881d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-08-02 Ludovic Marcotte + + * OpenChange/MAPIStoreUserContext.m (-_readUserPassword:) + We now read per-user passwords instead of relying on + a global file. + 2012-07-31 Jean Raby * sogo.spec: diff --git a/OpenChange/MAPIStoreUserContext.m b/OpenChange/MAPIStoreUserContext.m index 7e6f7ec5a..2d6097277 100644 --- a/OpenChange/MAPIStoreUserContext.m +++ b/OpenChange/MAPIStoreUserContext.m @@ -99,25 +99,21 @@ static NSMapTable *contextsTable = nil; - (NSString *) _readUserPassword: (NSString *) newUsername { - NSString *password; + NSString *password, *path; NSData *content; - id plist; - NSPropertyListFormat plistFormat; - NSString *error; - + password = nil; + + path = [NSString stringWithFormat: SAMBA_PRIVATE_DIR + @"/mapistore/%@/password", newUsername]; + + content = [NSData dataWithContentsOfFile: path]; - content = [NSData dataWithContentsOfFile: SAMBA_PRIVATE_DIR - @"/mapistore/SOGo/userpwds.plist"]; if (content) { - plist = [NSPropertyListSerialization - propertyListFromData: content - mutabilityOption: NSPropertyListImmutable - format: &plistFormat - errorDescription: &error]; - if ([plist respondsToSelector: @selector (objectForKey:)]) - password = [plist objectForKey: newUsername]; + password = [[NSString alloc] initWithData: content + encoding: NSUTF8StringEncoding]; + [password autorelease]; } return password; From 1f7166f86e328b02cc54d599efdf093fbe25e346 Mon Sep 17 00:00:00 2001 From: Jean Raby Date: Thu, 2 Aug 2012 15:44:58 +0000 Subject: [PATCH 054/127] * OpenChange/GNUmakefile: link against libWEExtensions Monotone-Parent: 22735bbc1319155936115d59c7f2699c32dc60f1 Monotone-Revision: 43364d6242db2d8b6496cce2c7905d9468fafa41 Monotone-Author: jraby@inverse.ca Monotone-Date: 2012-08-02T15:44:58 Monotone-Branch: ca.inverse.sogo --- OpenChange/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 39fd7d826..0db45e325 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -186,7 +186,7 @@ SAMBA_LIB_DIR = $(shell pkg-config libmapistore --variable=libdir) LIBMAPI_LIBS = $(shell pkg-config libmapi --libs) LIBMAPISTORE_CFLAGS = $(shell pkg-config libmapistore --cflags) -DSAMBA_PREFIX="\"$(shell pkg-config libmapistore --variable=prefix)\"" -LIBMAPISTORE_LIBS = $(shell pkg-config libmapistore --libs) -lmapiproxy +LIBMAPISTORE_LIBS = $(shell pkg-config libmapistore --libs) -lmapiproxy -lWEExtensions $(MAPISTORESOGO)_INSTALL_DIR = $(DESTDIR)/$(SAMBA_LIB_DIR)/mapistore_backends $(MAPISTORESOGO)_LIB_DIRS += \ From a0874e8562146330121e8414f6fb438c9fe9e593 Mon Sep 17 00:00:00 2001 From: Jean Raby Date: Thu, 2 Aug 2012 17:45:36 +0000 Subject: [PATCH 055/127] add sogo-openchange package contents on debian. Monotone-Parent: 4280fb032373c8ebfdcc67e2e271b47583c31ec3 Monotone-Revision: b2c6832ba400b4bb228726fbd0e791d2ce796007 Monotone-Author: jraby@inverse.ca Monotone-Date: 2012-08-02T17:45:36 Monotone-Branch: ca.inverse.sogo --- packaging/debian/sogo-openchange.install | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 packaging/debian/sogo-openchange.install diff --git a/packaging/debian/sogo-openchange.install b/packaging/debian/sogo-openchange.install new file mode 100644 index 000000000..dcae5f4e2 --- /dev/null +++ b/packaging/debian/sogo-openchange.install @@ -0,0 +1,2 @@ +usr/lib/mapistore_backends/* +usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore From 7d12d795be6a10b9aa0af5018b5622f37709ccaf Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 6 Aug 2012 19:16:12 +0000 Subject: [PATCH 056/127] Monotone-Parent: c0f07692ea20a10ac587360d8d82535fb4291afc Monotone-Revision: a797dc8fdc5b4a9a938cb4ecf4b99bda3e239fb7 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-06T19:16:12 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreMessage.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index 1217d295e..a5a8827ab 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -614,7 +614,8 @@ rtf2html (NSData *compressedRTF) - (int) getPidLidCurrentVersion: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = MAPILongValue (memCtx, 115608); // Outlook 11.5608 + // *data = MAPILongValue (memCtx, 115608); // Outlook 11.5608 + *data = MAPILongValue (memCtx, 0x1ce3a); // Outlook 11.8330 return MAPISTORE_SUCCESS; } From 5722856993d606edbb92b82235942720fa88f5f2 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 6 Aug 2012 19:16:46 +0000 Subject: [PATCH 057/127] Monotone-Parent: a797dc8fdc5b4a9a938cb4ecf4b99bda3e239fb7 Monotone-Revision: 08f69e80d11df21083547348b4136cf77bdb5a78 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-06T19:16:46 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++++ OpenChange/MAPIStoreSOGoObject.m | 13 +------------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index a30e40848..8c00429f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-08-06 Wolfgang Sourdeau + + * OpenChange/MAPIStoreSOGoObject.m (-objectId): force generation + of objectId by parent, whether it is a folder or not. + 2012-08-03 Jean Raby * SoObjects/SOGo/LDAPSource.m (changePasswordForLogin): diff --git a/OpenChange/MAPIStoreSOGoObject.m b/OpenChange/MAPIStoreSOGoObject.m index 421337505..f6d849857 100644 --- a/OpenChange/MAPIStoreSOGoObject.m +++ b/OpenChange/MAPIStoreSOGoObject.m @@ -132,18 +132,7 @@ static Class MAPIStoreFolderK; /* helpers */ - (uint64_t) objectId { - uint64_t objectId; - - if ([container isKindOfClass: MAPIStoreFolderK]) - objectId = [(MAPIStoreFolder *) container - idForObjectWithKey: [sogoObject nameInContainer]]; - else - { - [self errorWithFormat: @"%s: container is not a folder", __PRETTY_FUNCTION__]; - objectId = (uint64_t) -1; - } - - return objectId; + return [container idForObjectWithKey: [sogoObject nameInContainer]]; } /* getters */ From bd8af728ce878d4b5bc1660983d4cc6a759c4f00 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 6 Aug 2012 19:17:35 +0000 Subject: [PATCH 058/127] Monotone-Parent: 08f69e80d11df21083547348b4136cf77bdb5a78 Monotone-Revision: 152cd7be8bdfd9ff8cd05ec730d08c591d29dc2e Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-06T19:17:35 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/MAPIStoreMailVolatileMessage.m | 23 +++-------------------- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8c00429f0..501b57b70 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-08-06 Wolfgang Sourdeau + * OpenChange/MAPIStoreMailVolatileMessage.m (MakeMessageBody): + take "attachmentParts" parameter, deduced from the ivar with the + corresponding name. + * OpenChange/MAPIStoreSOGoObject.m (-objectId): force generation of objectId by parent, whether it is a folder or not. diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index ec33c54dd..2af242f49 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -309,16 +309,6 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" }; return rc; } -- (NSArray *) attachmentsKeysMatchingQualifier: (EOQualifier *) qualifier - andSortOrderings: (NSArray *) sortOrderings -{ - NSDictionary *attachments; - - attachments = [properties objectForKey: @"attachments"]; - - return [attachments allKeys]; -} - - (NSDate *) creationTime { return [sogoObject creationDate]; @@ -331,11 +321,7 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" }; - (id) lookupAttachment: (NSString *) childKey { - NSDictionary *attachments; - - attachments = [properties objectForKey: @"attachments"]; - - return [attachments objectForKey: childKey]; + return [attachmentParts objectForKey: childKey]; } - (void) getMessageData: (struct mapistore_message **) dataPtr @@ -762,9 +748,8 @@ MakeTextPartBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, // MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, // NSString **contentType) static id -MakeMessageBody (NSDictionary *mailProperties, NSString **contentType) +MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NSString **contentType) { - NSDictionary *attachmentParts; id messageBody, textBody; NSString *textContentType; NSArray *parts; @@ -772,7 +757,6 @@ MakeMessageBody (NSDictionary *mailProperties, NSString **contentType) NGMutableHashMap *headers; NSUInteger count, max; - attachmentParts = [mailProperties objectForKey: @"attachments"]; textBody = MakeTextPartBody (mailProperties, attachmentParts, &textContentType); @@ -821,8 +805,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSString **contentType) [message autorelease]; [headers release]; - messageBody = MakeMessageBody (properties, &contentType); - // messageBody = MakeMessageBody (mailProperties, attachmentParts, &contentType); + messageBody = MakeMessageBody (properties, attachmentParts, &contentType); if (messageBody) { [headers setObject: contentType forKey: @"content-type"]; From 4eafd2bd5841c0beab0c4369486d2c584da381fa Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 6 Aug 2012 19:19:15 +0000 Subject: [PATCH 059/127] Monotone-Parent: 152cd7be8bdfd9ff8cd05ec730d08c591d29dc2e Monotone-Revision: e14333177a9e3223d083bb94a4a7a18746ee7e12 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-06T19:19:15 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++++ OpenChange/MAPIStoreRecurrenceUtils.m | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 501b57b70..ea56b998a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2012-08-06 Wolfgang Sourdeau + * OpenChange/MAPIStoreRecurrenceUtils.m (-[iCalRecurrenceRule + fillRecurrencePattern:withEvent:inTimeZone:inMemCtx:]): fixed a + crash occurring when the exception has no recurrence-id and + ignore the specific occurrence. + * OpenChange/MAPIStoreMailVolatileMessage.m (MakeMessageBody): take "attachmentParts" parameter, deduced from the ivar with the corresponding name. diff --git a/OpenChange/MAPIStoreRecurrenceUtils.m b/OpenChange/MAPIStoreRecurrenceUtils.m index d07d640f6..4f36253d5 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.m +++ b/OpenChange/MAPIStoreRecurrenceUtils.m @@ -293,6 +293,7 @@ else { rp->EndDate = 0x5ae980df; + rp->OccurrenceCount = 0xa; rp->EndType = END_NEVER_END; } } @@ -426,7 +427,10 @@ for (count = 1; count < max; count++) { startDate = [[events objectAtIndex: count] recurrenceId]; - [modifiedDates addObject: startDate]; + if (startDate) + [modifiedDates addObject: startDate]; + else + [self errorWithFormat: @"missing recurrence-id for event %d", count]; } max = [modifiedDates count]; rp->ModifiedInstanceCount = max; From df6f1e3023ef2dd963a523ca709ce694ccb48fce Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 6 Aug 2012 19:19:41 +0000 Subject: [PATCH 060/127] Monotone-Parent: e14333177a9e3223d083bb94a4a7a18746ee7e12 Monotone-Revision: 35e905507b00aa93112b244da8c4f4c32c7942c7 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-06T19:19:41 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreAppointmentWrapper.h | 1 + OpenChange/MAPIStoreAppointmentWrapper.m | 541 +++++++++++++++++++---- 2 files changed, 462 insertions(+), 80 deletions(-) diff --git a/OpenChange/MAPIStoreAppointmentWrapper.h b/OpenChange/MAPIStoreAppointmentWrapper.h index ba3377965..d0f3fbc00 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.h +++ b/OpenChange/MAPIStoreAppointmentWrapper.h @@ -40,6 +40,7 @@ { struct mapistore_connection_info *connInfo; iCalCalendar *calendar; + iCalEvent *firstEvent; iCalEvent *event; NSTimeZone *timeZone; SOGoUser *user; diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index f545b443d..ac7cb057b 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -27,12 +27,14 @@ #import #import #import +#import #import #import #import #import #import #import +#import #import #import #import @@ -51,7 +53,6 @@ #import "MAPIStoreAppointmentWrapper.h" #undef DEBUG -#include #include #include #include @@ -183,11 +184,15 @@ static NSCharacterSet *hexCharacterSet = nil; inTimeZone: (NSTimeZone *) newTimeZone withConnectionInfo: (struct mapistore_connection_info *) newConnInfo { + NSArray *events; + if ((self = [self init])) { connInfo = newConnInfo; - ASSIGN (event, newEvent); - ASSIGN (calendar, [event parent]); + ASSIGN (calendar, [newEvent parent]); + event = newEvent; + events = [calendar events]; + firstEvent = [events objectAtIndex: 0]; ASSIGN (timeZone, newTimeZone); ASSIGN (user, newUser); ASSIGN (senderEmail, newSenderEmail); @@ -200,7 +205,6 @@ static NSCharacterSet *hexCharacterSet = nil; - (void) dealloc { [calendar release]; - [event release]; [timeZone release]; [user release]; [senderEmail release]; @@ -628,35 +632,20 @@ static NSCharacterSet *hexCharacterSet = nil; return MAPISTORE_SUCCESS; } +- (int) getPidLidAppointmentMessageClass: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = talloc_strdup (memCtx, "IPM.Appointment"); + + return MAPISTORE_SUCCESS; +} + - (int) getPidLidFInvited: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getYes: data inMemCtx: memCtx]; } -- (int) getPidTagStartDate: (void **) data - 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]; - *data = [dateValue asFileTimeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - - (int) getPidLidAppointmentSequence: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -724,13 +713,245 @@ static NSCharacterSet *hexCharacterSet = nil; - (int) getPidLidAppointmentStartWhole: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidTagStartDate: data inMemCtx: 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]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagStartDate: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + /* "The PidTagStartDate property ([MS-OXPROPS] section 2.1077) SHOULD be + set, and when set, it MUST be equal to the value of the + PidLidAppointmentStartWhole property (section 2.2.1.5).". Not true for + 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]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; } - (int) getPidLidCommonStart: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidLidAppointmentStartWhole: data inMemCtx: 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]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidLidClipStart: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + enum mapistore_error rc; + NSCalendarDate *dateValue; + + if ([event isRecurrent]) + { + dateValue = [[event startDate] hour: 0 minute: 0 second: 0]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + else if ([event recurrenceId] != nil) + rc = MAPISTORE_ERR_NOT_FOUND; + else + rc = [self getPidLidAppointmentStartWhole: data inMemCtx: memCtx]; + + return rc; +} + +- (int) getPidTagExceptionStartTime: (void **) data + inMemCtx: (TALLOC_CTX *) localMemCtx +{ + enum mapistore_error rc; + NSCalendarDate *dateValue; + NSInteger offset; + + if ([event recurrenceId] != nil) + { + 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]; + } + *data = [dateValue asFileTimeInMemCtx: localMemCtx]; + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + +- (int) getPidLidAppointmentEndWhole: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSCalendarDate *dateValue; + NSInteger offset; + + // if ([event isRecurrent]) + // dateValue = [event firstRecurrenceStartDate]; + // else + dateValue = [event startDate]; + offset = [event durationAsTimeInterval]; + if ([event isAllDay]) + offset -= [timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagEndDate: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSCalendarDate *dateValue; + NSInteger offset; + + dateValue = [event recurrenceId]; + if (!dateValue) + dateValue = [event startDate]; + [dateValue setTimeZone: timeZone]; + offset = [firstEvent durationAsTimeInterval]; + if ([firstEvent isAllDay]) + offset -= [timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidLidCommonEnd: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSCalendarDate *dateValue; + NSInteger offset; + + // if ([event isRecurrent]) + // dateValue = [event firstRecurrenceStartDate]; + // else + dateValue = [firstEvent startDate]; + offset = [firstEvent durationAsTimeInterval]; + if ([event isAllDay]) + offset -= [timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidLidClipEnd: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + 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]; + } + else + dateValue = [NSCalendarDate dateWithYear: 4500 month: 8 day: 31 + hour: 23 minute: 59 second: 59 + timeZone: utcTZ]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + else if ([event recurrenceId] != nil) + rc = MAPISTORE_ERR_NOT_FOUND; + else + rc = [self getPidLidAppointmentEndWhole: data inMemCtx: memCtx]; + + return rc; +} + +- (int) getPidTagExceptionEndTime: (void **) data + inMemCtx: (TALLOC_CTX *) localMemCtx +{ + enum mapistore_error rc; + NSCalendarDate *dateValue; + NSInteger offset; + + if ([event recurrenceId] != nil) + { + dateValue = [event startDate]; + [dateValue setTimeZone: timeZone]; + offset = [event durationAsTimeInterval]; + if (![event isAllDay]) + offset += [timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + *data = [dateValue asFileTimeInMemCtx: localMemCtx]; + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; } - (int) _getEntryIdFromCN: (NSString *) cn @@ -919,40 +1140,6 @@ static NSCharacterSet *hexCharacterSet = nil; } /* /attendee */ -- (int) getPidTagEndDate: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - NSCalendarDate *dateValue; - NSInteger offset; - - if ([event isRecurrent]) - dateValue = [event firstRecurrenceStartDate]; - else - dateValue = [event startDate]; - offset = [event durationAsTimeInterval]; - if ([event isAllDay]) - offset -= [timeZone secondsFromGMTForDate: dateValue]; - dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 - hours: 0 minutes: 0 - seconds: offset]; - [dateValue setTimeZone: utcTZ]; - *data = [dateValue asFileTimeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - -- (int) getPidLidAppointmentEndWhole: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getPidTagEndDate: data inMemCtx: memCtx]; -} - -- (int) getPidLidCommonEnd: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getPidLidAppointmentEndWhole: data inMemCtx: memCtx]; -} - - (int) getPidLidAppointmentDuration: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -1113,25 +1300,112 @@ static NSCharacterSet *hexCharacterSet = nil; return MAPISTORE_SUCCESS; } -- (void) _fillExceptionInfo: (struct ExceptionInfo *) exceptionInfo - withException: (iCalEvent *) exceptionEvent +- (int) getPidLidFExceptionalBody: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { - memset (exceptionInfo, 0, sizeof (struct ExceptionInfo)); - exceptionInfo->OverrideFlags = 0; - exceptionInfo->StartDateTime = [[exceptionEvent startDate] asMinutesSince1601]; - exceptionInfo->EndDateTime = [[exceptionEvent endDate] asMinutesSince1601]; - exceptionInfo->OriginalStartDate = [[[exceptionEvent recurrenceId] hour: 0 - minute: 0 - second: 0] - asMinutesSince1601]; + return [self getNo: data inMemCtx: memCtx]; } -- (void) _fillExtendedException: (struct ExtendedException *) extendedException - withException: (iCalEvent *) exceptionEvent +- (int) getPidLidExceptionReplaceTime: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { + 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]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + +- (void) _fillExceptionInfo: (struct ExceptionInfo *) exceptionInfo + andExtendedException: (struct ExtendedException *) extendedException + withException: (iCalEvent *) exceptionEvent + inMemCtx: (TALLOC_CTX *) memCtx +{ + iCalEventChanges *changes; + NSArray *changedProperties; + NSCalendarDate *dateValue; + NSInteger offset; + + changes = [iCalEventChanges changesFromEvent: event toEvent: exceptionEvent]; + + memset (exceptionInfo, 0, sizeof (struct ExceptionInfo)); memset (extendedException, 0, sizeof (struct ExtendedException)); extendedException->ChangeHighlight.Size = sizeof (uint32_t); - extendedException->ChangeHighlight.Value = 1 << 31 | 1 << 30; + + dateValue = [exceptionEvent startDate]; + offset = [timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + 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]; + 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]; + exceptionInfo->OriginalStartDate = [dateValue asMinutesSince1601]; + extendedException->OriginalStartDate = exceptionInfo->OriginalStartDate; + + changedProperties = [changes updatedProperties]; + if ([changedProperties containsObject: @"summary"]) + { + extendedException->ChangeHighlight.Value |= BIT_CH_SUBJECT; + extendedException->Subject + = [[exceptionEvent summary] asUnicodeInMemCtx: memCtx]; + + exceptionInfo->OverrideFlags |= ARO_SUBJECT; + exceptionInfo->Subject.subjectMsg.msg + = (uint8_t *) extendedException->Subject; + /* FIXME: this will fail with non ascii chars */ + exceptionInfo->Subject.subjectMsg.msgLength2 = [[exceptionEvent summary] length]; + exceptionInfo->Subject.subjectMsg.msgLength = exceptionInfo->Subject.subjectMsg.msgLength2 + 1; + } + if ([changedProperties containsObject: @"location"]) + { + extendedException->ChangeHighlight.Value |= BIT_CH_LOCATION; + extendedException->Location + = [[exceptionEvent location] asUnicodeInMemCtx: memCtx]; + exceptionInfo->OverrideFlags |= ARO_LOCATION; + exceptionInfo->Location.locationMsg.msg + = (uint8_t *) extendedException->Location; + /* FIXME: this will fail with non ascii chars */ + exceptionInfo->Location.locationMsg.msgLength2 = [[exceptionEvent location] length]; + exceptionInfo->Location.locationMsg.msgLength = exceptionInfo->Location.locationMsg.msgLength2 + 1; + } + if ([event isAllDay] != [exceptionEvent isAllDay]) + { + exceptionInfo->OverrideFlags |= ARO_SUBTYPE; + exceptionInfo->SubType.sType = [exceptionEvent isAllDay]; + } } // - (struct SBinary_short *) _computeAppointmentRecurInMemCtx: (TALLOC_CTX *) memCtx @@ -1160,7 +1434,8 @@ static NSCharacterSet *hexCharacterSet = nil; inTimeZone: timeZone inMemCtx: arp]; arp->ReaderVersion2 = 0x00003006; - arp->WriterVersion2 = 0x00003009; + arp->WriterVersion2 = 0x00003008; /* 0x3008 for compatibility with + ol2003 */ startMinutes = ([firstStartDate hourOfDay] * 60 + [firstStartDate minuteOfHour]); @@ -1180,9 +1455,9 @@ static NSCharacterSet *hexCharacterSet = nil; { exceptionEvent = [exceptions objectAtIndex: count]; [self _fillExceptionInfo: arp->ExceptionInfo + count - withException: exceptionEvent]; - [self _fillExtendedException: arp->ExtendedException + count - withException: exceptionEvent]; + andExtendedException: arp->ExtendedException + count + withException: exceptionEvent + inMemCtx: arp]; } arp->ReservedBlock1Size = 0; arp->ReservedBlock2Size = 0; @@ -1209,6 +1484,93 @@ static NSCharacterSet *hexCharacterSet = nil; return bin; } +/* exception 12345 + 123456 (exchange): + 81ad0102 (PT_BINARY): + named prop + guid: {00062002-0000-0000-c000-000000000046} + dispid: 0x00008216 + (163 bytes) + 04 30 04 30 0a 20 00 00 | \x04 0 \x04 0 \x0a \x00 \x00 + 00 00 00 00 00 00 a0 05 | \x00 \x00 \x00 \x00 \x00 \x00 \xa0 \x05 + 00 00 00 00 00 00 23 20 | \x00 \x00 \x00 \x00 \x00 \x00 # + 00 00 0a 00 00 00 00 00 | \x00 \x00 \x0a \x00 \x00 \x00 \x00 \x00 + 00 00 01 00 00 00 a0 c6 | \x00 \x00 \x01 \x00 \x00 \x00 \xa0 \xc6 + e6 0c 01 00 00 00 a0 c6 | \xe6 \x0c \x01 \x00 \x00 \x00 \xa0 \xc6 + e6 0c 00 c1 e6 0c df 80 | \xe6 \x0c \x00 \xc1 \xe6 \x0c \xdf \x80 + e9 5a 06 30 00 00 08 30 | \xe9 Z \x06 0 \x00 \x00 \x08 0 + 00 00 66 03 00 00 84 03 | \x00 \x00 f \x03 \x00 \x00 \x84 \x03 + 00 00 01 00 e8 c9 e6 0c | \x00 \x00 \x01 \x00 \xe8 \xc9 \xe6 \x0c + f6 ca e6 0c 06 ca e6 0c | \xf6 \xca \xe6 \x0c \x06 \xca \xe6 \x0c + 11 00 06 00 05 00 31 32 | \x11 \x00 \x06 \x00 \x05 \x00 1 2 + 33 34 35 07 00 06 00 31 | 3 4 5 \x07 \x00 \x06 \x00 1 + 32 33 34 35 36 00 00 00 | 2 3 4 5 6 \x00 \x00 \x00 + 00 00 00 00 00 e8 c9 e6 | \x00 \x00 \x00 \x00 \x00 \xe8 \xc9 \xe6 + 0c f6 ca e6 0c 06 ca e6 | \x0c \xf6 \xca \xe6 \x0c \x06 \xca \xe6 + 0c 05 00 31 00 32 00 33 | \x0c \x05 \x00 1 \x00 2 \x00 3 + 00 34 00 35 00 06 00 31 | \x00 4 \x00 5 \x00 \x06 \x00 1 + 00 32 00 33 00 34 00 35 | \x00 2 \x00 3 \x00 4 \x00 5 + 00 36 00 00 00 00 00 00 | \x00 6 \x00 \x00 \x00 \x00 \x00 \x00 + 00 00 00 | \x00 \x00 \x00 + +openchange: + 918b0102 (PT_BINARY): + named prop + guid: {00062002-0000-0000-c000-000000000046} + dispid: 0x00008216 + (167 bytes) + + +recurrence pattern + readerversion: 04 30 + writerversion: 04 30 + recurfrequency: 0a 20 (daily) + patterntype: 00 00 + calendartype: 00 00 + firstdatetime: 00 00 00 00 + period: a0 05 00 00 (1440 minutes) + slidingflag: 00 00 00 00 + patterntypespecific: (0 bytes) + endtype: 23 20 00 00 + occurrencecount: *00->0a 00 00 00 (meaningless since no enddate) + firstdow: 00 00 00 00 + deletedicount: 01 00 00 00 + deletedinstancedates: (1) + a0 c6 e6 0c + modifiedicount: 01 00 00 00 + modifiedinstancedates: (1) + a0 c6 e6 0c + startdate: 00 c1 e6 0c + enddate: df 80 e9 5a +ReaderVersion2: 06 30 00 00 +WriterVersion2: 08 30 00 00 +StartTimeOffset: 66 03 00 00 +EndTimeOffset: 84 03 00 00 +ExceptionCount: 01 00 +ExceptionInfos: (1) + StartDateTime: *e7->e8 *ca->c9 e6 0c + EndDateTime: *e6->f6 *cb->ca e6 0c + OriginalStartDate: *a0->06 *c6->ca e6 0c + OverrideFlags: 11 00 + SubjectLength2: 06 00 + SubjectLength: 05 00 + Subject: 31 32 33 34 35 + LocationLength2: 07 00 + LocationLength: 06 00 + Location: 31 32 33 34 35 36 +ReservedBlock1Size: 00 00 00 00 +ExtendedException: (1) + ReservedBlockEE1Size: 00 00 00 00 + StartDateTime: *e7->e8 *ca->c9 e6 0c + EndDateTime: *e6->f6 *cb->ca e6 0c + OriginalStartDate: *a0->06 *c6->ca e6 0c + WideCharSubjectLength *06->05 + WideCharSubject: 00 31 00 32 00 33 00 34 00 35 00 [2bytes sup: 00 00] + LocationLength: *07->06 + Location 00 31 00 32 00 33 00 34 00 35 00 36 00 00 + ReservedBlockEE2Size: 00 00 00 00 +ReservedBlockEE2Size: 00 00 00 00 +*/ + - (int) getPidLidAppointmentRecur: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -1588,6 +1950,25 @@ static NSCharacterSet *hexCharacterSet = nil; return MAPISTORE_ERR_NOT_FOUND; } +- (int) getPidLidTimeZoneDescription: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + enum mapistore_error rc; + NSString *tzid; + + tzid = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] + value: 0 ofAttribute: @"tzid"]; + if ([tzid length] > 0) + { + *data = [tzid asUnicodeInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + - (int) getPidLidTimeZoneStruct: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { From 28816877aa03a089f279e38987ca1df90dfbcea1 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 6 Aug 2012 19:20:07 +0000 Subject: [PATCH 061/127] Monotone-Parent: 35e905507b00aa93112b244da8c4f4c32c7942c7 Monotone-Revision: c4cd64ca35c43c187a23cc30e1bad4db1a5e9d1d Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-06T19:20:07 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreAttachment.m | 7 ++ OpenChange/MAPIStoreCalendarAttachment.m | 56 ++++++++++++-- OpenChange/MAPIStoreCalendarEmbeddedMessage.m | 46 ++++++++++++ OpenChange/MAPIStoreCalendarMessage.m | 57 ++++++-------- OpenChange/MAPIStoreEmbeddedMessage.m | 75 +++++++++++++++++++ 5 files changed, 200 insertions(+), 41 deletions(-) diff --git a/OpenChange/MAPIStoreAttachment.m b/OpenChange/MAPIStoreAttachment.m index 9e1551eb0..b7a2a75d4 100644 --- a/OpenChange/MAPIStoreAttachment.m +++ b/OpenChange/MAPIStoreAttachment.m @@ -28,6 +28,7 @@ #import "MAPIStoreMapping.h" #import "MAPIStoreMessage.h" #import "MAPIStoreTypes.h" +#import "NSObject+MAPIStore.h" #undef DEBUG #include @@ -90,6 +91,12 @@ return MAPISTORE_SUCCESS; } +- (int) getPidTagAccessLevel: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getLongZero: data inMemCtx: memCtx]; +} + - (int) openEmbeddedMessage: (MAPIStoreEmbeddedMessage **) messagePtr withMID: (uint64_t *) mid withMAPIStoreMsg: (struct mapistore_message **) mapistoreMsgPtr diff --git a/OpenChange/MAPIStoreCalendarAttachment.m b/OpenChange/MAPIStoreCalendarAttachment.m index a6d7848a2..d44a21e47 100644 --- a/OpenChange/MAPIStoreCalendarAttachment.m +++ b/OpenChange/MAPIStoreCalendarAttachment.m @@ -20,14 +20,22 @@ * Boston, MA 02111-1307, USA. */ +#import +#import #import +#import #import #import #import "iCalEvent+MAPIStore.h" -#import "MAPIStoreTypes.h" #import "MAPIStoreCalendarEmbeddedMessage.h" +#import "MAPIStoreTypes.h" +#import "MAPIStoreUserContext.h" +#import "NSDate+MAPIStore.h" +#import "NSData+MAPIStore.h" +#import "NSObject+MAPIStore.h" +#import "NSString+MAPIStore.h" #import "MAPIStoreCalendarAttachment.h" @@ -65,12 +73,16 @@ return event; } +- (NSString *) nameInContainer +{ + return [[event uniqueChildWithTag: @"recurrence-id"] + flattenedValuesForKey: @""]; +} + - (int) getPidTagAttachmentHidden: (void **) data inMemCtx: (TALLOC_CTX *) localMemCtx { - *data = MAPIBoolValue (localMemCtx, YES); - - return MAPISTORE_SUCCESS; + return [self getYes: data inMemCtx: localMemCtx]; } - (int) getPidTagAttachmentFlags: (void **) data @@ -81,6 +93,18 @@ return MAPISTORE_SUCCESS; } +- (int) getPidTagAttachmentLinkId: (void **) data + inMemCtx: (TALLOC_CTX *) localMemCtx +{ + return [self getLongZero: data inMemCtx: localMemCtx]; +} + +- (int) getPidTagAttachFlags: (void **) data + inMemCtx: (TALLOC_CTX *) localMemCtx +{ + return [self getLongZero: data inMemCtx: localMemCtx]; +} + - (int) getPidTagAttachMethod: (void **) data inMemCtx: (TALLOC_CTX *) localMemCtx { @@ -89,8 +113,28 @@ return MAPISTORE_SUCCESS; } -// case PidTagExceptionStartTime: -// case PidTagExceptionEndTime: +- (int) getPidTagAttachEncoding: (void **) data + inMemCtx: (TALLOC_CTX *) localMemCtx +{ + *data = [[NSData data] asBinaryInMemCtx: localMemCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagDisplayName: (void **) data + inMemCtx: (TALLOC_CTX *) localMemCtx +{ + *data = "Untitled"; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagAttachmentContactPhoto: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getNo: data inMemCtx: memCtx]; +} + // case PidTagExceptionReplaceTime: /* subclasses */ diff --git a/OpenChange/MAPIStoreCalendarEmbeddedMessage.m b/OpenChange/MAPIStoreCalendarEmbeddedMessage.m index 361b10d6f..7fa3274c3 100644 --- a/OpenChange/MAPIStoreCalendarEmbeddedMessage.m +++ b/OpenChange/MAPIStoreCalendarEmbeddedMessage.m @@ -98,6 +98,14 @@ return MAPISTORE_SUCCESS; } +- (int) getPidTagMessageFlags: (void **) data // TODO + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = MAPILongValue (memCtx, MSGFLAG_UNMODIFIED); + + return MAPISTORE_SUCCESS; +} + - (int) getPidTagProcessed: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getYes: data inMemCtx: memCtx]; @@ -109,6 +117,44 @@ return [self getYes: data inMemCtx: memCtx]; } +/* discarded properties */ + +- (int) getPidLidAppointmentLastSequence: (void **) + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidLidMeetingWorkspaceUrl: (void **) + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidLidContacts: (void **) + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagSensitivity: (void **) + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidLidPrivate: (void **) + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidNameKeywords: (void **) + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + - (void) save { // (gdb) po embeddedMessage->properties diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index f4dd3fbd6..fddadedf9 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -122,6 +122,7 @@ NSString *newKey; MAPIStoreCalendarAttachment *attachment; NSUInteger aid; + iCalEvent *event; events = [calendar events]; max = [events count]; @@ -133,8 +134,10 @@ right AID is 0 from the start */ aid = count - 1; [attachment setAID: aid]; - [attachment setEvent: [events objectAtIndex: count]]; - newKey = [NSString stringWithFormat: @"%ul", aid]; + event = [events objectAtIndex: count]; + [attachment setEvent: event]; + newKey = [[event uniqueChildWithTag: @"recurrence-id"] + flattenedValuesForKey: @""]; [attachmentParts setObject: attachment forKey: newKey]; } } @@ -201,14 +204,6 @@ return MAPISTORE_SUCCESS; } -- (int) getPidLidAppointmentMessageClass: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - *data = talloc_strdup (memCtx, "IPM.Appointment"); - - return MAPISTORE_SUCCESS; -} - - (int) getPidLidSideEffects: (void **) data // TODO inMemCtx: (TALLOC_CTX *) memCtx { @@ -422,41 +417,28 @@ return rc; } -- (void) _updateAttachedEvent: (MAPIStoreCalendarAttachment *) attachment - withUID: (NSString *) uid -{ - iCalEvent *newEvent; - SOGoUser *activeUser; - - newEvent = [iCalEvent groupWithTag: @"vevent"]; - [calendar addToEvents: newEvent]; - activeUser = [[self context] activeUser]; - [newEvent setUid: uid]; - [newEvent updateFromMAPIProperties: [attachment properties] - inUserContext: [self userContext] - withActiveUser: activeUser]; -} - - (void) _updateAttachedEvents { - NSMutableArray *otherEvents; NSArray *allAttachments; NSUInteger count, max; - NSString *uid; - - /* cleanup all recurring events */ - otherEvents = [[calendar events] mutableCopy]; - [otherEvents removeObject: masterEvent]; - [calendar removeChildren: otherEvents]; - [otherEvents release]; + NSString *uid, *summary; + iCalEvent *event; + MAPIStoreCalendarAttachment *attachment; + /* ensure that all exception events have the same UID as the master */ uid = [masterEvent uid]; + summary = [masterEvent summary]; allAttachments = [attachmentParts allValues]; max = [allAttachments count]; for (count = 0; count < max; count++) - [self _updateAttachedEvent: [allAttachments objectAtIndex: count] - withUID: uid]; + { + attachment = [allAttachments objectAtIndex: count]; + event = [attachment event]; + if ([[event summary] length] == 0) + [event setSummary: summary]; + [event setUid: uid]; + } } - (void) save @@ -513,12 +495,17 @@ MAPIStoreCalendarAttachment *newAttachment; uint32_t newAid; NSString *newKey; + iCalEvent *newEvent; newAid = [[self attachmentKeys] count]; newAttachment = [MAPIStoreCalendarAttachment mapiStoreObjectInContainer: self]; [newAttachment setAID: newAid]; + newEvent = [iCalEvent groupWithTag: @"vevent"]; + [newAttachment setEvent: newEvent]; + [calendar addToEvents: newEvent]; + newKey = [NSString stringWithFormat: @"%ul", newAid]; [attachmentParts setObject: newAttachment forKey: newKey]; diff --git a/OpenChange/MAPIStoreEmbeddedMessage.m b/OpenChange/MAPIStoreEmbeddedMessage.m index 63f093095..2d408e1ba 100644 --- a/OpenChange/MAPIStoreEmbeddedMessage.m +++ b/OpenChange/MAPIStoreEmbeddedMessage.m @@ -23,6 +23,8 @@ #import #import "MAPIStoreAttachment.h" +#import "MAPIStoreFolder.h" +#import "NSObject+MAPIStore.h" #import "MAPIStoreEmbeddedMessage.h" @@ -37,6 +39,30 @@ static Class MAPIStoreAttachmentK; MAPIStoreAttachmentK = [MAPIStoreAttachment class]; } +- (uint64_t) objectId +{ + NSString *objectKey; + MAPIStoreMessage *grandParent; + + grandParent = (MAPIStoreMessage *) [container container]; + + /* FIXME: this is a hack */ + objectKey = [NSString stringWithFormat: @"%@/%@/as-message", + [grandParent nameInContainer], + [container nameInContainer], + [self nameInContainer]]; + + return [(MAPIStoreFolder *) [grandParent container] + idForObjectWithKey: objectKey]; +} + +- (int) getPidTagAccessLevel: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getLongZero: data inMemCtx: memCtx]; +} + +/* disabled properties */ - (int) getPidTagFolderId: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -49,6 +75,12 @@ static Class MAPIStoreAttachmentK; return MAPISTORE_ERR_NOT_FOUND; } +- (int) getPidTagSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + - (int) getPidTagParentSourceKey: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -61,6 +93,49 @@ static Class MAPIStoreAttachmentK; return MAPISTORE_ERR_NOT_FOUND; } +- (int) getPidTagInstID: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagInstanceNum: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagRowType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagDepth: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagIconIndex: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagGenerateExchangeViews: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagOriginalMessageClass: (void **) dataa + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +/* common methods */ - (NSString *) nameInContainer { return @"as-message"; From 89865b66dba75fb4c147af162f3ca205785d2598 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 6 Aug 2012 19:51:59 +0000 Subject: [PATCH 062/127] Monotone-Parent: c4cd64ca35c43c187a23cc30e1bad4db1a5e9d1d Monotone-Revision: a627928e5439c333efd9a1bda334f534a91c3a30 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-06T19:51:59 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index ea56b998a..d2de77a4a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,9 +15,9 @@ 2012-08-03 Jean Raby * SoObjects/SOGo/LDAPSource.m (changePasswordForLogin): - if userPasswordAlgorithm was not set or was set to "none", - use the plaintext password directly instead of using '{none}plaintext' - which isn't valid. + if userPasswordAlgorithm was not set or was set to "none", + use the plaintext password directly instead of using '{none}plaintext' + which isn't valid. 2012-08-02 Ludovic Marcotte From c9a9d83e82a15915cd4b50321fc71918e2fe7f3b Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 7 Aug 2012 12:59:49 +0000 Subject: [PATCH 063/127] Monotone-Parent: a627928e5439c333efd9a1bda334f534a91c3a30 Monotone-Revision: fb5c07bbc778bf76fbbad3504f7d0d3af398045b Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-07T12:59:49 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++++ OpenChange/MAPIStoreMailVolatileMessage.m | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index d2de77a4a..f15a3879e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-08-07 Wolfgang Sourdeau + + * OpenChange/MAPIStoreMailVolatileMessage.m (-save): restored + registration of message url when saved. + 2012-08-06 Wolfgang Sourdeau * OpenChange/MAPIStoreRecurrenceUtils.m (-[iCalRecurrenceRule diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index 2af242f49..f673e4358 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -921,8 +921,9 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS NGImap4Client *client; SOGoMailFolder *containerFolder; NSDictionary *result, *responseResult; - // MAPIStoreMapping *mapping; - // uint64_t mid; + MAPIStoreMapping *mapping; + uint64_t mid; + BOOL registerAgain; messageData = [self _generateMailDataWithBcc: YES]; @@ -939,16 +940,17 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS responseResult = [[result objectForKey: @"RawResponse"] objectForKey: @"ResponseResult"]; flag = [responseResult objectForKey: @"flag"]; + newIdString = [[flag componentsSeparatedByString: @" "] objectAtIndex: 2]; - // mid = [self objectId]; - // mapping = [self mapping]; - // [mapping unregisterURLWithID: mid]; + mapping = [self mapping]; + mid = [self objectId]; + [mapping unregisterURLWithID: mid]; // [sogoObject setNameInContainer: ]; + messageKey = [NSString stringWithFormat: @"%@.eml", newIdString]; - // [mapping registerURL: [NSString stringWithFormat: @"%@%@", - // [(MAPIStoreMailFolder *) container url], messageKey] - // withID: mid]; + [sogoObject setNameInContainer: messageKey]; + [mapping registerURL: [self url] withID: mid]; /* synchronise the cache and update the change key with the one provided by the client */ From 5093fb964eac1d120f6b80b6ab997d892a0d5f43 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 7 Aug 2012 13:32:35 +0000 Subject: [PATCH 064/127] Monotone-Parent: fb5c07bbc778bf76fbbad3504f7d0d3af398045b Monotone-Revision: 355e6e150effcfc0fdb8c4139071a1a734173bda Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-07T13:32:35 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreMailVolatileMessage.m | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index f673e4358..e3764fdc2 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -923,7 +923,6 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS NSDictionary *result, *responseResult; MAPIStoreMapping *mapping; uint64_t mid; - BOOL registerAgain; messageData = [self _generateMailDataWithBcc: YES]; From f2e72f108fcc0ad78a0f167bed6e9df9e15111d0 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 7 Aug 2012 15:35:31 +0000 Subject: [PATCH 065/127] Monotone-Parent: 355e6e150effcfc0fdb8c4139071a1a734173bda Monotone-Revision: de8a628ccf75e9a2e0e0a0ce276c536a91eeb716 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-07T15:35:31 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++ .../Appointments/SOGoAptMailNotification.m | 54 +++++++++++-------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index f15a3879e..98cd188e0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-08-07 Wolfgang Sourdeau + * SoObjects/Appointments/SOGoAptMailNotification.m (-setupValues): + test whether each value is non-nil before adding it to the + dictionary. + * OpenChange/MAPIStoreMailVolatileMessage.m (-save): restored registration of message url when saved. diff --git a/SoObjects/Appointments/SOGoAptMailNotification.m b/SoObjects/Appointments/SOGoAptMailNotification.m index 70f911592..63c694103 100644 --- a/SoObjects/Appointments/SOGoAptMailNotification.m +++ b/SoObjects/Appointments/SOGoAptMailNotification.m @@ -173,8 +173,8 @@ - (void) setupValues { - NSString *sentBy, *sentByText, *description; - NSCalendarDate *date; + NSString *sentByText; + id value; NSDictionary *sentByValues; SOGoUser *user; SOGoDateFormatter *dateFormatter; @@ -184,15 +184,18 @@ [viewTZ retain]; values = [NSMutableDictionary new]; - [values setObject: [self summary] forKey: @"Summary"]; + value = [self summary]; + if (!value) + value = @""; + [values setObject: value forKey: @"Summary"]; if (organizerName) { [values setObject: organizerName forKey: @"Organizer"]; - sentBy = [[apt organizer] sentBy]; - if ([sentBy length]) + value = [[apt organizer] sentBy]; + if (value) { - sentByValues = [NSDictionary dictionaryWithObject: sentBy + sentByValues = [NSDictionary dictionaryWithObject: value forKey: @"SentBy"]; sentByText = [sentByValues keysWithFormat: [self @@ -201,29 +204,36 @@ } else sentByText = @""; + [values setObject: sentByText forKey: @"SentByText"]; } dateFormatter = [[context activeUser] dateFormatterInContext: context]; - date = [self newStartDate]; - [values setObject: [dateFormatter shortFormattedDate: date] - forKey: @"StartDate"]; - if (![apt isAllDay]) - [values setObject: [dateFormatter formattedTime: date] - forKey: @"StartTime"]; + value = [self newStartDate]; + if (value) + { + [values setObject: [dateFormatter shortFormattedDate: value] + forKey: @"StartDate"]; + if (![apt isAllDay]) + [values setObject: [dateFormatter formattedTime: value] + forKey: @"StartTime"]; + } - date = [self newEndDate]; - [values setObject: [dateFormatter shortFormattedDate: date] - forKey: @"EndDate"]; - if (![apt isAllDay]) - [values setObject: [dateFormatter formattedTime: date] - forKey: @"EndTime"]; - - description = [[self apt] comment]; - [values setObject: (description ? description : @"") - forKey: @"Description"]; + value = [self newEndDate]; + if (value) + { + [values setObject: [dateFormatter shortFormattedDate: value] + forKey: @"EndDate"]; + if (![apt isAllDay]) + [values setObject: [dateFormatter formattedTime: value] + forKey: @"EndTime"]; + } + value = [[self apt] comment]; + if (!value) + value = @""; + [values setObject: value forKey: @"Description"]; } @end From 5a7f357029633f859393099af05169015d1d73e3 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 7 Aug 2012 23:59:48 +0000 Subject: [PATCH 066/127] Monotone-Parent: de8a628ccf75e9a2e0e0a0ce276c536a91eeb716 Monotone-Revision: 102075f3748e18c36cc8606ce5e2e1de4dfcae13 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-07T23:59:48 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreContactsMessageTable.m | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/OpenChange/MAPIStoreContactsMessageTable.m b/OpenChange/MAPIStoreContactsMessageTable.m index 406329bab..e46a5813e 100644 --- a/OpenChange/MAPIStoreContactsMessageTable.m +++ b/OpenChange/MAPIStoreContactsMessageTable.m @@ -74,10 +74,12 @@ static Class MAPIStoreContactsMessageK, NGMailAddressK, NSDataK, NSStringK; forKey: MAPIPropertyKey (PidLidEmail2EmailAddress)]; [knownProperties setObject: @"c_mail" forKey: MAPIPropertyKey (PidLidEmail3EmailAddress)]; - [knownProperties setObject: @"c_cn" - forKey: MAPIPropertyKey (PR_DISPLAY_NAME_UNICODE)]; [knownProperties setObject: @"c_cn" forKey: MAPIPropertyKey (PidLidFileUnder)]; + [knownProperties setObject: @"c_cn" + forKey: MAPIPropertyKey (PidTagDisplayName)]; + [knownProperties setObject: @"c_cn" + forKey: MAPIPropertyKey (PidTagSubject)]; } return [knownProperties objectForKey: MAPIPropertyKey (property)]; @@ -213,7 +215,11 @@ static Class MAPIStoreContactsMessageK, NGMailAddressK, NSDataK, NSStringK; [knownProperties setObject: @"c_cn" forKey: MAPIPropertyKey (PidLidFileUnder)]; [knownProperties setObject: @"c_cn" - forKey: MAPIPropertyKey (PR_DISPLAY_NAME_UNICODE)]; + forKey: MAPIPropertyKey (PidTagDisplayName)]; + [knownProperties setObject: @"c_cn" + forKey: MAPIPropertyKey (PidTagSubject)]; + [knownProperties setObject: @"c_cn" + forKey: MAPIPropertyKey (PidTagNormalizedSubject)]; } return [knownProperties objectForKey: MAPIPropertyKey (property)]; From 812c7486b2e75ce82189e5e249cbcd565f113f53 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 8 Aug 2012 17:39:18 +0000 Subject: [PATCH 067/127] Monotone-Parent: 102075f3748e18c36cc8606ce5e2e1de4dfcae13 Monotone-Revision: cd55270af0875980e8fd804d528743a3c0103fe8 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-08T17:39:18 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++++ OpenChange/MAPIApplication.m | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/ChangeLog b/ChangeLog index 98cd188e0..a3e54ec45 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-08-08 Wolfgang Sourdeau + + * OpenChange/MAPIApplication.m (-shouldSetupSignalHandlers): + overriden method by returning "NO". + 2012-08-07 Wolfgang Sourdeau * SoObjects/Appointments/SOGoAptMailNotification.m (-setupValues): diff --git a/OpenChange/MAPIApplication.m b/OpenChange/MAPIApplication.m index ecf3bedb0..b4ad58073 100644 --- a/OpenChange/MAPIApplication.m +++ b/OpenChange/MAPIApplication.m @@ -66,6 +66,11 @@ MAPIApplication *MAPIApp = nil; return MAPIApp; } +- (BOOL) shouldSetupSignalHandlers +{ + return NO; +} + - (void) setUserContext: (MAPIStoreUserContext *) newContext { /* user contexts must not be retained here ad their holder (mapistore) From 7a05ec77deeaede334d277dd641a57b40a967c3f Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 8 Aug 2012 19:09:22 +0000 Subject: [PATCH 068/127] Monotone-Parent: cd55270af0875980e8fd804d528743a3c0103fe8 Monotone-Revision: ae2f3622e019b557af4f9dd642911dec3afe7ba1 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-08T19:09:22 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/MAPIStoreMessage.m | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/ChangeLog b/ChangeLog index a3e54ec45..bdf6c4779 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-08-08 Wolfgang Sourdeau + * OpenChange/MAPIStoreMessage.m (-saveMessage): make sure that the + PidTagChangeKey and PidTagChangeNumber props are no longer set in + the properties dict after the save occurred. + * OpenChange/MAPIApplication.m (-shouldSetupSignalHandlers): overriden method by returning "NO". diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index a5a8827ab..febdb629c 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -496,6 +496,11 @@ rtf2html (NSData *compressedRTF) } [self save]; + /* We make sure that any change-related properties are removes from the + properties dictionary, to make sure that related methods will be + invoked the next time they are requested. */ + [properties removeObjectForKey: MAPIPropertyKey (PidTagChangeKey)]; + [properties removeObjectForKey: MAPIPropertyKey (PidTagChangeNumber)]; if ([container isKindOfClass: MAPIStoreFolderK]) { From 4940c2ba488777039e54f3ad7e0d0cdb3dc9d62c Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 8 Aug 2012 19:10:28 +0000 Subject: [PATCH 069/127] Monotone-Parent: ae2f3622e019b557af4f9dd642911dec3afe7ba1 Monotone-Revision: 86fd1ace33a761145516f77910d46684fbe4f423 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-08T19:10:28 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/MAPIStoreCalendarMessage.m | 26 ++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index bdf6c4779..c7ade139a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-08-08 Wolfgang Sourdeau + * OpenChange/MAPIStoreCalendarMessage.m (-save): generate a + "nameInContainer" for the new object iif it is not set yet. If + set, we generate a new UID from it instead. + * OpenChange/MAPIStoreMessage.m (-saveMessage): make sure that the PidTagChangeKey and PidTagChangeNumber props are no longer set in the properties dict after the save occurred. diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index fddadedf9..7900135f1 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -445,10 +445,11 @@ { // iCalCalendar *vCalendar; // NSCalendarDate *now; - NSString *uid; + NSString *uid, *nameInContainer; // iCalEvent *newEvent; // iCalPerson *userPerson; SOGoUser *activeUser; + NSRange rangeOfDot; if (isNew) { @@ -463,10 +464,27 @@ [self _fixupAppointmentObjectWithUID: uid]; } else - uid = [SOGoObject globallyUniqueObjectId]; + { + /* We create a UID from the nameInContainer, or the reverse if the + latter is already set... */ + nameInContainer = [sogoObject nameInContainer]; + if (nameInContainer) + { + rangeOfDot = [nameInContainer rangeOfString: @"." + options: NSBackwardsSearch]; + if (rangeOfDot.location == NSNotFound) + uid = nameInContainer; + else + uid = [nameInContainer substringToIndex: rangeOfDot.location]; + } + else + { + uid = [SOGoObject globallyUniqueObjectId]; + nameInContainer = [NSString stringWithFormat: @"%@.ics", uid]; + [sogoObject setNameInContainer: nameInContainer]; + } + } [masterEvent setUid: uid]; - [sogoObject setNameInContainer: - [NSString stringWithFormat: @"%@.ics", uid]]; } // [self logWithFormat: @"-save, event props:"]; From c2a63a3d8e0af7dbdd31fc590e224b4c423bbea6 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 9 Aug 2012 19:42:38 +0000 Subject: [PATCH 070/127] Monotone-Parent: 86fd1ace33a761145516f77910d46684fbe4f423 Monotone-Revision: 3ded00a80ce87781ff6767f6fe38a12735a48340 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-09T19:42:38 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreDBFolder.m | 1 + OpenChange/MAPIStoreMessageTable.m | 1 + OpenChange/MAPIStorePermissionsTable.m | 3 +-- OpenChange/MAPIStoreUserContext.m | 1 + OpenChange/SOGoMAPIObject.m | 3 +++ 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreDBFolder.m b/OpenChange/MAPIStoreDBFolder.m index d8af710ad..21c542f81 100644 --- a/OpenChange/MAPIStoreDBFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -29,6 +29,7 @@ #import #import #import +#import #import #import "EOQualifier+MAPI.h" #import "MAPIStoreContext.h" diff --git a/OpenChange/MAPIStoreMessageTable.m b/OpenChange/MAPIStoreMessageTable.m index 3c08e2bab..f93ec13da 100644 --- a/OpenChange/MAPIStoreMessageTable.m +++ b/OpenChange/MAPIStoreMessageTable.m @@ -29,6 +29,7 @@ #import "MAPIStoreContext.h" #import "MAPIStoreFolder.h" +#import "MAPIStoreMessage.h" #import "MAPIStoreTypes.h" #import "NSData+MAPIStore.h" #import "NSString+MAPIStore.h" diff --git a/OpenChange/MAPIStorePermissionsTable.m b/OpenChange/MAPIStorePermissionsTable.m index 2385ee8a5..b5704610b 100644 --- a/OpenChange/MAPIStorePermissionsTable.m +++ b/OpenChange/MAPIStorePermissionsTable.m @@ -23,7 +23,6 @@ #import #import #import - #import #import #import @@ -103,7 +102,7 @@ entryId = [NSData data]; else { - connInfo = [[container context] connectionInfo]; + connInfo = [(MAPIStoreContext *) [container context] connectionInfo]; entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, userId); } *data = [entryId asBinaryInMemCtx: memCtx]; diff --git a/OpenChange/MAPIStoreUserContext.m b/OpenChange/MAPIStoreUserContext.m index 2d6097277..9489eba44 100644 --- a/OpenChange/MAPIStoreUserContext.m +++ b/OpenChange/MAPIStoreUserContext.m @@ -25,6 +25,7 @@ #import #import #import +#import #import #import diff --git a/OpenChange/SOGoMAPIObject.m b/OpenChange/SOGoMAPIObject.m index ec8a9ae52..178202963 100644 --- a/OpenChange/SOGoMAPIObject.m +++ b/OpenChange/SOGoMAPIObject.m @@ -20,6 +20,9 @@ * Boston, MA 02111-1307, USA. */ +#import +#import + #import "SOGoMAPIObject.h" @implementation SOGoMAPIObject From 700d23e80eaeab7d28039dbce6a86d781ae12622 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 9 Aug 2012 19:43:17 +0000 Subject: [PATCH 071/127] Monotone-Parent: 3ded00a80ce87781ff6767f6fe38a12735a48340 Monotone-Revision: af0fb5901615e40ad3549c59f74f88bb33f9b392 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-09T19:43:17 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++ OpenChange/MAPIStoreFolder.h | 8 ++++ OpenChange/MAPIStoreFolder.m | 15 +++++++ OpenChange/MAPIStoreSOGo.m | 82 ++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+) diff --git a/ChangeLog b/ChangeLog index c7ade139a..f10711b10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-08-09 Wolfgang Sourdeau + + * OpenChange/MAPIStoreSOGo.m (sogo_folder_move_folder) + (sogo_folder_copy_folder): new backend methods. + 2012-08-08 Wolfgang Sourdeau * OpenChange/MAPIStoreCalendarMessage.m (-save): generate a diff --git a/OpenChange/MAPIStoreFolder.h b/OpenChange/MAPIStoreFolder.h index b29a93d3d..3e65423ee 100644 --- a/OpenChange/MAPIStoreFolder.h +++ b/OpenChange/MAPIStoreFolder.h @@ -123,6 +123,14 @@ andChangeKeys: (struct Binary_r **) targetChangeKeys wantCopy: (uint8_t) want_copy; +- (enum mapistore_error) moveFolderWithFID: (uint64_t) fid + fromFolder: (MAPIStoreFolder *) sourceFolder + withNewName: (NSString *) newFolderName; +- (enum mapistore_error) copyFolderWithFID: (uint64_t) fid + fromFolder: (MAPIStoreFolder *) sourceFolder + recursive: (BOOL) resursive + withNewName: (NSString *) newFolderName; + - (int) getDeletedFMIDs: (struct I8Array_r **) fmidsPtr andCN: (uint64_t *) cnPtr fromChangeNumber: (uint64_t) changeNum diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index f4128695d..4beafc5b3 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -795,6 +795,21 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe return rc; } +- (enum mapistore_error) moveFolderWithFID: (uint64_t) fid + fromFolder: (MAPIStoreFolder *) sourceFolder + withNewName: (NSString *) newFolderName +{ + return MAPISTORE_ERR_DENIED; +} + +- (enum mapistore_error) copyFolderWithFID: (uint64_t) fid + fromFolder: (MAPIStoreFolder *) sourceFolder + recursive: (BOOL) resursive + withNewName: (NSString *) newFolderName +{ + return MAPISTORE_ERR_DENIED; +} + - (SOGoFolder *) aclFolder { [self subclassResponsibility: _cmd]; diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 2dd78074b..09dfa596a 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -608,6 +608,86 @@ sogo_folder_move_copy_messages(void *folder_object, return rc; } +static enum mapistore_error +sogo_folder_move_folder(void *folder_object, void *source_folder_object, + uint64_t fid, const char *new_folder_name) +{ + MAPIStoreFolder *sourceFolder, *targetFolder; + NSAutoreleasePool *pool; + NSString *newFolderName; + struct MAPIStoreTallocWrapper *wrapper; + int rc; + + DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + + if (folder_object) + { + wrapper = folder_object; + targetFolder = wrapper->instance; + + wrapper = source_folder_object; + sourceFolder = wrapper->instance; + + GSRegisterCurrentThread (); + pool = [NSAutoreleasePool new]; + + newFolderName = [NSString stringWithUTF8String: new_folder_name]; + + rc = [targetFolder moveFolderWithFID: fid + fromFolder: sourceFolder + withNewName: newFolderName]; + [pool release]; + GSUnregisterCurrentThread (); + } + else + { + rc = sogo_backend_unexpected_error(); + } + + return rc; +} + +static enum mapistore_error +sogo_folder_copy_folder(void *folder_object, void *source_folder_object, + uint64_t fid, bool recursive, + const char *new_folder_name) +{ + MAPIStoreFolder *sourceFolder, *targetFolder; + NSAutoreleasePool *pool; + NSString *newFolderName; + struct MAPIStoreTallocWrapper *wrapper; + int rc; + + DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + + if (folder_object) + { + wrapper = folder_object; + targetFolder = wrapper->instance; + + wrapper = source_folder_object; + sourceFolder = wrapper->instance; + + GSRegisterCurrentThread (); + pool = [NSAutoreleasePool new]; + + newFolderName = [NSString stringWithUTF8String: new_folder_name]; + + rc = [targetFolder copyFolderWithFID: fid + fromFolder: sourceFolder + recursive: recursive + withNewName: newFolderName]; + [pool release]; + GSUnregisterCurrentThread (); + } + else + { + rc = sogo_backend_unexpected_error(); + } + + return rc; +} + static enum mapistore_error sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx, enum mapistore_table_type table_type, uint64_t change_num, @@ -1414,6 +1494,8 @@ int mapistore_init_backend(void) backend.folder.create_message = sogo_folder_create_message; backend.folder.delete_message = sogo_folder_delete_message; backend.folder.move_copy_messages = sogo_folder_move_copy_messages; + backend.folder.move_folder = sogo_folder_move_folder; + backend.folder.copy_folder = sogo_folder_copy_folder; backend.folder.get_deleted_fmids = sogo_folder_get_deleted_fmids; backend.folder.get_child_count = sogo_folder_get_child_count; backend.folder.open_table = sogo_folder_open_table; From 830a3687b924d587db5f2073057700ed7e1e68f1 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 9 Aug 2012 21:34:27 +0000 Subject: [PATCH 072/127] Monotone-Parent: af0fb5901615e40ad3549c59f74f88bb33f9b392 Monotone-Revision: 5a88c883713608f144b55bfcc8139174ad4ab129 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-09T21:34:27 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 2 ++ OpenChange/MAPIStoreSOGo.m | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index f10711b10..b04463fdc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,8 @@ * OpenChange/MAPIStoreSOGo.m (sogo_folder_move_folder) (sogo_folder_copy_folder): new backend methods. + (sogo_folder_move_folder): do not instantiate an NSString from a + NULL "new_folder_name" parameter. 2012-08-08 Wolfgang Sourdeau diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 09dfa596a..aaac2bcf7 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -631,7 +631,10 @@ sogo_folder_move_folder(void *folder_object, void *source_folder_object, GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; - newFolderName = [NSString stringWithUTF8String: new_folder_name]; + if (new_folder_name) + newFolderName = [NSString stringWithUTF8String: new_folder_name]; + else + newFolderName = nil; rc = [targetFolder moveFolderWithFID: fid fromFolder: sourceFolder From b13fe70bebeb5bb977cee5a6ee773aa7e9b57de5 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 9 Aug 2012 21:35:09 +0000 Subject: [PATCH 073/127] Monotone-Parent: 5a88c883713608f144b55bfcc8139174ad4ab129 Monotone-Revision: 9f415bbce0de3939851adeff8e3f25986b8630f7 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-09T21:35:09 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/MAPIStoreMailFolder.m | 41 +++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index b04463fdc..d7dde49dd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-08-09 Wolfgang Sourdeau + * OpenChange/MAPIStoreMailFolder.m + (-moveFolderWithFID:fromFolder:withNewName:): first implementation + for IMAP folders. + * OpenChange/MAPIStoreSOGo.m (sogo_folder_move_folder) (sogo_folder_copy_folder): new backend methods. (sogo_folder_move_folder): do not instantiate an NSString from a diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 8fffd8d9d..ffac80999 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -60,7 +60,7 @@ #import "MAPIStoreMailFolder.h" -static Class SOGoMailFolderK, MAPIStoreOutboxFolderK; +static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; #undef DEBUG #include @@ -73,6 +73,7 @@ static Class SOGoMailFolderK, MAPIStoreOutboxFolderK; + (void) initialize { SOGoMailFolderK = [SOGoMailFolder class]; + MAPIStoreMailFolderK = [MAPIStoreMailFolder class]; MAPIStoreOutboxFolderK = [MAPIStoreOutboxFolder class]; [MAPIStoreAppointmentWrapper class]; } @@ -1002,6 +1003,44 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) return MAPISTORE_SUCCESS; } +- (enum mapistore_error) moveFolderWithFID: (uint64_t) fid + fromFolder: (MAPIStoreFolder *) sourceFolder + withNewName: (NSString *) newFolderName +{ + enum mapistore_error rc; + MAPIStoreMailFolder *moveFolder; + NSURL *folderURL, *newFolderURL; + SOGoMailFolder *sogoMoveFolder; + NSException *error; + + if ([sourceFolder isKindOfClass: MAPIStoreMailFolderK]) + { + rc = [sourceFolder openFolder: &moveFolder withFID: fid]; + if (rc == MAPISTORE_SUCCESS) + { + sogoMoveFolder = [moveFolder sogoObject]; + folderURL = [sogoMoveFolder imap4URL]; + if (!newFolderName) + newFolderName = [sogoMoveFolder nameInContainer]; + newFolderURL = [NSURL URLWithString: newFolderName + relativeToURL: [sogoObject imap4URL]]; + error = [[sogoMoveFolder imap4Connection] + moveMailboxAtURL: folderURL + toURL: newFolderURL]; + if (error) + rc = MAPISTORE_ERR_DENIED; + else + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + } + else + rc = MAPISTORE_ERR_DENIED; + + return rc; +} + - (MAPIStoreMessage *) createMessage { SOGoMAPIObject *childObject; From 32af60c24facfa359e2344ca181a7b833d6da71e Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 10 Aug 2012 14:08:40 +0000 Subject: [PATCH 074/127] Monotone-Parent: 9f415bbce0de3939851adeff8e3f25986b8630f7 Monotone-Revision: 1bf1a3f87feb2c04469fcff28770c25704ee5aab Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-10T14:08:40 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 6 +++++ OpenChange/MAPIStoreFolder.h | 12 ++++------ OpenChange/MAPIStoreFolder.m | 12 ++++------ OpenChange/MAPIStoreMailFolder.m | 40 +++++++++++++------------------- OpenChange/MAPIStoreSOGo.m | 37 ++++++++++++++--------------- 5 files changed, 49 insertions(+), 58 deletions(-) diff --git a/ChangeLog b/ChangeLog index d7dde49dd..ef359d4e4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-08-10 Wolfgang Sourdeau + + * OpenChange/MAPIStoreSOGo.m (sogo_folder_move_folder) + (sogo_folder_copy_folder): the object on which the backend method + is invoked is now the folder being moved rather than its parent. + 2012-08-09 Wolfgang Sourdeau * OpenChange/MAPIStoreMailFolder.m diff --git a/OpenChange/MAPIStoreFolder.h b/OpenChange/MAPIStoreFolder.h index 3e65423ee..bb2aefec1 100644 --- a/OpenChange/MAPIStoreFolder.h +++ b/OpenChange/MAPIStoreFolder.h @@ -123,13 +123,11 @@ andChangeKeys: (struct Binary_r **) targetChangeKeys wantCopy: (uint8_t) want_copy; -- (enum mapistore_error) moveFolderWithFID: (uint64_t) fid - fromFolder: (MAPIStoreFolder *) sourceFolder - withNewName: (NSString *) newFolderName; -- (enum mapistore_error) copyFolderWithFID: (uint64_t) fid - fromFolder: (MAPIStoreFolder *) sourceFolder - recursive: (BOOL) resursive - withNewName: (NSString *) newFolderName; +- (enum mapistore_error) moveToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName; +- (enum mapistore_error) copyToFolder: (MAPIStoreFolder *) targetFolder + recursive: (BOOL) resursive + withNewName: (NSString *) newFolderName; - (int) getDeletedFMIDs: (struct I8Array_r **) fmidsPtr andCN: (uint64_t *) cnPtr diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 4beafc5b3..50b635c06 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -795,17 +795,15 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe return rc; } -- (enum mapistore_error) moveFolderWithFID: (uint64_t) fid - fromFolder: (MAPIStoreFolder *) sourceFolder - withNewName: (NSString *) newFolderName +- (enum mapistore_error) moveToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName { return MAPISTORE_ERR_DENIED; } -- (enum mapistore_error) copyFolderWithFID: (uint64_t) fid - fromFolder: (MAPIStoreFolder *) sourceFolder - recursive: (BOOL) resursive - withNewName: (NSString *) newFolderName +- (enum mapistore_error) copyToFolder: (MAPIStoreFolder *) targetFolder + recursive: (BOOL) resursive + withNewName: (NSString *) newFolderName { return MAPISTORE_ERR_DENIED; } diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index ffac80999..01907accb 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1003,37 +1003,29 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) return MAPISTORE_SUCCESS; } -- (enum mapistore_error) moveFolderWithFID: (uint64_t) fid - fromFolder: (MAPIStoreFolder *) sourceFolder - withNewName: (NSString *) newFolderName +- (enum mapistore_error) moveToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName { enum mapistore_error rc; - MAPIStoreMailFolder *moveFolder; NSURL *folderURL, *newFolderURL; - SOGoMailFolder *sogoMoveFolder; + SOGoMailFolder *targetSOGoFolder; NSException *error; - if ([sourceFolder isKindOfClass: MAPIStoreMailFolderK]) + if ([targetFolder isKindOfClass: MAPIStoreMailFolderK]) { - rc = [sourceFolder openFolder: &moveFolder withFID: fid]; - if (rc == MAPISTORE_SUCCESS) - { - sogoMoveFolder = [moveFolder sogoObject]; - folderURL = [sogoMoveFolder imap4URL]; - if (!newFolderName) - newFolderName = [sogoMoveFolder nameInContainer]; - newFolderURL = [NSURL URLWithString: newFolderName - relativeToURL: [sogoObject imap4URL]]; - error = [[sogoMoveFolder imap4Connection] - moveMailboxAtURL: folderURL - toURL: newFolderURL]; - if (error) - rc = MAPISTORE_ERR_DENIED; - else - rc = MAPISTORE_SUCCESS; - } + folderURL = [sogoObject imap4URL]; + if (!newFolderName) + newFolderName = [sogoObject nameInContainer]; + targetSOGoFolder = [targetFolder sogoObject]; + newFolderURL = [NSURL URLWithString: newFolderName + relativeToURL: [targetSOGoFolder imap4URL]]; + error = [[sogoObject imap4Connection] + moveMailboxAtURL: folderURL + toURL: newFolderURL]; + if (error) + rc = MAPISTORE_ERR_DENIED; else - rc = MAPISTORE_ERR_NOT_FOUND; + rc = MAPISTORE_SUCCESS; } else rc = MAPISTORE_ERR_DENIED; diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index aaac2bcf7..276bd6268 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -609,11 +609,11 @@ sogo_folder_move_copy_messages(void *folder_object, } static enum mapistore_error -sogo_folder_move_folder(void *folder_object, void *source_folder_object, - uint64_t fid, const char *new_folder_name) +sogo_folder_move_folder(void *folder_object, void *target_folder_object, + const char *new_folder_name) { - MAPIStoreFolder *sourceFolder, *targetFolder; NSAutoreleasePool *pool; + MAPIStoreFolder *moveFolder, *targetFolder; NSString *newFolderName; struct MAPIStoreTallocWrapper *wrapper; int rc; @@ -623,10 +623,10 @@ sogo_folder_move_folder(void *folder_object, void *source_folder_object, if (folder_object) { wrapper = folder_object; - targetFolder = wrapper->instance; + moveFolder = wrapper->instance; - wrapper = source_folder_object; - sourceFolder = wrapper->instance; + wrapper = target_folder_object; + targetFolder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; @@ -636,9 +636,8 @@ sogo_folder_move_folder(void *folder_object, void *source_folder_object, else newFolderName = nil; - rc = [targetFolder moveFolderWithFID: fid - fromFolder: sourceFolder - withNewName: newFolderName]; + rc = [moveFolder moveToFolder: targetFolder + withNewName: newFolderName]; [pool release]; GSUnregisterCurrentThread (); } @@ -651,12 +650,11 @@ sogo_folder_move_folder(void *folder_object, void *source_folder_object, } static enum mapistore_error -sogo_folder_copy_folder(void *folder_object, void *source_folder_object, - uint64_t fid, bool recursive, - const char *new_folder_name) +sogo_folder_copy_folder(void *folder_object, void *target_folder_object, + bool recursive, const char *new_folder_name) { - MAPIStoreFolder *sourceFolder, *targetFolder; NSAutoreleasePool *pool; + MAPIStoreFolder *copyFolder, *targetFolder; NSString *newFolderName; struct MAPIStoreTallocWrapper *wrapper; int rc; @@ -666,20 +664,19 @@ sogo_folder_copy_folder(void *folder_object, void *source_folder_object, if (folder_object) { wrapper = folder_object; - targetFolder = wrapper->instance; + copyFolder = wrapper->instance; - wrapper = source_folder_object; - sourceFolder = wrapper->instance; + wrapper = target_folder_object; + targetFolder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; newFolderName = [NSString stringWithUTF8String: new_folder_name]; - rc = [targetFolder copyFolderWithFID: fid - fromFolder: sourceFolder - recursive: recursive - withNewName: newFolderName]; + rc = [copyFolder copyToFolder: targetFolder + recursive: recursive + withNewName: newFolderName]; [pool release]; GSUnregisterCurrentThread (); } From a735498d7be72a9a4ceffe7391f2039b1bc249a9 Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Fri, 10 Aug 2012 12:29:31 +0000 Subject: [PATCH 075/127] See ChangeLog Monotone-Parent: 1bf1a3f87feb2c04469fcff28770c25704ee5aab Monotone-Revision: 1b66e85ded0b1d64105f0f5d2035ef81e9a8eb4f Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2012-08-10T12:29:31 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 6 ++++++ OpenChange/SOGoMAPIDBObject.m | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ef359d4e4..d44865ec4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-08-10 Ludovic Marcotte + + * Changed OpenChange/SOGoMAPIDBObject.m so we use + GNUstep's binary encoding - which is an order or + magnitude faster at encoding data than any other formats. + 2012-08-10 Wolfgang Sourdeau * OpenChange/MAPIStoreSOGo.m (sogo_folder_move_folder) diff --git a/OpenChange/SOGoMAPIDBObject.m b/OpenChange/SOGoMAPIDBObject.m index b80af8fc5..f5014dd52 100644 --- a/OpenChange/SOGoMAPIDBObject.m +++ b/OpenChange/SOGoMAPIDBObject.m @@ -428,7 +428,7 @@ static EOAttribute *textColumn = nil; { content = [NSPropertyListSerialization dataFromPropertyList: properties - format: NSPropertyListBinaryFormat_v1_0 + format: NSPropertyListGNUstepBinaryFormat errorDescription: NULL]; propsValue = [adaptor formatValue: [content stringByEncodingBase64] forAttribute: textColumn]; From dd48699bb325947df25af48b95eafbc1d0520e30 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 10 Aug 2012 21:03:05 +0000 Subject: [PATCH 076/127] Monotone-Parent: 1b66e85ded0b1d64105f0f5d2035ef81e9a8eb4f Monotone-Revision: 8d4ca03b16c54609dce23f43fc358a43d7e96d99 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-10T21:03:05 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++++ OpenChange/MAPIStoreObject.h | 3 +++ OpenChange/MAPIStoreObject.m | 18 ++++++++++++++++++ OpenChange/MAPIStoreSOGo.m | 30 ++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/ChangeLog b/ChangeLog index d44865ec4..52a6b1e59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-08-10 Wolfgang Sourdeau + + * OpenChange/MAPIStoreSOGo.m (sogo_properties_get_uri): new + backend method. + 2012-08-10 Ludovic Marcotte * Changed OpenChange/SOGoMAPIDBObject.m so we use diff --git a/OpenChange/MAPIStoreObject.h b/OpenChange/MAPIStoreObject.h index ddb28ada0..6918184a4 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -68,6 +68,9 @@ - (NSMutableDictionary *) properties; /* ops */ +- (enum mapistore_error) getURI: (char **) uriP + inMemCtx: (TALLOC_CTX *) memCtx; + - (int) getProperties: (struct mapistore_property_data *) data withTags: (enum MAPITAGS *) tags andCount: (uint16_t) columnCount diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index eba69c966..a751927e4 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -150,6 +150,24 @@ static Class NSExceptionK, MAPIStoreFolderK; return properties; } +- (enum mapistore_error) getURI: (char **) uriP + inMemCtx: (TALLOC_CTX *) memCtx +{ + enum mapistore_error rc; + NSString *url; + + url = [self url]; + if (url) + { + *uriP = [url asUnicodeInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + - (int) getProperty: (void **) data withTag: (enum MAPITAGS) propTag inMemCtx: (TALLOC_CTX *) memCtx diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 276bd6268..8d31a11dc 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -1325,6 +1325,35 @@ sogo_table_handle_destructor (void *table_object, uint32_t handle_id) return rc; } +static enum mapistore_error sogo_properties_get_uri(void *object, + TALLOC_CTX *mem_ctx, + char **uriP) +{ + struct MAPIStoreTallocWrapper *wrapper; + NSAutoreleasePool *pool; + MAPIStoreObject *propObject; + int rc; + + DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + + if (object) + { + wrapper = object; + propObject = wrapper->instance; + GSRegisterCurrentThread (); + pool = [NSAutoreleasePool new]; + rc = [propObject getURI: uriP inMemCtx: mem_ctx]; + [pool release]; + GSUnregisterCurrentThread (); + } + else + { + rc = sogo_backend_unexpected_error(); + } + + return rc; +} + static enum mapistore_error sogo_properties_get_available_properties(void *object, TALLOC_CTX *mem_ctx, struct SPropTagArray **propertiesP) @@ -1517,6 +1546,7 @@ int mapistore_init_backend(void) backend.table.get_row = sogo_table_get_row; backend.table.get_row_count = sogo_table_get_row_count; backend.table.handle_destructor = sogo_table_handle_destructor; + backend.properties.get_uri = sogo_properties_get_uri; backend.properties.get_available_properties = sogo_properties_get_available_properties; backend.properties.get_properties = sogo_properties_get_properties; backend.properties.set_properties = sogo_properties_set_properties; From e146ba68e64dbe259b063e7babadecbf3b8e99ba Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 03:55:48 +0000 Subject: [PATCH 077/127] Monotone-Parent: 8d4ca03b16c54609dce23f43fc358a43d7e96d99 Monotone-Revision: 047b040e318a98223980da2af8241b7eb6d75341 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T03:55:48 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++ OpenChange/MAPIStoreMapping.h | 2 + OpenChange/MAPIStoreMapping.m | 84 +++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/ChangeLog b/ChangeLog index 52a6b1e59..f949ad0f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-08-12 Wolfgang Sourdeau + + * OpenChange/MAPIStoreMapping.m (-updateID:withURL:): new method + that perform a change of url on container and leaf entries. + 2012-08-10 Wolfgang Sourdeau * OpenChange/MAPIStoreSOGo.m (sogo_properties_get_uri): new diff --git a/OpenChange/MAPIStoreMapping.h b/OpenChange/MAPIStoreMapping.h index 484c74da3..74b320aa0 100644 --- a/OpenChange/MAPIStoreMapping.h +++ b/OpenChange/MAPIStoreMapping.h @@ -54,6 +54,8 @@ - (BOOL) registerURL: (NSString *) urlString withID: (uint64_t) idNbr; - (void) unregisterURLWithID: (uint64_t) idNbr; +- (void) updateID: (uint64_t) idNbr + withURL: (NSString *) urlString; @end diff --git a/OpenChange/MAPIStoreMapping.m b/OpenChange/MAPIStoreMapping.m index c1a4b1f6b..8c7e29090 100644 --- a/OpenChange/MAPIStoreMapping.m +++ b/OpenChange/MAPIStoreMapping.m @@ -204,6 +204,90 @@ MAPIStoreMappingTDBTraverse (TDB_CONTEXT *ctx, TDB_DATA data1, TDB_DATA data2, return idNbr; } +- (void) _updateFolderWithURL: (NSString *) oldURL + withURL: (NSString *) urlString +{ + NSArray *allKeys; + NSUInteger count, max; + NSString *currentKey, *keyEnd, *newKey; + NSUInteger oldURLLength; + NSNumber *idKey; + TDB_DATA key, dbuf; + + oldURLLength = [oldURL length]; + + allKeys = [reverseMapping allKeys]; + max = [allKeys count]; + for (count = 0; count < max; count++) + { + currentKey = [allKeys objectAtIndex: count]; + if ([currentKey hasPrefix: oldURL]) + { + keyEnd = [currentKey substringFromIndex: oldURLLength]; + newKey = [NSString stringWithFormat: @"%@%@", urlString, keyEnd]; + + idKey = [reverseMapping objectForKey: currentKey]; + [mapping setObject: newKey forKey: idKey]; + [reverseMapping setObject: idKey forKey: newKey]; + [reverseMapping removeObjectForKey: currentKey]; + + /* update the record in the indexing database */ + key.dptr = (unsigned char *) talloc_asprintf (NULL, "0x%.16"PRIx64, + (uint64_t) [idKey unsignedLongLongValue]); + key.dsize = strlen ((const char *) key.dptr); + + dbuf.dptr = (unsigned char *) talloc_strdup (NULL, + [newKey UTF8String]); + dbuf.dsize = strlen ((const char *) dbuf.dptr); + tdb_store (indexing->tdb, key, dbuf, TDB_MODIFY); + talloc_free (key.dptr); + talloc_free (dbuf.dptr); + } + } +} + +- (void) updateID: (uint64_t) idNbr + withURL: (NSString *) urlString +{ + NSString *oldURL; + NSNumber *idKey; + TDB_DATA key, dbuf; + + idKey = [NSNumber numberWithUnsignedLongLong: idNbr]; + oldURL = [mapping objectForKey: idKey]; + if (oldURL) + { + if ([oldURL hasSuffix: @"/"]) /* is container ? */ + { + if (![urlString hasSuffix: @"/"]) + [NSException raise: NSInvalidArgumentException + format: @"a container url must have an ending '/'"]; + tdb_transaction_start (indexing->tdb); + [self _updateFolderWithURL: oldURL withURL: urlString]; + tdb_transaction_commit (indexing->tdb); + } + else + { + if ([urlString hasSuffix: @"/"]) + [NSException raise: NSInvalidArgumentException + format: @"a leaf url must not have an ending '/'"]; + [mapping setObject: urlString forKey: idKey]; + [reverseMapping setObject: idKey forKey: urlString]; + [reverseMapping removeObjectForKey: oldURL]; + + /* update the record in the indexing database */ + key.dptr = (unsigned char *) talloc_asprintf(NULL, "0x%.16"PRIx64, idNbr); + key.dsize = strlen((const char *) key.dptr); + + dbuf.dptr = (unsigned char *) talloc_strdup (NULL, [urlString UTF8String]); + dbuf.dsize = strlen((const char *) dbuf.dptr); + tdb_store (indexing->tdb, key, dbuf, TDB_MODIFY); + talloc_free (key.dptr); + talloc_free (dbuf.dptr); + } + } +} + - (BOOL) registerURL: (NSString *) urlString withID: (uint64_t) idNbr { From 9b5e7360d013c5b97baf162d83eefceda59cb4ab Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 03:56:16 +0000 Subject: [PATCH 078/127] Monotone-Parent: 047b040e318a98223980da2af8241b7eb6d75341 Monotone-Revision: 2fea5fbc833aa109f5048dda8ddd9884c91385e1 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T03:56:16 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 3 +++ OpenChange/MAPIStoreFolder.m | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index f949ad0f0..1f12a81d7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2012-08-12 Wolfgang Sourdeau + * OpenChange/MAPIStoreFolder.m (-objectId): folder keys always end + with a "/" by convention. + * OpenChange/MAPIStoreMapping.m (-updateID:withURL:): new method that perform a change of url on container and leaf entries. diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 50b635c06..d2baea090 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -1656,9 +1656,14 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (uint64_t) objectId { uint64_t objectId; + NSString *folderKey; if (container) - objectId = [super objectId]; + { + folderKey = [NSString stringWithFormat: @"%@/", + [sogoObject nameInContainer]]; + objectId = [container idForObjectWithKey: folderKey]; + } else objectId = [self idForObjectWithKey: nil]; From 9ec0b9d3d6c1c9928f2537ff47580ee9e1058753 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 03:58:14 +0000 Subject: [PATCH 079/127] Monotone-Parent: 2fea5fbc833aa109f5048dda8ddd9884c91385e1 Monotone-Revision: 3227626c75075b7ce019ef85ce3b7ddbd4c461f7 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T03:58:14 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 6 ++++++ OpenChange/MAPIStoreMailFolder.m | 15 +++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1f12a81d7..2a7273d57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2012-08-12 Wolfgang Sourdeau + * OpenChange/MAPIStoreMailFolder.m (-moveToFolder:withName:): if + the new name is not provided (unlikely), the computed new name + must not have the "folder" prefix. + We now also make use of -[MAPIStoreMapping updateID:withURL:] to + change the references in the mapping database. + * OpenChange/MAPIStoreFolder.m (-objectId): folder keys always end with a "/" by convention. diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 01907accb..a415a814e 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1009,13 +1009,16 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) enum mapistore_error rc; NSURL *folderURL, *newFolderURL; SOGoMailFolder *targetSOGoFolder; + NSString *newURL; NSException *error; + MAPIStoreMapping *mapping; if ([targetFolder isKindOfClass: MAPIStoreMailFolderK]) { folderURL = [sogoObject imap4URL]; if (!newFolderName) - newFolderName = [sogoObject nameInContainer]; + newFolderName = [[sogoObject nameInContainer] + substringFromIndex: 6]; /* length of "folder" */ targetSOGoFolder = [targetFolder sogoObject]; newFolderURL = [NSURL URLWithString: newFolderName relativeToURL: [targetSOGoFolder imap4URL]]; @@ -1025,7 +1028,15 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) if (error) rc = MAPISTORE_ERR_DENIED; else - rc = MAPISTORE_SUCCESS; + { + rc = MAPISTORE_SUCCESS; + mapping = [self mapping]; + newURL = [NSString stringWithFormat: @"%@folder%@/", + [targetFolder url], + [newFolderName stringByEscapingURL]]; + [mapping updateID: [self objectId] + withURL: newURL]; + } } else rc = MAPISTORE_ERR_DENIED; From b3c66a09963e7f0585386751c150338bf66b6ce6 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 14:08:49 +0000 Subject: [PATCH 080/127] Monotone-Parent: 3227626c75075b7ce019ef85ce3b7ddbd4c461f7 Monotone-Revision: 7bc959b7bdbff70b4793f01076b797130e83fd01 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T14:08:49 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++++ OpenChange/MAPIStoreMailFolder.m | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/ChangeLog b/ChangeLog index 2a7273d57..869bdac3d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-08-13 Wolfgang Sourdeau + + * OpenChange/MAPIStoreMailFolder.m (-supportsSubFolders): + overriden method to return YES. + 2012-08-12 Wolfgang Sourdeau * OpenChange/MAPIStoreMailFolder.m (-moveToFolder:withName:): if diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index a415a814e..ec88180e4 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -397,6 +397,11 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; return permissionEntries; } +- (BOOL) supportsSubFolders +{ + return YES; +} + /* synchronisation */ /* Tree: From a224a100db2f76f7100af0f082219b27f67f675e Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 14:35:00 +0000 Subject: [PATCH 081/127] Monotone-Parent: 7bc959b7bdbff70b4793f01076b797130e83fd01 Monotone-Revision: 56f8217cb19f50d50429b4f745548b63bd418877 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T14:35:00 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 8 ++++++++ OpenChange/GCSSpecialQueries+OpenChange.m | 5 +++++ OpenChange/SOGoMAPIDBFolder.m | 9 +++++---- OpenChange/SOGoMAPIDBObject.m | 12 ++++++++---- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 869bdac3d..a3950b176 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2012-08-13 Wolfgang Sourdeau + * OpenChange/SOGoMAPIDBFolder.m + (-childKeysOfType:includeDeleted:matchingQualifier:andSortOrderings:): + records now have a c_parent_path column in order to avoid fetch + the children of children due to the nature of our "LIKE" clause. + + * OpenChange/SOGoMAPIDBObject.m (-save): records now have a + c_parent_path. + * OpenChange/MAPIStoreMailFolder.m (-supportsSubFolders): overriden method to return YES. diff --git a/OpenChange/GCSSpecialQueries+OpenChange.m b/OpenChange/GCSSpecialQueries+OpenChange.m index aa336bf99..914fe6227 100644 --- a/OpenChange/GCSSpecialQueries+OpenChange.m +++ b/OpenChange/GCSSpecialQueries+OpenChange.m @@ -35,6 +35,8 @@ @implementation GCSSpecialQueries (OpenChangeHelpers) +/* FIXME: c_parent_path should be indexed */ + - (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName { [self subclassResponsibility: _cmd]; @@ -51,6 +53,7 @@ static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (" @" c_path VARCHAR(255) PRIMARY KEY," + @" c_parent_path VARCHAR(255)," @" c_type SMALLINT NOT NULL," @" c_creationdate INT4 NOT NULL," @" c_lastmodified INT4 NOT NULL," @@ -70,6 +73,7 @@ static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (" @" c_path VARCHAR(255) PRIMARY KEY," + @" c_parent_path VARCHAR(255)," @" c_type TINYINT NOT NULL," @" c_creationdate INT NOT NULL," @" c_lastmodified INT NOT NULL," @@ -89,6 +93,7 @@ static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (" @" c_path VARCHAR2(255) PRIMARY KEY," + @" c_parent_path VARCHAR2(255)," @" c_type SMALLINT NOT NULL," @" c_creationdate INT4 NOT NULL," @" c_lastmodified INT4 NOT NULL," diff --git a/OpenChange/SOGoMAPIDBFolder.m b/OpenChange/SOGoMAPIDBFolder.m index ddd6086a6..2607eb1aa 100644 --- a/OpenChange/SOGoMAPIDBFolder.m +++ b/OpenChange/SOGoMAPIDBFolder.m @@ -107,7 +107,7 @@ Class SOGoMAPIDBObjectK = Nil; NSMutableString *path; path = [self path]; - [path appendFormat: @"/%@", childName]; + [path appendFormat: @"/%@", childName]; return path; } @@ -153,9 +153,8 @@ Class SOGoMAPIDBObjectK = Nil; [sql appendFormat: @"SELECT * FROM %@", [self tableName]]; whereClause = [NSMutableArray arrayWithCapacity: 2]; - childPathPrefix = [NSString stringWithFormat: @"%@/", [self path]]; - [whereClause addObject: [NSString stringWithFormat: @"c_path LIKE '%@%%'", - childPathPrefix]]; + [whereClause addObject: [NSString stringWithFormat: @"c_parent_path = '%@'", + [self path]]]; [whereClause addObject: [NSString stringWithFormat: @"c_type = %d", type]]; if (!includeDeleted) [whereClause addObject: @"c_deleted = 0"]; @@ -163,6 +162,8 @@ Class SOGoMAPIDBObjectK = Nil; [sql appendFormat: @" WHERE %@", [whereClause componentsJoinedByString: @" AND "]]; + childPathPrefix = [NSString stringWithFormat: @"%@/", [self path]]; + /* results */ records = [self performSQLQuery: sql]; if (records) diff --git a/OpenChange/SOGoMAPIDBObject.m b/OpenChange/SOGoMAPIDBObject.m index f5014dd52..e085440a3 100644 --- a/OpenChange/SOGoMAPIDBObject.m +++ b/OpenChange/SOGoMAPIDBObject.m @@ -391,7 +391,7 @@ static EOAttribute *textColumn = nil; EOAdaptor *adaptor; EOAdaptorChannel *channel; NSInteger creationDateValue, lastModifiedValue, deletedValue; - NSString *tableName, *pathValue, *propsValue; + NSString *tableName, *pathValue, *parentPathValue, *propsValue; NSException *result; if (!initialized) @@ -440,14 +440,18 @@ static EOAttribute *textColumn = nil; { ASSIGN (creationDate, now); creationDateValue = (NSInteger) [creationDate timeIntervalSince1970]; + parentPathValue = [adaptor formatValue: [container path] + forAttribute: textColumn]; + if (!parentPathValue) + parentPathValue = @"NULL"; sql = [NSString stringWithFormat: (@"INSERT INTO %@" - @" (c_path, c_type, c_creationdate, c_lastmodified," + @" (c_path, c_parent_path, c_type, c_creationdate, c_lastmodified," @" c_deleted, c_version, c_content)" - @" VALUES (%@, %d, %d, %d, 0, 0, %@" + @" VALUES (%@, %@, %d, %d, %d, 0, 0, %@" @")"), tableName, - pathValue, objectType, + pathValue, parentPathValue, objectType, creationDateValue, lastModifiedValue, propsValue]; isNew = NO; From 7d7724a5f5df338e5b60773dd12184eac5ab8e0c Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 15:26:06 +0000 Subject: [PATCH 082/127] Monotone-Parent: 56f8217cb19f50d50429b4f745548b63bd418877 Monotone-Revision: 844ddef9e05b2d52503e6a44804f1d3036558771 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T15:26:06 Monotone-Branch: ca.inverse.sogo --- SoObjects/SOGo/NSString+Utilities.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/SoObjects/SOGo/NSString+Utilities.h b/SoObjects/SOGo/NSString+Utilities.h index a94e48ce6..ef836fa16 100644 --- a/SoObjects/SOGo/NSString+Utilities.h +++ b/SoObjects/SOGo/NSString+Utilities.h @@ -31,6 +31,7 @@ @interface NSString (SOGoURLExtension) +/* URL handling */ - (NSString *) composeURLWithAction: (NSString *) action parameters: (NSDictionary *) urlParameters andHash: (BOOL) useHash; @@ -40,13 +41,21 @@ - (NSString *) stringByDetectingURLs; +/* escaping */ - (NSString *) doubleQuotedString; -- (NSString *) jsonRepresentation; - +/* CSS and URL safety */ - (NSString *) asCSSIdentifier; - (NSString *) fromCSSIdentifier; +/* SQL safety */ +- (NSString *) asSafeSQLString; + +/* JSON */ +- (NSString *) jsonRepresentation; +- (BOOL) isJSONString; +- (id) objectFromJSONString; + /* bare email addresses */ - (NSString *) pureEMailAddress; @@ -54,6 +63,7 @@ - (NSRange) _rangeOfURLInRange: (NSRange) refRange; +/* LDAP */ - (BOOL) caseInsensitiveMatches: (NSString *) match; #ifndef GNUSTEP_BASE_LIBRARY @@ -62,12 +72,6 @@ - (int) timeValue; -- (BOOL) isJSONString; - -- (id) objectFromJSONString; - -- (NSString *) asSafeSQLString; - - (NSUInteger) countOccurrencesOfString: (NSString *) substring; From 99aa98fdaa49170d762c49cd072210950c52ecad Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 15:26:22 +0000 Subject: [PATCH 083/127] Monotone-Parent: 844ddef9e05b2d52503e6a44804f1d3036558771 Monotone-Revision: 61e6d0133bf0d45c09767727617ba746f65a28b9 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T15:26:22 Monotone-Branch: ca.inverse.sogo --- SoObjects/SOGo/NSString+Utilities.h | 1 + 1 file changed, 1 insertion(+) diff --git a/SoObjects/SOGo/NSString+Utilities.h b/SoObjects/SOGo/NSString+Utilities.h index ef836fa16..409c3fe86 100644 --- a/SoObjects/SOGo/NSString+Utilities.h +++ b/SoObjects/SOGo/NSString+Utilities.h @@ -72,6 +72,7 @@ - (int) timeValue; +/* substrings */ - (NSUInteger) countOccurrencesOfString: (NSString *) substring; From 5557c01b99704d1b2288fc7192465330cf660b94 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 15:29:44 +0000 Subject: [PATCH 084/127] Monotone-Parent: 61e6d0133bf0d45c09767727617ba746f65a28b9 Monotone-Revision: 54ac2dbf42dee286f64da8b9b3c4567570b00258 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T15:29:44 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 3 +++ SoObjects/SOGo/NSString+Utilities.h | 3 ++- SoObjects/SOGo/NSString+Utilities.m | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index a3950b176..36869115b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2012-08-13 Wolfgang Sourdeau + * SoObjects/SOGo/NSString+Utilities.m + (-stringByReplacingPrefix:withPrefix:): new self-explicit method. + * OpenChange/SOGoMAPIDBFolder.m (-childKeysOfType:includeDeleted:matchingQualifier:andSortOrderings:): records now have a c_parent_path column in order to avoid fetch diff --git a/SoObjects/SOGo/NSString+Utilities.h b/SoObjects/SOGo/NSString+Utilities.h index 409c3fe86..df82535e2 100644 --- a/SoObjects/SOGo/NSString+Utilities.h +++ b/SoObjects/SOGo/NSString+Utilities.h @@ -74,7 +74,8 @@ /* substrings */ - (NSUInteger) countOccurrencesOfString: (NSString *) substring; - +- (NSString *) stringByReplacingPrefix: (NSString *) oldPrefix + withPrefix: (NSString *) newPrefix; /* Those methods provide symmetric enc-/decryption via a XOR operation */ - (NSString *) encryptWithKey: (NSString *) theKey; diff --git a/SoObjects/SOGo/NSString+Utilities.m b/SoObjects/SOGo/NSString+Utilities.m index ec04b9795..da5a69993 100644 --- a/SoObjects/SOGo/NSString+Utilities.m +++ b/SoObjects/SOGo/NSString+Utilities.m @@ -560,6 +560,24 @@ static int cssEscapingCount; return count; } +- (NSString *) stringByReplacingPrefix: (NSString *) oldPrefix + withPrefix: (NSString *) newPrefix +{ + NSUInteger oldPrefixLength; + NSString *newString; + + if (![self hasPrefix: oldPrefix]) + [NSException raise: NSInvalidArgumentException + format: @"string does not have the specified prefix"]; + + oldPrefixLength = [oldPrefix length]; + newString = [NSString stringWithFormat: @"%@%@", + newPrefix, + [self substringFromIndex: oldPrefixLength]]; + + return newString; +} + - (NSString *) encryptWithKey: (NSString *) theKey { NSMutableData *encryptedPassword; From 57afca1c7474785281df80d672eb2b77b011faee Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 17:48:18 +0000 Subject: [PATCH 085/127] Monotone-Parent: 54ac2dbf42dee286f64da8b9b3c4567570b00258 Monotone-Revision: dbc58efbc938f11a813baa01021a534ed90f70b8 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T17:48:18 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++ OpenChange/SOGoMAPIDBObject.h | 4 ++- OpenChange/SOGoMAPIDBObject.m | 59 +++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 36869115b..d215a538c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2012-08-13 Wolfgang Sourdeau + * OpenChange/SOGoMAPIDBObject.m (-performBatchSQLQueries:) new + method to perform void queries under a transaction. + (-changePathTo:) new method that updates the references for the + object record in the dbfs table. + * SoObjects/SOGo/NSString+Utilities.m (-stringByReplacingPrefix:withPrefix:): new self-explicit method. diff --git a/OpenChange/SOGoMAPIDBObject.h b/OpenChange/SOGoMAPIDBObject.h index ea0a7a58a..6bf1750bb 100644 --- a/OpenChange/SOGoMAPIDBObject.h +++ b/OpenChange/SOGoMAPIDBObject.h @@ -73,10 +73,12 @@ typedef enum { /* automatically set from actions */ - (BOOL) deleted; +- (void) changePathTo: (NSString *) newPath; + /* db helpers */ - (EOAdaptor *) tableChannelAdaptor; - (NSArray *) performSQLQuery: (NSString *) sql; - +- (BOOL) performBatchSQLQueries: (NSArray *) queries; @end diff --git a/OpenChange/SOGoMAPIDBObject.m b/OpenChange/SOGoMAPIDBObject.m index e085440a3..deb760383 100644 --- a/OpenChange/SOGoMAPIDBObject.m +++ b/OpenChange/SOGoMAPIDBObject.m @@ -260,6 +260,33 @@ static EOAttribute *textColumn = nil; } /* actions */ +- (void) changePathTo: (NSString *) newPath +{ + NSMutableString *sql; + NSString *oldPath, *newParentPath; + NSRange slashRange; + + oldPath = [self path]; + + slashRange = [newPath rangeOfString: @"/" + options: NSBackwardsSearch]; + if (slashRange.location != NSNotFound) + newParentPath = [newPath substringToIndex: slashRange.location]; + else + newParentPath = NULL; + + sql = [NSMutableString stringWithFormat: @"UPDATE %@" + @" SET c_path = '%@'", + [self tableName], + newPath]; + if (newParentPath) + [sql appendFormat: @", c_parent_path = '%@'", newParentPath]; + else + [sql appendString: @", c_parent_path = NULL"]; + [sql appendFormat: @" WHERE c_path = '%@'", oldPath]; + [self performBatchSQLQueries: [NSArray arrayWithObject: sql]]; +} + - (EOAdaptor *) tableChannelAdaptor { GCSChannelManager *cm; @@ -307,6 +334,38 @@ static EOAttribute *textColumn = nil; return records; } +- (BOOL) performBatchSQLQueries: (NSArray *) queries +{ + GCSChannelManager *cm; + EOAdaptorChannel *channel; + EOAdaptorContext *dbContext; + NSException *error; + NSUInteger count, max; + NSString *sql; + + cm = [GCSChannelManager defaultChannelManager]; + channel = [cm acquireOpenChannelForURL: [self tableUrl]]; + dbContext = [channel adaptorContext]; + + [dbContext beginTransaction]; + + error = nil; + + max = [queries count]; + for (count = 0; error == nil && count < max; count++) + { + sql = [queries objectAtIndex: count]; + error = [channel evaluateExpressionX: sql]; + if (error) + [dbContext rollbackTransaction]; + } + if (!error) + [dbContext commitTransaction]; + [cm releaseChannel: channel]; + + return (error == nil); +} + - (NSDictionary *) lookupRecord: (NSString *) path newerThanVersion: (NSInteger) startVersion { From 5c1610c070b53b372c2ea05e0ab96d72599c57da Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 17:48:43 +0000 Subject: [PATCH 086/127] Monotone-Parent: dbc58efbc938f11a813baa01021a534ed90f70b8 Monotone-Revision: ded960271197442de0917fc8f66509f7377b6a75 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T17:48:43 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 3 ++ OpenChange/SOGoMAPIDBFolder.h | 2 ++ OpenChange/SOGoMAPIDBFolder.m | 53 +++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/ChangeLog b/ChangeLog index d215a538c..3a0249635 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2012-08-13 Wolfgang Sourdeau + * OpenChange/SOGoMAPIDBFolder.m (-changePathTo:): overriden method + in order to update children records too. + * OpenChange/SOGoMAPIDBObject.m (-performBatchSQLQueries:) new method to perform void queries under a transaction. (-changePathTo:) new method that updates the references for the diff --git a/OpenChange/SOGoMAPIDBFolder.h b/OpenChange/SOGoMAPIDBFolder.h index e2d29058f..d055291bc 100644 --- a/OpenChange/SOGoMAPIDBFolder.h +++ b/OpenChange/SOGoMAPIDBFolder.h @@ -52,6 +52,8 @@ matchingQualifier: (EOQualifier *) qualifier andSortOrderings: (NSArray *) sortOrderings; +- (void) changePathTo: (NSString *) newPath; + @end #endif /* SOGOMAPIDBFOLDER_H */ diff --git a/OpenChange/SOGoMAPIDBFolder.m b/OpenChange/SOGoMAPIDBFolder.m index 2607eb1aa..2e9556dcb 100644 --- a/OpenChange/SOGoMAPIDBFolder.m +++ b/OpenChange/SOGoMAPIDBFolder.m @@ -30,11 +30,13 @@ #import #import +#import #import #import // #import #import +#import #import #import #import "EOQualifier+MAPI.h" @@ -213,6 +215,57 @@ Class SOGoMAPIDBObjectK = Nil; andSortOrderings: nil]; } +- (void) changePathTo: (NSString *) newPath +{ + NSMutableString *sql// , *qualifierClause + ; + NSString *oldPath, *oldPathAsPrefix, *path, *parentPath; + NSMutableArray *queries; + NSArray *records; + NSDictionary *record; + NSUInteger count, max; + + /* change the paths in children records */ + oldPath = [self path]; + oldPathAsPrefix = [NSString stringWithFormat: @"%@/", oldPath]; + + sql = [NSMutableString stringWithFormat: + @"SELECT c_path, c_parent_path FROM %@" + @" WHERE c_path LIKE '%@%%'", + [self tableName], oldPathAsPrefix]; + records = [self performSQLQuery: sql]; + max = [records count]; + queries = [NSMutableArray arrayWithCapacity: max + 1]; + if (max > 0) + { + for (count = 0; count < max; count++) + { + record = [records objectAtIndex: count]; + path = [record objectForKey: @"c_path"]; + if ([path isEqualToString: oldPath] + || [path hasPrefix: oldPathAsPrefix]) + { + sql = [NSMutableString stringWithFormat: @"UPDATE %@" + @" SET c_path = '%@'", + [self tableName], + [path stringByReplacingPrefix: oldPath + withPrefix: newPath]]; + parentPath = [record objectForKey: @"c_parent_path"]; + if ([parentPath isNotNull]) + [sql appendFormat: @", c_parent_path = '%@'", + [parentPath stringByReplacingPrefix: oldPath + withPrefix: newPath]]; + [sql appendFormat: @" WHERE c_path = '%@'", oldPath]; + [queries addObject: sql]; + } + } + [self performBatchSQLQueries: queries]; + } + + /* change the path in this folder record */ + [super changePathTo: newPath]; +} + // - (NSArray *) toOneRelationshipKeysMatchingQualifier: (EOQualifier *) qualifier // andSortOrderings: (NSArray *) sortOrderings // { From db43dcdd0d589552fa9e02e4a19e43065e811be5 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 17:48:57 +0000 Subject: [PATCH 087/127] Monotone-Parent: ded960271197442de0917fc8f66509f7377b6a75 Monotone-Revision: 62face8d68b60cbdfeed3e1857fabd32fceffb4c Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T17:48:57 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreMapping.m | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/OpenChange/MAPIStoreMapping.m b/OpenChange/MAPIStoreMapping.m index 8c7e29090..36c4dc9a3 100644 --- a/OpenChange/MAPIStoreMapping.m +++ b/OpenChange/MAPIStoreMapping.m @@ -30,6 +30,8 @@ #import +#import + #import "MAPIStoreTypes.h" #import "MAPIStoreMapping.h" @@ -209,13 +211,10 @@ MAPIStoreMappingTDBTraverse (TDB_CONTEXT *ctx, TDB_DATA data1, TDB_DATA data2, { NSArray *allKeys; NSUInteger count, max; - NSString *currentKey, *keyEnd, *newKey; - NSUInteger oldURLLength; + NSString *currentKey, *newKey; NSNumber *idKey; TDB_DATA key, dbuf; - oldURLLength = [oldURL length]; - allKeys = [reverseMapping allKeys]; max = [allKeys count]; for (count = 0; count < max; count++) @@ -223,8 +222,8 @@ MAPIStoreMappingTDBTraverse (TDB_CONTEXT *ctx, TDB_DATA data1, TDB_DATA data2, currentKey = [allKeys objectAtIndex: count]; if ([currentKey hasPrefix: oldURL]) { - keyEnd = [currentKey substringFromIndex: oldURLLength]; - newKey = [NSString stringWithFormat: @"%@%@", urlString, keyEnd]; + newKey = [currentKey stringByReplacingPrefix: oldURL + withPrefix: urlString]; idKey = [reverseMapping objectForKey: currentKey]; [mapping setObject: newKey forKey: idKey]; From c4ad9891b3d0f0c93f9bf3ca5936bb4dfd913758 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 17:49:50 +0000 Subject: [PATCH 088/127] Monotone-Parent: 62face8d68b60cbdfeed3e1857fabd32fceffb4c Monotone-Revision: daeccf44f2750bfeb36858cb6386c86f90cc252a Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T17:49:50 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 3 +++ OpenChange/MAPIStoreMailFolder.m | 18 +++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3a0249635..0a51e0a0c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2012-08-13 Wolfgang Sourdeau + * OpenChange/MAPIStoreMailFolder.m (-moveToFolder:withNewName:): + invoke changePathTo: on the dbFolder. + * OpenChange/SOGoMAPIDBFolder.m (-changePathTo:): overriden method in order to update children records too. diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index ec88180e4..250d8d815 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -55,6 +55,7 @@ #import "NSData+MAPIStore.h" #import "NSString+MAPIStore.h" #import "SOGoMAPIDBMessage.h" +#import "SOGoMAPIDBFolder.h" #import "MAPIStoreMailVolatileMessage.h" @@ -1014,7 +1015,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) enum mapistore_error rc; NSURL *folderURL, *newFolderURL; SOGoMailFolder *targetSOGoFolder; - NSString *newURL; + NSString *newURL, *parentDBFolderPath; NSException *error; MAPIStoreMapping *mapping; @@ -1024,6 +1025,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) if (!newFolderName) newFolderName = [[sogoObject nameInContainer] substringFromIndex: 6]; /* length of "folder" */ + newFolderName = [newFolderName stringByEscapingURL]; targetSOGoFolder = [targetFolder sogoObject]; newFolderURL = [NSURL URLWithString: newFolderName relativeToURL: [targetSOGoFolder imap4URL]]; @@ -1037,10 +1039,16 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) rc = MAPISTORE_SUCCESS; mapping = [self mapping]; newURL = [NSString stringWithFormat: @"%@folder%@/", - [targetFolder url], - [newFolderName stringByEscapingURL]]; + [targetFolder url], newFolderName]; [mapping updateID: [self objectId] withURL: newURL]; + parentDBFolderPath = [[targetFolder dbFolder] path]; + if (!parentDBFolderPath) + parentDBFolderPath = @""; + [dbFolder changePathTo: [NSString stringWithFormat: + @"%@/folder%@", + parentDBFolderPath, + newFolderName]]; } } else @@ -1086,8 +1094,6 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) [roles addObject: SOGoRole_ObjectViewer]; if (rights & RightsCreateSubfolders) [roles addObject: SOGoRole_FolderCreator]; - if (rights & RightsCreateSubfolders) - [roles addObject: SOGoRole_FolderCreator]; // [self logWithFormat: @"roles for rights %.8x = (%@)", rights, roles]; @@ -1112,8 +1118,6 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) rights |= RightsReadItems; if ([roles containsObject: SOGoRole_FolderCreator]) rights |= RightsCreateSubfolders; - if ([roles containsObject: SOGoRole_FolderCreator]) - rights |= RightsCreateSubfolders; if (rights != 0) rights |= RoleNone; /* actually "folder visible" */ From 149be2b43f6043fce3a101b6d45638e07c59df1c Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 19:39:47 +0000 Subject: [PATCH 089/127] Monotone-Parent: daeccf44f2750bfeb36858cb6386c86f90cc252a Monotone-Revision: 43d241658c366d49394b3972e7951947d8271398 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T19:39:47 Monotone-Branch: ca.inverse.sogo --- OpenChange/SOGoMAPIDBFolder.m | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/OpenChange/SOGoMAPIDBFolder.m b/OpenChange/SOGoMAPIDBFolder.m index 2e9556dcb..b5cd90c3d 100644 --- a/OpenChange/SOGoMAPIDBFolder.m +++ b/OpenChange/SOGoMAPIDBFolder.m @@ -242,22 +242,18 @@ Class SOGoMAPIDBObjectK = Nil; { record = [records objectAtIndex: count]; path = [record objectForKey: @"c_path"]; - if ([path isEqualToString: oldPath] - || [path hasPrefix: oldPathAsPrefix]) - { - sql = [NSMutableString stringWithFormat: @"UPDATE %@" - @" SET c_path = '%@'", - [self tableName], - [path stringByReplacingPrefix: oldPath - withPrefix: newPath]]; - parentPath = [record objectForKey: @"c_parent_path"]; - if ([parentPath isNotNull]) - [sql appendFormat: @", c_parent_path = '%@'", - [parentPath stringByReplacingPrefix: oldPath - withPrefix: newPath]]; - [sql appendFormat: @" WHERE c_path = '%@'", oldPath]; - [queries addObject: sql]; - } + sql = [NSMutableString stringWithFormat: @"UPDATE %@" + @" SET c_path = '%@'", + [self tableName], + [path stringByReplacingPrefix: oldPath + withPrefix: newPath]]; + parentPath = [record objectForKey: @"c_parent_path"]; + if ([parentPath isNotNull]) + [sql appendFormat: @", c_parent_path = '%@'", + [parentPath stringByReplacingPrefix: oldPath + withPrefix: newPath]]; + [sql appendFormat: @" WHERE c_path = '%@'", path]; + [queries addObject: sql]; } [self performBatchSQLQueries: queries]; } From bff811b7b86beeefb685c585f19efbdd9411ea7f Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 19:40:22 +0000 Subject: [PATCH 090/127] Monotone-Parent: 43d241658c366d49394b3972e7951947d8271398 Monotone-Revision: 2042b5fba4b0e3a86f1181c84e675df4953329e4 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T19:40:22 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 3 +++ OpenChange/MAPIStoreDBFolder.m | 42 +++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 0a51e0a0c..a05380841 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2012-08-13 Wolfgang Sourdeau + * OpenChange/MAPIStoreDBFolder.m (-moveToFolder:withNewName:): + implemented method. + * OpenChange/MAPIStoreMailFolder.m (-moveToFolder:withNewName:): invoke changePathTo: on the dbFolder. diff --git a/OpenChange/MAPIStoreDBFolder.m b/OpenChange/MAPIStoreDBFolder.m index 21c542f81..3cb90b949 100644 --- a/OpenChange/MAPIStoreDBFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -25,6 +25,7 @@ #import #import #import +#import #import #import #import @@ -36,6 +37,7 @@ #import "MAPIStoreDBFolderTable.h" #import "MAPIStoreDBMessage.h" #import "MAPIStoreDBMessageTable.h" +#import "MAPIStoreMapping.h" #import "MAPIStoreTypes.h" #import "MAPIStoreUserContext.h" #import "SOGoMAPIDBFolder.h" @@ -47,7 +49,7 @@ #include #include -static Class EOKeyValueQualifierK, SOGoMAPIDBFolderK; +static Class EOKeyValueQualifierK, SOGoMAPIDBFolderK, MAPIStoreDBFolderK; static NSString *MAPIStoreRightReadItems = @"RightsReadItems"; static NSString *MAPIStoreRightCreateItems = @"RightsCreateItems"; @@ -65,6 +67,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; { EOKeyValueQualifierK = [EOKeyValueQualifier class]; SOGoMAPIDBFolderK = [SOGoMAPIDBFolder class]; + MAPIStoreDBFolderK = [MAPIStoreDBFolder class]; } - (void) setupAuxiliaryObjects @@ -123,6 +126,43 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; return rc; } +- (enum mapistore_error) moveToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName +{ + enum mapistore_error rc; + NSString *path, *pathComponent, *targetPath, *newPath; + NSString *newURL; + MAPIStoreMapping *mapping; + NSRange slashRange; + + if ([targetFolder isKindOfClass: MAPIStoreDBFolderK]) + { + path = [sogoObject path]; + slashRange = [path rangeOfString: @"/" options: NSBackwardsSearch]; + if (slashRange.location == NSNotFound) + [NSException raise: @"MAPIStoreIOException" + format: @"db folder path must start with a '/'"]; + else + pathComponent = [path substringFromIndex: slashRange.location + 1]; + targetPath = [[targetFolder sogoObject] path]; + newPath = [NSString stringWithFormat: @"%@/%@", + targetPath, pathComponent]; + [dbFolder changePathTo: newPath]; + + mapping = [self mapping]; + newURL = [NSString stringWithFormat: @"%@%@/", + [targetFolder url], pathComponent]; + [mapping updateID: [self objectId] + withURL: newURL]; + + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_DENIED; + + return rc; +} + - (MAPIStoreMessage *) createMessage { MAPIStoreMessage *newMessage; From de462516766c210de2f96b2a996426d42996f525 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 19:42:08 +0000 Subject: [PATCH 091/127] Monotone-Parent: 2042b5fba4b0e3a86f1181c84e675df4953329e4 Monotone-Revision: 3b8c41adf2fbd28bd91312ef68f3f4faa8ef381f Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T19:42:08 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/MAPIStoreFolder.m | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index a05380841..dabf1ed30 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-08-13 Wolfgang Sourdeau + * OpenChange/MAPIStoreFolder.m (-createFolder:withRow:andFID:): + append a "/" to the new folder url when registering with the + url/id mapper. + * OpenChange/MAPIStoreDBFolder.m (-moveToFolder:withNewName:): implemented method. diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index d2baea090..d39683bff 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -399,7 +399,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe baseURL = [self url]; if (![baseURL hasSuffix: @"/"]) baseURL = [NSString stringWithFormat: @"%@/", baseURL]; - childURL = [NSString stringWithFormat: @"%@%@", + childURL = [NSString stringWithFormat: @"%@%@/", baseURL, folderKey]; [mapping registerURL: childURL withID: fid]; childFolder = [self lookupFolder: folderKey]; From 07a376b461c09acd96f76c26c7ab86d71098a122 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 13 Aug 2012 19:55:50 +0000 Subject: [PATCH 092/127] Monotone-Parent: 3b8c41adf2fbd28bd91312ef68f3f4faa8ef381f Monotone-Revision: 22a3b958acddeb274e788d95f5da332880c64d78 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-13T19:55:50 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 3 +++ OpenChange/MAPIStoreObject.h | 3 --- OpenChange/MAPIStoreObject.m | 18 ------------------ OpenChange/MAPIStoreSOGo.m | 30 ------------------------------ 4 files changed, 3 insertions(+), 51 deletions(-) diff --git a/ChangeLog b/ChangeLog index dabf1ed30..f07e56ffb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2012-08-13 Wolfgang Sourdeau + * OpenChange/MAPIStoreSOGo.m (sogo_properties_get_uri): removed + useless backend method. + * OpenChange/MAPIStoreFolder.m (-createFolder:withRow:andFID:): append a "/" to the new folder url when registering with the url/id mapper. diff --git a/OpenChange/MAPIStoreObject.h b/OpenChange/MAPIStoreObject.h index 6918184a4..ddb28ada0 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -68,9 +68,6 @@ - (NSMutableDictionary *) properties; /* ops */ -- (enum mapistore_error) getURI: (char **) uriP - inMemCtx: (TALLOC_CTX *) memCtx; - - (int) getProperties: (struct mapistore_property_data *) data withTags: (enum MAPITAGS *) tags andCount: (uint16_t) columnCount diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index a751927e4..eba69c966 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -150,24 +150,6 @@ static Class NSExceptionK, MAPIStoreFolderK; return properties; } -- (enum mapistore_error) getURI: (char **) uriP - inMemCtx: (TALLOC_CTX *) memCtx -{ - enum mapistore_error rc; - NSString *url; - - url = [self url]; - if (url) - { - *uriP = [url asUnicodeInMemCtx: memCtx]; - rc = MAPISTORE_SUCCESS; - } - else - rc = MAPISTORE_ERR_NOT_FOUND; - - return rc; -} - - (int) getProperty: (void **) data withTag: (enum MAPITAGS) propTag inMemCtx: (TALLOC_CTX *) memCtx diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 8d31a11dc..276bd6268 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -1325,35 +1325,6 @@ sogo_table_handle_destructor (void *table_object, uint32_t handle_id) return rc; } -static enum mapistore_error sogo_properties_get_uri(void *object, - TALLOC_CTX *mem_ctx, - char **uriP) -{ - struct MAPIStoreTallocWrapper *wrapper; - NSAutoreleasePool *pool; - MAPIStoreObject *propObject; - int rc; - - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); - - if (object) - { - wrapper = object; - propObject = wrapper->instance; - GSRegisterCurrentThread (); - pool = [NSAutoreleasePool new]; - rc = [propObject getURI: uriP inMemCtx: mem_ctx]; - [pool release]; - GSUnregisterCurrentThread (); - } - else - { - rc = sogo_backend_unexpected_error(); - } - - return rc; -} - static enum mapistore_error sogo_properties_get_available_properties(void *object, TALLOC_CTX *mem_ctx, struct SPropTagArray **propertiesP) @@ -1546,7 +1517,6 @@ int mapistore_init_backend(void) backend.table.get_row = sogo_table_get_row; backend.table.get_row_count = sogo_table_get_row_count; backend.table.handle_destructor = sogo_table_handle_destructor; - backend.properties.get_uri = sogo_properties_get_uri; backend.properties.get_available_properties = sogo_properties_get_available_properties; backend.properties.get_properties = sogo_properties_get_properties; backend.properties.set_properties = sogo_properties_set_properties; From 9d6b1d47bbe2994b2e2b5e1d97033db0bc0619ad Mon Sep 17 00:00:00 2001 From: Jean Raby Date: Tue, 14 Aug 2012 16:32:53 +0000 Subject: [PATCH 093/127] * OpenChange/GNUmakefile: use version_info[{0,1}] instead of version_info.{major,minor} when checking for legacy version of python since these named attributes where added in python2.7 Monotone-Parent: abd34c5936406914d038a38374b7414d4b8435f2 Monotone-Revision: 800eec672662916c1befcca1d44eb844a104ca97 Monotone-Author: jraby@inverse.ca Monotone-Date: 2012-08-14T16:32:53 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 6 ++++++ OpenChange/GNUmakefile | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index f6b6412e8..d029fdfda 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-08-14 Jean Raby + + * OpenChange/GNUmakefile: use version_info[{0,1}] instead of + version_info.{major,minor} when checking for legacy version + of python since these named attributes where added in python2.7 + 2012-08-13 Wolfgang Sourdeau * OpenChange/MAPIStoreSOGo.m (sogo_properties_get_uri): removed diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 0db45e325..1174670b2 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -27,7 +27,7 @@ BUNDLE_INSTALL_DIR = $(SOGO_LIBDIR) UNRTF_DIR = unrtf-$(UNRTF_VERSION) PYTHON = /usr/bin/python -PYTHON_IS_GOOD = $(shell $(PYTHON) -c 'from sys import version_info; a=version_info; print a.major == 2 and a.minor >= 6') +PYTHON_IS_GOOD = $(shell $(PYTHON) -c 'from sys import version_info; a=version_info; print a[0] == 2 and a[1] >= 6') ifeq (${PYTHON_IS_GOOD},False) PYTHON = /usr/bin/python2.6 endif From 992c95f9a0665fd7481e01f5883d51609b55bf15 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 14 Aug 2012 20:15:15 +0000 Subject: [PATCH 094/127] Monotone-Parent: 22a3b958acddeb274e788d95f5da332880c64d78 Monotone-Revision: 1036da510d0360f1e473b578044e95ac7792871f Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-14T20:15:15 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 7 +++++++ OpenChange/MAPIStoreMailFolder.m | 17 ++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index f07e56ffb..171a82f9e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2012-08-14 Wolfgang Sourdeau + + * OpenChange/MAPIStoreMailFolder.m (- + moveCopyMessagesWithMIDs:andCount:fromFolder:withMIDs:andChangeKeys:wantCopy:): + do not attempt to access targetChangeKeys when NULL, to avoid a + SEGFAULT. + 2012-08-13 Wolfgang Sourdeau * OpenChange/MAPIStoreSOGo.m (sogo_properties_get_uri): removed diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 250d8d815..8aea7e359 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -985,14 +985,17 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) } /* Update the change keys */ - [self synchroniseCache]; - for (count = 0; count < midCount; count++) + if (targetChangeKeys) { - changeKey = [NSData dataWithBinary: targetChangeKeys[count]]; - messageKey = [NSString stringWithFormat: @"%@.eml", - [destUIDs objectAtIndex: count]]; - [self setChangeKey: changeKey - forMessageWithKey: messageKey]; + [self synchroniseCache]; + for (count = 0; count < midCount; count++) + { + changeKey = [NSData dataWithBinary: targetChangeKeys[count]]; + messageKey = [NSString stringWithFormat: @"%@.eml", + [destUIDs objectAtIndex: count]]; + [self setChangeKey: changeKey + forMessageWithKey: messageKey]; + } } [self postNotificationsForMoveCopyMessagesWithMIDs: srcMids From 5426fb4bbb1120c1e2efb222734f8d71245d3809 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 14 Aug 2012 20:16:16 +0000 Subject: [PATCH 095/127] Monotone-Parent: 1036da510d0360f1e473b578044e95ac7792871f Monotone-Revision: 0a2405280c040b602d25fea256f5093976a1aa95 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-14T20:16:16 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/MAPIStoreSOGo.m | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 171a82f9e..5169befd9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-08-14 Wolfgang Sourdeau + * OpenChange/MAPIStoreSOGo.m (sogo_folder_move_folder): if + "target_folder_object", we do not attempt to access the + corresponding instance member. + * OpenChange/MAPIStoreMailFolder.m (- moveCopyMessagesWithMIDs:andCount:fromFolder:withMIDs:andChangeKeys:wantCopy:): do not attempt to access targetChangeKeys when NULL, to avoid a diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 276bd6268..38bdd765a 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -626,7 +626,10 @@ sogo_folder_move_folder(void *folder_object, void *target_folder_object, moveFolder = wrapper->instance; wrapper = target_folder_object; - targetFolder = wrapper->instance; + if (wrapper) + targetFolder = wrapper->instance; + else + targetFolder = nil; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; From dac62b634cbdc99876e37939974965211f04dbb7 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 15 Aug 2012 00:59:55 +0000 Subject: [PATCH 096/127] Monotone-Parent: 0a2405280c040b602d25fea256f5093976a1aa95 Monotone-Revision: 5599b85afd7e2707325836a3b533b900d96b8b0c Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-15T00:59:55 Monotone-Branch: ca.inverse.sogo --- OpenChange/SOGoMAPIDBFolder.m | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/OpenChange/SOGoMAPIDBFolder.m b/OpenChange/SOGoMAPIDBFolder.m index b5cd90c3d..914cba1c1 100644 --- a/OpenChange/SOGoMAPIDBFolder.m +++ b/OpenChange/SOGoMAPIDBFolder.m @@ -357,26 +357,6 @@ Class SOGoMAPIDBObjectK = Nil; // return [self _fileAttributeForKey: NSFileModificationDate]; // } -- (NSException *) delete -{ - [self notImplemented: _cmd]; - - // NSFileManager *fm; - // NSException *error; - - // fm = [NSFileManager defaultManager]; - - // if (![fm removeFileAtPath: directory handler: NULL]) - // error = [NSException exceptionWithName: @"MAPIStoreIOException" - // reason: @"could not delete folder" - // userInfo: nil]; - // else - // error = nil; - - // return error; - return nil; -} - /* acl */ - (NSString *) defaultUserID { From 45974ec74b49d383cf5fbfa75f8d4d85c3774ac3 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 15 Aug 2012 01:02:08 +0000 Subject: [PATCH 097/127] Monotone-Parent: 5599b85afd7e2707325836a3b533b900d96b8b0c Monotone-Revision: 570b17715b63da450bef9fde6d9c95288911034f Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-15T01:02:08 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 + OpenChange/MAPIStoreAttachment.h | 3 + OpenChange/MAPIStoreAttachment.m | 24 ++++ OpenChange/MAPIStoreDBFolder.m | 12 +- OpenChange/MAPIStoreFolder.h | 6 +- OpenChange/MAPIStoreFolder.m | 183 +++++++++++++++++++++---------- OpenChange/MAPIStoreMailFolder.m | 19 ++-- OpenChange/MAPIStoreMessage.h | 3 + OpenChange/MAPIStoreMessage.m | 35 ++++++ OpenChange/MAPIStoreObject.h | 3 + OpenChange/MAPIStoreObject.m | 56 ++++++++++ OpenChange/MAPIStoreSOGo.m | 6 +- 12 files changed, 284 insertions(+), 71 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5169befd9..815c1a29e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2012-08-14 Wolfgang Sourdeau + * OpenChange/MAPIStoreFolder.m (-moveToFolder:withNewName:): + renamed to "moveCopyToFolder:withNewName:isMove:isRecursive:", + with the ability to specify whether the operation is a move or + copy operation and whether it is recursive or not (for copy). + * OpenChange/MAPIStoreSOGo.m (sogo_folder_move_folder): if "target_folder_object", we do not attempt to access the corresponding instance member. diff --git a/OpenChange/MAPIStoreAttachment.h b/OpenChange/MAPIStoreAttachment.h index 76afd8539..5ee546c0e 100644 --- a/OpenChange/MAPIStoreAttachment.h +++ b/OpenChange/MAPIStoreAttachment.h @@ -47,6 +47,9 @@ /* helpers */ - (NSData *) mimeAttachTag; +/* move & copy operations */ +- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment; + /* subclasses */ - (MAPIStoreEmbeddedMessage *) openEmbeddedMessage; - (MAPIStoreEmbeddedMessage *) createEmbeddedMessage; diff --git a/OpenChange/MAPIStoreAttachment.m b/OpenChange/MAPIStoreAttachment.m index b7a2a75d4..a3c17ec45 100644 --- a/OpenChange/MAPIStoreAttachment.m +++ b/OpenChange/MAPIStoreAttachment.m @@ -158,6 +158,30 @@ return ULLONG_MAX; } +- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment +{ + void *attachMethod; + enum mapistore_error error; + MAPIStoreEmbeddedMessage *embeddedMessage, *newEmbeddedMessage; + + [self copyPropertiesToObject: newAttachment]; + + attachMethod = NULL; + error = [self getProperty: &attachMethod + withTag: PidTagAttachMethod + inMemCtx: NULL]; + if (error == MAPISTORE_SUCCESS && attachMethod) + { + if (*(uint32_t *) attachMethod == afEmbeddedMessage) + { + embeddedMessage = [self openEmbeddedMessage]; + newEmbeddedMessage = [newAttachment createEmbeddedMessage]; + [embeddedMessage copyToMessage: newEmbeddedMessage]; + } + talloc_free (attachMethod); + } +} + /* subclasses */ - (MAPIStoreEmbeddedMessage *) openEmbeddedMessage { diff --git a/OpenChange/MAPIStoreDBFolder.m b/OpenChange/MAPIStoreDBFolder.m index 3cb90b949..8b89202f4 100644 --- a/OpenChange/MAPIStoreDBFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -126,8 +126,10 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; return rc; } -- (enum mapistore_error) moveToFolder: (MAPIStoreFolder *) targetFolder - withNewName: (NSString *) newFolderName +- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName + isMove: (BOOL) isMove + isRecursive: (BOOL) isRecursive { enum mapistore_error rc; NSString *path, *pathComponent, *targetPath, *newPath; @@ -135,7 +137,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; MAPIStoreMapping *mapping; NSRange slashRange; - if ([targetFolder isKindOfClass: MAPIStoreDBFolderK]) + if (isMove && [targetFolder isKindOfClass: MAPIStoreDBFolderK]) { path = [sogoObject path]; slashRange = [path rangeOfString: @"/" options: NSBackwardsSearch]; @@ -158,7 +160,9 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; rc = MAPISTORE_SUCCESS; } else - rc = MAPISTORE_ERR_DENIED; + rc = [super moveCopyToFolder: targetFolder withNewName: newFolderName + isMove: isMove + isRecursive: isRecursive]; return rc; } diff --git a/OpenChange/MAPIStoreFolder.h b/OpenChange/MAPIStoreFolder.h index bb2aefec1..b31f8ce49 100644 --- a/OpenChange/MAPIStoreFolder.h +++ b/OpenChange/MAPIStoreFolder.h @@ -123,8 +123,10 @@ andChangeKeys: (struct Binary_r **) targetChangeKeys wantCopy: (uint8_t) want_copy; -- (enum mapistore_error) moveToFolder: (MAPIStoreFolder *) targetFolder - withNewName: (NSString *) newFolderName; +- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName + isMove: (BOOL) isMove + isRecursive: (BOOL) isRecursive; - (enum mapistore_error) copyToFolder: (MAPIStoreFolder *) targetFolder recursive: (BOOL) resursive withNewName: (NSString *) newFolderName; diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index d39683bff..606c4a7cd 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -23,6 +23,7 @@ /* TODO: main key arrays must be initialized */ #import +#import #import #import #import @@ -653,13 +654,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe int rc; MAPIStoreMessage *sourceMsg, *destMsg; TALLOC_CTX *memCtx; - struct SPropTagArray *availableProps; - bool *exclusions; - NSUInteger count; - enum MAPITAGS propTag; - struct SRow *aRow; - int error; - void *data; + struct SRow aRow; + struct SPropValue property; memCtx = talloc_zero (NULL, TALLOC_CTX); rc = [sourceFolder openMessage: &sourceMsg @@ -669,56 +665,23 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe if (rc != MAPISTORE_SUCCESS) goto end; - rc = [sourceMsg getAvailableProperties: &availableProps - inMemCtx: memCtx]; - if (rc != MAPISTORE_SUCCESS) - goto end; - - exclusions = talloc_array(NULL, bool, 65536); - exclusions[PR_ROW_TYPE >> 16] = true; - exclusions[PR_INSTANCE_KEY >> 16] = true; - exclusions[PR_INSTANCE_NUM >> 16] = true; - exclusions[PR_INST_ID >> 16] = true; - exclusions[PR_FID >> 16] = true; - exclusions[PR_MID >> 16] = true; - exclusions[PR_SOURCE_KEY >> 16] = true; - exclusions[PR_PARENT_SOURCE_KEY >> 16] = true; - exclusions[PR_PARENT_FID >> 16] = true; - exclusions[PR_CHANGE_KEY >> 16] = true; - exclusions[PR_PREDECESSOR_CHANGE_LIST >> 16] = true; - - aRow = talloc_zero (memCtx, struct SRow); - aRow->lpProps = talloc_array (aRow, struct SPropValue, 65535); - - for (count = 0; count < availableProps->cValues; count++) - { - propTag = availableProps->aulPropTag[count]; - if (!exclusions[propTag >> 16]) - { - error = [sourceMsg getProperty: &data - withTag: propTag - inMemCtx: aRow]; - if (error == MAPISTORE_SUCCESS && data) - { - set_SPropValue_proptag(&aRow->lpProps[aRow->cValues], propTag, data); - aRow->cValues++; - } - } - } - - if (targetChangeKey) - { - set_SPropValue_proptag(&aRow->lpProps[aRow->cValues], PR_CHANGE_KEY, targetChangeKey); - aRow->cValues++; - } - rc = [self createMessage: &destMsg withMID: targetMid isAssociated: [sourceMsg isKindOfClass: MAPIStoreFAIMessageK]]; if (rc != MAPISTORE_SUCCESS) goto end; - rc = [destMsg addPropertiesFromRow: aRow]; - if (rc != MAPISTORE_SUCCESS) - goto end; + + [sourceMsg copyToMessage: destMsg]; + + if (targetChangeKey) + { + property.ulPropTag = PidTagChangeKey; + property.value.bin = *targetChangeKey; + aRow.cValues = 1; + aRow.lpProps = &property; + rc = [destMsg addPropertiesFromRow: &aRow]; + if (rc != MAPISTORE_SUCCESS) + goto end; + } [destMsg save]; if (!wantCopy) rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: 0]; @@ -795,10 +758,118 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe return rc; } -- (enum mapistore_error) moveToFolder: (MAPIStoreFolder *) targetFolder - withNewName: (NSString *) newFolderName +- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName + isMove: (BOOL) isMove + isRecursive: (BOOL) isRecursive { - return MAPISTORE_ERR_DENIED; + enum mapistore_error rc; + NSAutoreleasePool *pool; + struct SRow folderRow; + struct SPropValue nameProperty; + MAPIStoreFolder *subFolder, *newFolder; + NSArray *children; + MAPIStoreMapping *mapping; + MAPIStoreMessage *message, *targetMessage; + NSUInteger count, max; + NSString *childKey; + uint64_t fmid; + + /* TODO: one possible issue with this algorithm is that moved messages will + lack a version number and will all be assigned a new one, even though + they have not changed. This also means that they will be transferred + again to the client during a sync operation. */ + + if ([targetFolder supportsSubFolders]) + { + mapping = [self mapping]; + + if (!newFolderName) + newFolderName = [sogoObject displayName]; + nameProperty.ulPropTag = PidTagDisplayName; + nameProperty.value.lpszW = [newFolderName UTF8String]; + folderRow.lpProps = &nameProperty; + folderRow.cValues = 1; + rc = [targetFolder createFolder: &folderRow + withFID: [self objectId] + andKey: &childKey]; + if (rc == MAPISTORE_SUCCESS) + { + newFolder = [targetFolder lookupFolder: childKey]; + [self copyPropertiesToObject: newFolder]; + + pool = [NSAutoreleasePool new]; + children = [self messageKeys]; + max = [children count]; + for (count = 0; count < max; count++) + { + childKey = [children objectAtIndex: count]; + message = [self lookupMessage: childKey]; + targetMessage = [newFolder createMessage: NO]; + [message copyToMessage: targetMessage]; + if (isMove) + { + fmid = [mapping idFromURL: [message url]]; + [self deleteMessageWithMID: fmid andFlags: 0]; + [mapping registerURL: [targetMessage url] + withID: fmid]; + } + [targetMessage save]; + } + [pool release]; + + pool = [NSAutoreleasePool new]; + children = [self faiMessageKeys]; + max = [children count]; + for (count = 0; count < max; count++) + { + childKey = [children objectAtIndex: count]; + message = [self lookupFAIMessage: childKey]; + targetMessage = [newFolder createMessage: YES]; + [message copyToMessage: targetMessage]; + if (isMove) + { + fmid = [mapping idFromURL: [message url]]; + [self deleteMessageWithMID: fmid andFlags: 0]; + [mapping registerURL: [targetMessage url] + withID: fmid]; + } + [targetMessage save]; + } + [pool release]; + + if (isRecursive) + { + pool = [NSAutoreleasePool new]; + children = [self folderKeys]; + max = [children count]; + for (count = 0; count < max; count++) + { + childKey = [children objectAtIndex: count]; + subFolder = [self lookupFolder: childKey]; + [subFolder moveCopyToFolder: newFolder withNewName: nil + isMove: isMove + isRecursive: isRecursive]; + } + [pool release]; + } + + if (isMove) + { + fmid = [mapping idFromURL: [self url]]; + [mapping unregisterURLWithID: fmid]; + [self deleteFolder]; + [mapping registerURL: [newFolder url] + withID: fmid]; + } + [targetFolder cleanupCaches]; + } + [self cleanupCaches]; + } + else + rc = MAPISTORE_ERR_DENIED; + + return rc; } - (enum mapistore_error) copyToFolder: (MAPIStoreFolder *) targetFolder diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 8aea7e359..787d1db45 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -207,7 +207,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; } - (int) getPidTagContentUnreadCount: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { EOQualifier *searchQualifier; uint32_t longValue; @@ -1012,8 +1012,10 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) return MAPISTORE_SUCCESS; } -- (enum mapistore_error) moveToFolder: (MAPIStoreFolder *) targetFolder - withNewName: (NSString *) newFolderName +- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName + isMove: (BOOL) isMove + isRecursive: (BOOL) isRecursive { enum mapistore_error rc; NSURL *folderURL, *newFolderURL; @@ -1022,12 +1024,11 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) NSException *error; MAPIStoreMapping *mapping; - if ([targetFolder isKindOfClass: MAPIStoreMailFolderK]) + if (isMove && [targetFolder isKindOfClass: MAPIStoreMailFolderK]) { folderURL = [sogoObject imap4URL]; if (!newFolderName) - newFolderName = [[sogoObject nameInContainer] - substringFromIndex: 6]; /* length of "folder" */ + newFolderName = [sogoObject displayName]; newFolderName = [newFolderName stringByEscapingURL]; targetSOGoFolder = [targetFolder sogoObject]; newFolderURL = [NSURL URLWithString: newFolderName @@ -1053,9 +1054,13 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) parentDBFolderPath, newFolderName]]; } + [targetFolder cleanupCaches]; + [self cleanupCaches]; } else - rc = MAPISTORE_ERR_DENIED; + rc = [super moveCopyToFolder: targetFolder withNewName: newFolderName + isMove: isMove + isRecursive: isRecursive]; return rc; } diff --git a/OpenChange/MAPIStoreMessage.h b/OpenChange/MAPIStoreMessage.h index 51fa56ec3..28230622e 100644 --- a/OpenChange/MAPIStoreMessage.h +++ b/OpenChange/MAPIStoreMessage.h @@ -70,6 +70,9 @@ - (NSArray *) activeUserRoles; +/* move & copy internal ops */ +- (void) copyToMessage: (MAPIStoreMessage *) newMessage; + /* subclasses */ - (void) save; diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index febdb629c..20c518baa 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -425,6 +425,41 @@ rtf2html (NSData *compressedRTF) andType: MAPISTORE_MESSAGE_TABLE]; } +- (void) copyToMessage: (MAPIStoreMessage *) newMessage + +{ + TALLOC_CTX *memCtx; + struct mapistore_message *messageData; + NSArray *keys; + NSUInteger count, max; + NSString *key; + MAPIStoreAttachment *attachment, *newAttachment; + + memCtx = talloc_zero (NULL, TALLOC_CTX); + + /* message headers and recipients */ + [self getMessageData: &messageData inMemCtx: memCtx]; + [newMessage modifyRecipientsWithRecipients: messageData->recipients + andCount: messageData->recipients_count + andColumns: messageData->columns]; + + /* properties */ + [self copyPropertiesToObject: newMessage]; + + /* attachments */ + keys = [self attachmentKeys]; + max = [keys count]; + for (count = 0; count < max; count++) + { + key = [keys objectAtIndex: count]; + attachment = [self lookupAttachment: key]; + newAttachment = [newMessage createAttachment]; + [attachment copyToAttachment: newAttachment]; + } + + talloc_free (memCtx); +} + - (enum mapistore_error) saveMessage { enum mapistore_error rc; diff --git a/OpenChange/MAPIStoreObject.h b/OpenChange/MAPIStoreObject.h index ddb28ada0..ccbc5a157 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -90,6 +90,9 @@ - (int) getPidTagLastModificationTime: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; +/* move and copy operations */ +- (void) copyPropertiesToObject: (MAPIStoreObject *) newObject; + /* subclasses */ - (NSString *) nameInContainer; - (NSDate *) creationTime; diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index eba69c966..9f1b04969 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -315,6 +315,62 @@ static Class NSExceptionK, MAPIStoreFolderK; return MAPISTORE_SUCCESS; } +/* move and copy operations */ +- (void) copyPropertiesToObject: (MAPIStoreObject *) newObject +{ + TALLOC_CTX *memCtx; + struct SPropTagArray *availableProps; + struct SRow row; + enum MAPITAGS propTag; + bool *exclusions; + NSUInteger count; + enum mapistore_error error; + void *data; + + memCtx = talloc_zero (NULL, TALLOC_CTX); + + [self getAvailableProperties: &availableProps inMemCtx: memCtx]; + + /* We exclude identity and versioning properties to facilitate copy + operations. If they need to be set (move operations), the caller will need + to take care of them. */ + exclusions = talloc_array (memCtx, bool, 65536); + exclusions[PidTagRowType >> 16] = true; + exclusions[PidTagInstanceKey >> 16] = true; + exclusions[PidTagInstanceNum >> 16] = true; + exclusions[PidTagInstID >> 16] = true; + exclusions[PidTagAttachNumber >> 16] = true; + exclusions[PidTagFolderId >> 16] = true; + exclusions[PidTagMid >> 16] = true; + exclusions[PidTagSourceKey >> 16] = true; + exclusions[PidTagParentSourceKey >> 16] = true; + exclusions[PidTagParentFolderId >> 16] = true; + exclusions[PidTagChangeKey >> 16] = true; + exclusions[PidTagChangeNumber >> 16] = true; + exclusions[PidTagPredecessorChangeList >> 16] = true; + + row.cValues = 0; + row.lpProps = talloc_array (memCtx, struct SPropValue, 65535); + + for (count = 0; count < availableProps->cValues; count++) + { + propTag = availableProps->aulPropTag[count]; + if (!exclusions[propTag >> 16]) + { + error = [self getProperty: &data withTag: propTag inMemCtx: memCtx]; + if (error == MAPISTORE_SUCCESS && data) + { + set_SPropValue_proptag (row.lpProps + row.cValues, propTag, data); + row.cValues++; + } + } + } + [newObject addPropertiesFromRow: &row]; + + talloc_free (memCtx); + +} + /* subclasses */ - (NSString *) nameInContainer { diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 38bdd765a..2d4e11dec 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -639,8 +639,10 @@ sogo_folder_move_folder(void *folder_object, void *target_folder_object, else newFolderName = nil; - rc = [moveFolder moveToFolder: targetFolder - withNewName: newFolderName]; + rc = [moveFolder moveCopyToFolder: targetFolder + withNewName: newFolderName + isMove: YES + isRecursive: YES]; [pool release]; GSUnregisterCurrentThread (); } From 47afdfcd40899a7203df7ccc1d1a2d4c9b4e27bf Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 15 Aug 2012 13:13:15 +0000 Subject: [PATCH 098/127] Monotone-Parent: de4fcfa81509a5dd3cc5acd2a1c6ba7c97653649 Monotone-Revision: 85e37dbc7e87a173193494e6234f460788904318 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-15T13:13:15 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 6 ++ OpenChange/MAPIStoreDBFolder.m | 2 + OpenChange/MAPIStoreFolder.h | 3 - OpenChange/MAPIStoreFolder.m | 9 +-- OpenChange/MAPIStoreMailFolder.m | 106 +++++++++++++++++++++++++------ OpenChange/MAPIStoreSOGo.m | 7 +- 6 files changed, 99 insertions(+), 34 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6e5b86f9e..bfa5a5120 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-08-15 Wolfgang Sourdeau + + * OpenChange/MAPIStoreMailFolder.m + (-moveCopyToFolder:withNewName:isMove:isRecursive:): implemented + IMAP-based copy operation, for speed. + 2012-08-14 Wolfgang Sourdeau * OpenChange/MAPIStoreFolder.m (-moveToFolder:withNewName:): diff --git a/OpenChange/MAPIStoreDBFolder.m b/OpenChange/MAPIStoreDBFolder.m index 8b89202f4..0306c2012 100644 --- a/OpenChange/MAPIStoreDBFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -157,6 +157,8 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; [mapping updateID: [self objectId] withURL: newURL]; + [targetFolder cleanupCaches]; + rc = MAPISTORE_SUCCESS; } else diff --git a/OpenChange/MAPIStoreFolder.h b/OpenChange/MAPIStoreFolder.h index b31f8ce49..ccf3c800c 100644 --- a/OpenChange/MAPIStoreFolder.h +++ b/OpenChange/MAPIStoreFolder.h @@ -127,9 +127,6 @@ withNewName: (NSString *) newFolderName isMove: (BOOL) isMove isRecursive: (BOOL) isRecursive; -- (enum mapistore_error) copyToFolder: (MAPIStoreFolder *) targetFolder - recursive: (BOOL) resursive - withNewName: (NSString *) newFolderName; - (int) getDeletedFMIDs: (struct I8Array_r **) fmidsPtr andCN: (uint64_t *) cnPtr diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 606c4a7cd..5d5da9a07 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -806,6 +806,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe childKey = [children objectAtIndex: count]; message = [self lookupMessage: childKey]; targetMessage = [newFolder createMessage: NO]; + [targetMessage setIsNew: YES]; [message copyToMessage: targetMessage]; if (isMove) { @@ -826,6 +827,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe childKey = [children objectAtIndex: count]; message = [self lookupFAIMessage: childKey]; targetMessage = [newFolder createMessage: YES]; + [targetMessage setIsNew: YES]; [message copyToMessage: targetMessage]; if (isMove) { @@ -872,13 +874,6 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe return rc; } -- (enum mapistore_error) copyToFolder: (MAPIStoreFolder *) targetFolder - recursive: (BOOL) resursive - withNewName: (NSString *) newFolderName -{ - return MAPISTORE_ERR_DENIED; -} - - (SOGoFolder *) aclFolder { [self subclassResponsibility: _cmd]; diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 787d1db45..deaef0c15 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1019,12 +1019,21 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) { enum mapistore_error rc; NSURL *folderURL, *newFolderURL; + struct SRow folderRow; + struct SPropValue nameProperty; + MAPIStoreMailFolder *newFolder; SOGoMailFolder *targetSOGoFolder; - NSString *newURL, *parentDBFolderPath; + NSMutableArray *uids; + NSArray *childKeys; + NSUInteger count, max; + NGImap4Connection *connection; + NGImap4Client *client; + NSString *newURL, *parentDBFolderPath, *childKey, *folderIMAPName, *newFolderIMAPName; NSException *error; MAPIStoreMapping *mapping; + NSDictionary *result; - if (isMove && [targetFolder isKindOfClass: MAPIStoreMailFolderK]) + if ([targetFolder isKindOfClass: MAPIStoreMailFolderK]) { folderURL = [sogoObject imap4URL]; if (!newFolderName) @@ -1033,29 +1042,84 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) targetSOGoFolder = [targetFolder sogoObject]; newFolderURL = [NSURL URLWithString: newFolderName relativeToURL: [targetSOGoFolder imap4URL]]; - error = [[sogoObject imap4Connection] - moveMailboxAtURL: folderURL - toURL: newFolderURL]; - if (error) - rc = MAPISTORE_ERR_DENIED; + if (isMove) + { + error = [[sogoObject imap4Connection] + moveMailboxAtURL: folderURL + toURL: newFolderURL]; + if (error) + rc = MAPISTORE_ERR_DENIED; + else + { + rc = MAPISTORE_SUCCESS; + mapping = [self mapping]; + newURL = [NSString stringWithFormat: @"%@folder%@/", + [targetFolder url], newFolderName]; + [mapping updateID: [self objectId] + withURL: newURL]; + parentDBFolderPath = [[targetFolder dbFolder] path]; + if (!parentDBFolderPath) + parentDBFolderPath = @""; + [dbFolder changePathTo: [NSString stringWithFormat: + @"%@/folder%@", + parentDBFolderPath, + newFolderName]]; + } + } else { - rc = MAPISTORE_SUCCESS; - mapping = [self mapping]; - newURL = [NSString stringWithFormat: @"%@folder%@/", - [targetFolder url], newFolderName]; - [mapping updateID: [self objectId] - withURL: newURL]; - parentDBFolderPath = [[targetFolder dbFolder] path]; - if (!parentDBFolderPath) - parentDBFolderPath = @""; - [dbFolder changePathTo: [NSString stringWithFormat: - @"%@/folder%@", - parentDBFolderPath, - newFolderName]]; + nameProperty.ulPropTag = PidTagDisplayName; + nameProperty.value.lpszW = [newFolderName UTF8String]; + folderRow.lpProps = &nameProperty; + folderRow.cValues = 1; + rc = [targetFolder createFolder: &folderRow + withFID: -1 + andKey: &childKey]; + if (rc == MAPISTORE_SUCCESS) + { + newFolder = [targetFolder lookupFolder: childKey]; + + connection = [sogoObject imap4Connection]; + folderIMAPName = [connection + imap4FolderNameForURL: [sogoObject imap4URL]]; + newFolderIMAPName = [connection + imap4FolderNameForURL: [[newFolder sogoObject] imap4URL]]; + client = [connection client]; + [client select: folderIMAPName]; + + childKeys = [self messageKeys]; + max = [childKeys count]; + uids = [NSMutableArray arrayWithCapacity: max]; + for (count = 0; count < max; count++) + { + childKey = [childKeys objectAtIndex: count]; + [uids addObject: [self messageUIDFromMessageKey: childKey]]; + } + + result = [client copyUids: uids + toFolder: newFolderIMAPName]; + if ([[result objectForKey: @"result"] boolValue]) + { + if (isRecursive) + { + childKeys = [self folderKeys]; + max = [childKeys count]; + for (count = 0; count < max; count++) + { + childKey = [childKeys objectAtIndex: count]; + [[self lookupFolder: childKey] + moveCopyToFolder: newFolder + withNewName: nil + isMove: NO + isRecursive: YES]; + } + } + } + else + rc = MAPISTORE_ERROR; + } } [targetFolder cleanupCaches]; - [self cleanupCaches]; } else rc = [super moveCopyToFolder: targetFolder withNewName: newFolderName diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 2d4e11dec..22abf4e68 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -679,9 +679,10 @@ sogo_folder_copy_folder(void *folder_object, void *target_folder_object, newFolderName = [NSString stringWithUTF8String: new_folder_name]; - rc = [copyFolder copyToFolder: targetFolder - recursive: recursive - withNewName: newFolderName]; + rc = [copyFolder moveCopyToFolder: targetFolder + withNewName: newFolderName + isMove: NO + isRecursive: recursive]; [pool release]; GSUnregisterCurrentThread (); } From ab001192d668f77b9878900eaf781faebfa85241 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 15 Aug 2012 15:24:42 +0000 Subject: [PATCH 099/127] Monotone-Parent: 85e37dbc7e87a173193494e6234f460788904318 Monotone-Revision: 107e4e5ebd41e916769f1be7ce070d725d255f0d Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-15T15:24:42 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 2 ++ OpenChange/MAPIStoreMailFolder.m | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index bfa5a5120..f8496b16d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,8 @@ * OpenChange/MAPIStoreMailFolder.m (-moveCopyToFolder:withNewName:isMove:isRecursive:): implemented IMAP-based copy operation, for speed. + (-addProperties): restored the ability to rename IMAP folders by + properly updating the fid/url mapping with our new methods. 2012-08-14 Wolfgang Sourdeau diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index deaef0c15..c4c85c8ad 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -113,6 +113,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; NSString *newDisplayName; NSMutableDictionary *propsCopy; NSNumber *key; + uint64_t fid; key = MAPIPropertyKey (PR_DISPLAY_NAME_UNICODE); newDisplayName = [newProperties objectForKey: key]; @@ -121,10 +122,11 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; && ![[(SOGoMailFolder *) sogoObject displayName] isEqualToString: newDisplayName]) { - [NSException raise: @"MAPIStoreIOException" - format: @"renaming a mail folder via OpenChange is" - @" currently a bad idea"]; + fid = [self objectId]; [(SOGoMailFolder *) sogoObject renameTo: newDisplayName]; + [[self mapping] updateID: fid withURL: [self url]]; + [self cleanupCaches]; + propsCopy = [newProperties mutableCopy]; [propsCopy removeObjectForKey: key]; [propsCopy autorelease]; From 3f2cfd97e4fda9ee70623f90f89049f0f1150107 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 15 Aug 2012 18:59:42 +0000 Subject: [PATCH 100/127] Monotone-Parent: 107e4e5ebd41e916769f1be7ce070d725d255f0d Monotone-Revision: 2180e9f83acd350f77772f161695cca6bff102ec Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-15T18:59:42 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++++ OpenChange/MAPIStoreMailContext.h | 3 +++ OpenChange/MAPIStoreMailContext.m | 28 +++++++++++++++++++++++++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index f8496b16d..ab99c99d9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2012-08-15 Wolfgang Sourdeau + * OpenChange/MAPIStoreMailContext.m (-updateURLWithFolderName): + change the folder name used in the context url to use the new + folder name after a rename operation, so that further invocations + of -url will return the right url. + * OpenChange/MAPIStoreMailFolder.m (-moveCopyToFolder:withNewName:isMove:isRecursive:): implemented IMAP-based copy operation, for speed. diff --git a/OpenChange/MAPIStoreMailContext.h b/OpenChange/MAPIStoreMailContext.h index ab176cd1a..5c23fc98a 100644 --- a/OpenChange/MAPIStoreMailContext.h +++ b/OpenChange/MAPIStoreMailContext.h @@ -26,6 +26,9 @@ #import "MAPIStoreContext.h" @interface MAPIStoreMailContext : MAPIStoreContext + +- (void) updateURLWithFolderName: (NSString *) newFolderName; + @end @interface MAPIStoreOutboxContext : MAPIStoreMailContext diff --git a/OpenChange/MAPIStoreMailContext.m b/OpenChange/MAPIStoreMailContext.m index d91d76514..8046c994c 100644 --- a/OpenChange/MAPIStoreMailContext.m +++ b/OpenChange/MAPIStoreMailContext.m @@ -23,7 +23,8 @@ #import #import #import - +#import +#import #import #import @@ -203,6 +204,31 @@ MakeDisplayFolderName (NSString *folderName) return [[userContext rootFolders] objectForKey: @"mail"]; } +- (void) updateURLWithFolderName: (NSString *) newFolderName +{ + NSString *urlString; + NSMutableArray *pathComponents; + BOOL hasSlash; + NSUInteger max, folderNameIdx; + NSURL *newURL; + + urlString = [contextUrl absoluteString]; + hasSlash = [urlString hasSuffix: @"/"]; + pathComponents = [[urlString componentsSeparatedByString: @"/"] + mutableCopy]; + [pathComponents autorelease]; + max = [pathComponents count]; + if (hasSlash) + folderNameIdx = max - 2; + else + folderNameIdx = max - 1; + [pathComponents replaceObjectAtIndex: folderNameIdx + withObject: [newFolderName stringByEscapingURL]]; + urlString = [pathComponents componentsJoinedByString: @"/"]; + newURL = [NSURL URLWithString: urlString]; + ASSIGN (contextUrl, newURL); +} + @end @implementation MAPIStoreOutboxContext From abe8de11aa4eba66f526613201544e93abafa8ff Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 15 Aug 2012 19:00:38 +0000 Subject: [PATCH 101/127] Monotone-Parent: 2180e9f83acd350f77772f161695cca6bff102ec Monotone-Revision: c24e0fd5407c5155f41caca1fbb44c9686e3bc0f Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-15T19:00:38 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 +++ OpenChange/SOGoMAPIDBFolder.m | 50 +++++++++++++++++++++++++++++++++++ OpenChange/SOGoMAPIDBObject.m | 23 ++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/ChangeLog b/ChangeLog index ab99c99d9..08939ad65 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-08-15 Wolfgang Sourdeau + * OpenChange/SOGoMAPIDBObject.m (-setNameInContainer): update the + object record in the database to reflect the change of folder + name. + * OpenChange/MAPIStoreMailContext.m (-updateURLWithFolderName): change the folder name used in the context url to use the new folder name after a rename operation, so that further invocations diff --git a/OpenChange/SOGoMAPIDBFolder.m b/OpenChange/SOGoMAPIDBFolder.m index 914cba1c1..1ed8d23ff 100644 --- a/OpenChange/SOGoMAPIDBFolder.m +++ b/OpenChange/SOGoMAPIDBFolder.m @@ -215,6 +215,56 @@ Class SOGoMAPIDBObjectK = Nil; andSortOrderings: nil]; } +- (void) setNameInContainer: (NSString *) newName +{ + NSMutableString *sql; + NSString *oldPath, *newPath, *path, *parentPath; + NSMutableArray *queries; + NSArray *records; + NSDictionary *record; + NSUInteger count, max; + + /* change the paths in children records */ + if (nameInContainer) + oldPath = [self path]; + + [super setNameInContainer: newName]; + + if (nameInContainer) + { + newPath = [self path]; + + sql = [NSMutableString stringWithFormat: + @"SELECT c_path, c_parent_path FROM %@" + @" WHERE c_path LIKE '%@/%%'", + [self tableName], oldPath]; + records = [self performSQLQuery: sql]; + max = [records count]; + queries = [NSMutableArray arrayWithCapacity: max + 1]; + if (max > 0) + { + for (count = 0; count < max; count++) + { + record = [records objectAtIndex: count]; + path = [record objectForKey: @"c_path"]; + sql = [NSMutableString stringWithFormat: @"UPDATE %@" + @" SET c_path = '%@'", + [self tableName], + [path stringByReplacingPrefix: oldPath + withPrefix: newPath]]; + parentPath = [record objectForKey: @"c_parent_path"]; + if ([parentPath isNotNull]) + [sql appendFormat: @", c_parent_path = '%@'", + [parentPath stringByReplacingPrefix: oldPath + withPrefix: newPath]]; + [sql appendFormat: @" WHERE c_path = '%@'", path]; + [queries addObject: sql]; + } + [self performBatchSQLQueries: queries]; + } + } +} + - (void) changePathTo: (NSString *) newPath { NSMutableString *sql// , *qualifierClause diff --git a/OpenChange/SOGoMAPIDBObject.m b/OpenChange/SOGoMAPIDBObject.m index deb760383..0b75270af 100644 --- a/OpenChange/SOGoMAPIDBObject.m +++ b/OpenChange/SOGoMAPIDBObject.m @@ -260,6 +260,29 @@ static EOAttribute *textColumn = nil; } /* actions */ +- (void) setNameInContainer: (NSString *) newNameInContainer +{ + NSMutableString *sql; + NSString *oldPath, *newPath; + + if (nameInContainer) + oldPath = [self path]; + + [super setNameInContainer: newNameInContainer]; + + if (nameInContainer) + { + newPath = [self path]; + + sql = [NSMutableString stringWithFormat: @"UPDATE %@" + @" SET c_path = '%@'", + [self tableName], + newPath]; + [sql appendFormat: @" WHERE c_path = '%@'", oldPath]; + [self performBatchSQLQueries: [NSArray arrayWithObject: sql]]; + } +} + - (void) changePathTo: (NSString *) newPath { NSMutableString *sql; From e09972700bcba858ad8f67a21709fbffa492061c Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 15 Aug 2012 19:01:24 +0000 Subject: [PATCH 102/127] Monotone-Parent: c24e0fd5407c5155f41caca1fbb44c9686e3bc0f Monotone-Revision: d9117c53c33a58d47b6b3993f78e09e431f47f96 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-15T19:01:24 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/MAPIStoreMailFolder.m | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 08939ad65..ba30b668a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-08-15 Wolfgang Sourdeau + * OpenChange/MAPIStoreMailFolder.m (-addProperties:): make use of + the new methods below when a mail folder has been renamed, as this + operation affects the url of mail objects. + * OpenChange/SOGoMAPIDBObject.m (-setNameInContainer): update the object record in the database to reflect the change of folder name. diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index c4c85c8ad..45e3c7c91 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -49,6 +49,7 @@ #import "MAPIStoreAppointmentWrapper.h" #import "MAPIStoreContext.h" #import "MAPIStoreFAIMessage.h" +#import "MAPIStoreMailContext.h" #import "MAPIStoreMailMessageTable.h" #import "MAPIStoreMapping.h" #import "MAPIStoreTypes.h" @@ -110,7 +111,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; - (void) addProperties: (NSDictionary *) newProperties { - NSString *newDisplayName; + NSString *newDisplayName, *newNameInContainer; NSMutableDictionary *propsCopy; NSNumber *key; uint64_t fid; @@ -124,7 +125,12 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; { fid = [self objectId]; [(SOGoMailFolder *) sogoObject renameTo: newDisplayName]; + newNameInContainer = [sogoObject nameInContainer]; + if (!container) + [(MAPIStoreMailContext *) context + updateURLWithFolderName: newNameInContainer]; [[self mapping] updateID: fid withURL: [self url]]; + [dbFolder setNameInContainer: newNameInContainer]; [self cleanupCaches]; propsCopy = [newProperties mutableCopy]; From 9f0312db41c820555c6c487a8bb2e4589c61ad22 Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Thu, 16 Aug 2012 15:46:05 +0000 Subject: [PATCH 103/127] Major update to the documentation Monotone-Parent: d50a947c2bfbadd4649b083ee3432fbdd28180c2 Monotone-Revision: 3b05428c1c26f8039e60ec4b3d67714b8d3c2f95 Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2012-08-16T15:46:05 Monotone-Branch: ca.inverse.sogo --- ...Native Microsoft Outlook Configuration.odt | Bin 27917 -> 24189 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Documentation/SOGo Native Microsoft Outlook Configuration.odt b/Documentation/SOGo Native Microsoft Outlook Configuration.odt index 3761cc8329c4bc0bb68370d8af7f6d7cb5d83a0a..6f21afc607a3a348c1a038a44ff285518773da44 100644 GIT binary patch literal 24189 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 F{V(1JF%tj) From 0d12810e14c161611f8e31c7ef081e1abc48acb5 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 16 Aug 2012 16:29:47 +0000 Subject: [PATCH 104/127] Monotone-Parent: d9117c53c33a58d47b6b3993f78e09e431f47f96 Monotone-Revision: 586a2e5adebfaf2123f3514dffa057f7f0f0574e Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-16T16:29:47 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 8 ++++++++ OpenChange/MAPIStoreAppointmentWrapper.m | 18 +++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ba30b668a..927be6402 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2012-08-16 Wolfgang Sourdeau + + * OpenChange/MAPIStoreAppointmentWrapper.m + (-getPidTagInternetCodepage:inMemCtx:): new getter for a property + that is sometimes requested. + (-getPidTagBody:inMemCtx:): we return an empty string when no + "description"/"comment" is actually present. + 2012-08-15 Wolfgang Sourdeau * OpenChange/MAPIStoreMailFolder.m (-addProperties:): make use of diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index ac7cb057b..86437006a 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -1269,11 +1269,27 @@ static NSCharacterSet *hexCharacterSet = nil; if ([stringValue length] > 0) *data = [stringValue asUnicodeInMemCtx: memCtx]; else - rc = MAPISTORE_ERR_NOT_FOUND; + *data = [@"" asUnicodeInMemCtx: memCtx]; return rc; } +- (int) getPidTagInternetCodepage: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + /* ref: + http://msdn.microsoft.com/en-us/library/dd317756%28v=vs.85%29.aspx + + minimal list that should be handled: + us-ascii: 20127 + iso-8859-1: 28591 + iso-8859-15: 28605 + utf-8: 65001 */ + *data = MAPILongValue(memCtx, 65001); + + return MAPISTORE_SUCCESS; +} + - (int) getPidLidRecurring: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { From e5a39484683d0d6c2196e276b53fbd439e8ec237 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 16 Aug 2012 16:30:58 +0000 Subject: [PATCH 105/127] Monotone-Parent: 586a2e5adebfaf2123f3514dffa057f7f0f0574e Monotone-Revision: 8dee72c8fdafae92791aa552c3705e9c68f5c59e Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-16T16:30:58 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/MAPIStoreMapping.m | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index 927be6402..f030d098f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-08-16 Wolfgang Sourdeau + * OpenChange/MAPIStoreMapping.m (_updateFolderWithURL:withURL:): + we retain and release "oldURL" to avoid releasing it when it + is replaced in the list of urls to modify. + * OpenChange/MAPIStoreAppointmentWrapper.m (-getPidTagInternetCodepage:inMemCtx:): new getter for a property that is sometimes requested. diff --git a/OpenChange/MAPIStoreMapping.m b/OpenChange/MAPIStoreMapping.m index 36c4dc9a3..448ef1d1b 100644 --- a/OpenChange/MAPIStoreMapping.m +++ b/OpenChange/MAPIStoreMapping.m @@ -215,6 +215,8 @@ MAPIStoreMappingTDBTraverse (TDB_CONTEXT *ctx, TDB_DATA data1, TDB_DATA data2, NSNumber *idKey; TDB_DATA key, dbuf; + [oldURL retain]; + allKeys = [reverseMapping allKeys]; max = [allKeys count]; for (count = 0; count < max; count++) @@ -243,6 +245,8 @@ MAPIStoreMappingTDBTraverse (TDB_CONTEXT *ctx, TDB_DATA data1, TDB_DATA data2, talloc_free (dbuf.dptr); } } + + [oldURL release]; } - (void) updateID: (uint64_t) idNbr From d2321642bf30c5d87bf95422de07104986d9c591 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 16 Aug 2012 16:32:52 +0000 Subject: [PATCH 106/127] Monotone-Parent: 8dee72c8fdafae92791aa552c3705e9c68f5c59e Monotone-Revision: d50a947c2bfbadd4649b083ee3432fbdd28180c2 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-16T16:32:52 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 ++ OpenChange/MAPIStoreCalendarMessage.m | 94 +++++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index f030d098f..3fd14b8b4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2012-08-16 Wolfgang Sourdeau + * OpenChange/MAPIStoreCalendarMessage.m + (-getMessageData:inMemCtx:): when a "recipients" records is + available in the properties, we must return that list instead of + the list of attendees since it will be the most recent one. + * OpenChange/MAPIStoreMapping.m (_updateFolderWithURL:withURL:): we retain and release "oldURL" to avoid releasing it when it is replaced in the list of urls to modify. diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index 7900135f1..3cc5af4f9 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -44,6 +44,7 @@ #import #import #import +#import #import #import #import @@ -222,13 +223,91 @@ - (void) getMessageData: (struct mapistore_message **) dataPtr inMemCtx: (TALLOC_CTX *) memCtx { + static NSString *recTypes[] = {@"orig", @"to", @"cc", @"bcc"}; + static NSInteger recTypesValue[] = {MAPI_ORIG, MAPI_TO, MAPI_CC, MAPI_BCC}; struct mapistore_message *msgData; + NSDictionary *recipients, *contactInfos; + NSString *email; + NSArray *attendees; + NSDictionary *attendee; + SOGoUserManager *mgr; + struct mapistore_message_recipient *recipient; + NSUInteger nRecType, maxRecTypes, count, max, propCount; + NSObject *currentValue; [super getMessageData: &msgData inMemCtx: memCtx]; - /* HACK: we know the first (and only) proxy is our appointment wrapper - instance, but this might not always be true */ - [[proxies objectAtIndex: 0] fillMessageData: msgData - inMemCtx: memCtx]; + + /* The presence of the "recipients" meta-property means that our most recent + list of recipients has not been saved yet and that we must return that + one instead of the one stored in the event. */ + recipients = [properties objectForKey: @"recipients"]; + if (recipients) + { + mgr = [SOGoUserManager sharedUserManager]; + + /* TODO: this code might need to be moved into MAPIStoreMessage */ + msgData->columns = set_SPropTagArray (msgData, 9, + PR_OBJECT_TYPE, + PR_DISPLAY_TYPE, + PR_7BIT_DISPLAY_NAME_UNICODE, + PR_SMTP_ADDRESS_UNICODE, + PR_SEND_INTERNET_ENCODING, + PR_RECIPIENT_DISPLAY_NAME_UNICODE, + PR_RECIPIENT_FLAGS, + PR_RECIPIENT_ENTRYID, + PR_RECIPIENT_TRACKSTATUS); + + maxRecTypes = sizeof(recTypes) / sizeof(recTypes[0]); + for (nRecType = 0; nRecType < maxRecTypes; nRecType++) + { + attendees = [recipients objectForKey: recTypes[nRecType]]; + max = [attendees count]; + if (max > 0) + { + msgData->recipients_count += max; + msgData->recipients = talloc_realloc(msgData, + msgData->recipients, struct + mapistore_message_recipient, msgData->recipients_count); + recipient = msgData->recipients; + for (count = 0; count < max; count++) + { + attendee = [attendees objectAtIndex: count]; + recipient->type = recTypesValue[nRecType]; + email = [attendee objectForKey: @"email"]; + if (email) + { + contactInfos + = [mgr contactInfosForUserWithUIDorEmail: email]; + recipient->username = [[contactInfos + objectForKey: @"c_uid"] + asUnicodeInMemCtx: msgData]; + } + else + recipient->username = NULL; + + recipient->data = talloc_array(msgData, void *, + msgData->columns->cValues); + for (propCount = 0; + propCount < msgData->columns->cValues; + propCount++) + { + currentValue = [attendee objectForKey: MAPIPropertyKey (msgData->columns->aulPropTag[propCount])]; + [currentValue getValue: recipient->data + propCount + forTag: msgData->columns->aulPropTag[propCount] + inMemCtx: msgData]; + } + recipient++; + } + } + } + } + else + { + /* HACK: we know the first (and only) proxy is our appointment wrapper + instance, but this might not always be true */ + [[proxies objectAtIndex: 0] fillMessageData: msgData + inMemCtx: memCtx]; + } *dataPtr = msgData; } @@ -368,8 +447,11 @@ /* reinstantiate the old sogo object and attach it to self */ woContext = [[self userContext] woContext]; if (isNew) - newObject = [SOGoAppointmentObject objectWithName: cname - inContainer: folder]; + { + newObject = [SOGoAppointmentObject objectWithName: cname + inContainer: folder]; + [newObject setIsNew: YES]; + } else { /* dissociate the object url from the old object's id */ From 90e226d5bb366335076ea9442696f0787487dc58 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 16 Aug 2012 21:05:16 +0000 Subject: [PATCH 107/127] Monotone-Parent: d50a947c2bfbadd4649b083ee3432fbdd28180c2 Monotone-Revision: 1fb3121c84e0bb2773973fcfde109c7b26530951 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-16T21:05:16 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 ++ OpenChange/MAPIStoreCalendarMessage.m | 73 +++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3fd14b8b4..1401d6101 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,11 @@ (-getMessageData:inMemCtx:): when a "recipients" records is available in the properties, we must return that list instead of the list of attendees since it will be the most recent one. + (_fixupAppointmentObjectWithUID::): when an appointment had been + deleted, we first attempt to resurrect it from the database before + reinstantiating it, which allows the event synchronisation to + happen properly in [SOGoAppointmentObject + updateContentWithCalendar:fromRequest:]. * OpenChange/MAPIStoreMapping.m (_updateFolderWithURL:withURL:): we retain and release "oldURL" to avoid releasing it when it diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index 3cc5af4f9..7371aa826 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -33,8 +33,11 @@ #import #import #import +#import +#import #import #import +#import #import #import #import @@ -78,6 +81,8 @@ // extern void ndr_print_AppointmentRecurrencePattern(struct ndr_print *ndr, const char *name, const struct AppointmentRecurrencePattern *r); +static Class NSArrayK; + @implementation SOGoAppointmentObject (MAPIStoreExtension) - (Class) mapistoreMessageClass @@ -89,6 +94,11 @@ @implementation MAPIStoreCalendarMessage ++ (void) initialize +{ + NSArrayK = [NSArray class]; +} + + (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP inMemCtx: (TALLOC_CTX *) memCtx { @@ -425,14 +435,61 @@ return uid; } +- (SOGoAppointmentObject *) _resurrectRecord: (NSString *) cname + fromFolder: (SOGoAppointmentFolder *) folder +{ + NSArray *records; + EOQualifier *qualifier; + EOFetchSpecification *fs; + GCSFolder *ocsFolder; + SOGoAppointmentObject *newObject; + NSMutableDictionary *newRecord; + static NSArray *childRecordFields = nil; + + if (!childRecordFields) + { + childRecordFields = [NSArray arrayWithObjects: @"c_name", + @"c_creationdate", @"c_lastmodified", + @"c_content", nil]; + [childRecordFields retain]; + } + + ocsFolder = [folder ocsFolder]; + + qualifier + = [EOQualifier qualifierWithQualifierFormat: + [NSString stringWithFormat: @"c_name='%@'", cname]]; + fs = [EOFetchSpecification fetchSpecificationWithEntityName: [ocsFolder folderName] + qualifier: qualifier + sortOrderings: nil]; + records = [ocsFolder fetchFields: childRecordFields + fetchSpecification: fs + ignoreDeleted: NO]; + if ([records isKindOfClass: NSArrayK] && [records count]) + { + newRecord = [[records objectAtIndex: 0] mutableCopy]; + [newRecord setObject: [NSNumber numberWithInt: 0] + forKey: @"c_version"]; + newObject = [SOGoAppointmentObject objectWithRecord: newRecord + inContainer: folder]; + [newRecord autorelease]; + [newObject setIsNew: NO]; + } + else + newObject = nil; + + + return newObject; +} + - (void) _fixupAppointmentObjectWithUID: (NSString *) uid { NSString *cname, *url; MAPIStoreMapping *mapping; uint64_t objectId; + WOContext *woContext; SOGoAppointmentFolder *folder; SOGoAppointmentObject *newObject; - WOContext *woContext; cname = [[container sogoObject] resourceNameForEventUID: uid]; if (cname) @@ -443,14 +500,20 @@ mapping = [self mapping]; url = [NSString stringWithFormat: @"%@%@", [container url], cname]; - folder = [container sogoObject]; + folder = [sogoObject container]; + /* reinstantiate the old sogo object and attach it to self */ woContext = [[self userContext] woContext]; if (isNew) { - newObject = [SOGoAppointmentObject objectWithName: cname - inContainer: folder]; - [newObject setIsNew: YES]; + /* event could have been deleted, let's try to resurrect it */ + newObject = [self _resurrectRecord: cname fromFolder: folder]; + if (!newObject) + { + newObject = [SOGoAppointmentObject objectWithName: cname + inContainer: folder]; + [newObject setIsNew: YES]; + } } else { From cb2f8e27dd21bd98f1387e69fc26557392db4f4d Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Fri, 17 Aug 2012 15:24:27 +0000 Subject: [PATCH 108/127] Updated Native Microsoft Outlook Configuration Guide. Monotone-Parent: d073d1d434e8c6c57d9c0f53a3cac4c19354b6f7 Monotone-Revision: 22f4b6731e332b6ef213a0c2e104ac7fef48969a Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2012-08-17T15:24:27 Monotone-Branch: ca.inverse.sogo --- ...Native Microsoft Outlook Configuration.odt | Bin 24189 -> 30477 bytes Documentation/sogo-2.png | Bin 0 -> 56690 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Documentation/sogo-2.png diff --git a/Documentation/SOGo Native Microsoft Outlook Configuration.odt b/Documentation/SOGo Native Microsoft Outlook Configuration.odt index 6f21afc607a3a348c1a038a44ff285518773da44..1eed637675fbca3e3830e70c38515cf47c8c3036 100644 GIT binary patch delta 27971 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

6_rVB?_SIDp?i1YzAY2V)<=7gc8j{a> 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 delta 21682 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 AcK`qY diff --git a/Documentation/sogo-2.png b/Documentation/sogo-2.png new file mode 100644 index 0000000000000000000000000000000000000000..0c73b13b9352b9e2391e736ced74d0f66811256f GIT binary patch literal 56690 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 literal 0 HcmV?d00001 From fb297c913c11347b2b9719119c710022ad7d086d Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 17 Aug 2012 17:56:25 +0000 Subject: [PATCH 109/127] Monotone-Parent: 1fb3121c84e0bb2773973fcfde109c7b26530951 Monotone-Revision: e2f910a1982b774a3f5dfd586d968821441f2076 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-17T17:56:25 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 6 ++++++ OpenChange/MAPIStoreContext.m | 14 +++++++++----- OpenChange/MAPIStoreFolder.m | 9 ++++++--- OpenChange/MAPIStoreMailContext.m | 7 +++++-- OpenChange/MAPIStoreMailFolder.m | 13 ++++++------- 5 files changed, 32 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1401d6101..0750a45db 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-08-17 Wolfgang Sourdeau + + * OpenChange/MAPIStoreContext.m (-getPath:ofFMID:inMemCtx:): + properly escape urls containing non-ascii chars. + (-getRootFoldeR:withFID:): idem. + 2012-08-16 Wolfgang Sourdeau * OpenChange/MAPIStoreCalendarMessage.m diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m index a3704289b..6899aa202 100644 --- a/OpenChange/MAPIStoreContext.m +++ b/OpenChange/MAPIStoreContext.m @@ -366,7 +366,8 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) NSString *objectURL, *url; // TDB_DATA key, dbuf; - url = [contextUrl absoluteString]; + url = [[contextUrl absoluteString] + stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; objectURL = [[userContext mapping] urlFromID: fmid]; if (objectURL) { @@ -417,15 +418,18 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) MAPIStoreFolder *baseFolder; SOGoFolder *currentFolder; WOContext *woContext; - NSString *path; + NSString *path, *urlString; NSArray *pathComponents; NSUInteger count, max; mapping = [userContext mapping]; if (![mapping urlFromID: newFid]) - [mapping registerURL: [contextUrl absoluteString] - withID: newFid]; - + { + urlString = [[contextUrl absoluteString] + stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; + [mapping registerURL: urlString + withID: newFid]; + } [userContext activateWithUser: activeUser]; woContext = [userContext woContext]; diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 5d5da9a07..5cf2bf834 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -94,12 +94,14 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe { NSURL *folderURL; NSMutableString *pathPrefix; - NSString *path, *folderName; + NSString *path, *escapedURL, *folderName; NSArray *parts; NSUInteger lastPartIdx; MAPIStoreUserContext *userContext; - folderURL = [NSURL URLWithString: [self url]]; + escapedURL = [[self url] + stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; + folderURL = [NSURL URLWithString: escapedURL]; path = [folderURL path]; path = [path substringFromIndex: 1]; if ([path length] > 0) @@ -1495,7 +1497,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe url = [NSString stringWithFormat: @"%@/", [super url]]; else { - url = [[context url] absoluteString]; + url = [[[context url] absoluteString] + stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; if (![url hasSuffix: @"/"]) url = [NSString stringWithFormat: @"%@/", url]; } diff --git a/OpenChange/MAPIStoreMailContext.m b/OpenChange/MAPIStoreMailContext.m index 8046c994c..e687a02b8 100644 --- a/OpenChange/MAPIStoreMailContext.m +++ b/OpenChange/MAPIStoreMailContext.m @@ -206,12 +206,14 @@ MakeDisplayFolderName (NSString *folderName) - (void) updateURLWithFolderName: (NSString *) newFolderName { - NSString *urlString; + NSString *urlString, *escapedName; NSMutableArray *pathComponents; BOOL hasSlash; NSUInteger max, folderNameIdx; NSURL *newURL; + /* we do not need to unescape the url here as it will be reassembled later + in the method */ urlString = [contextUrl absoluteString]; hasSlash = [urlString hasSuffix: @"/"]; pathComponents = [[urlString componentsSeparatedByString: @"/"] @@ -222,8 +224,9 @@ MakeDisplayFolderName (NSString *folderName) folderNameIdx = max - 2; else folderNameIdx = max - 1; + escapedName = [newFolderName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; [pathComponents replaceObjectAtIndex: folderNameIdx - withObject: [newFolderName stringByEscapingURL]]; + withObject: escapedName]; urlString = [pathComponents componentsJoinedByString: @"/"]; newURL = [NSURL URLWithString: urlString]; ASSIGN (contextUrl, newURL); diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 45e3c7c91..fc1a4278d 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1046,15 +1046,15 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) folderURL = [sogoObject imap4URL]; if (!newFolderName) newFolderName = [sogoObject displayName]; - newFolderName = [newFolderName stringByEscapingURL]; targetSOGoFolder = [targetFolder sogoObject]; - newFolderURL = [NSURL URLWithString: newFolderName - relativeToURL: [targetSOGoFolder imap4URL]]; if (isMove) { + newFolderURL = [NSURL + URLWithString: [newFolderName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding] + relativeToURL: [targetSOGoFolder imap4URL]]; error = [[sogoObject imap4Connection] - moveMailboxAtURL: folderURL - toURL: newFolderURL]; + moveMailboxAtURL: folderURL + toURL: newFolderURL]; if (error) rc = MAPISTORE_ERR_DENIED; else @@ -1063,8 +1063,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) mapping = [self mapping]; newURL = [NSString stringWithFormat: @"%@folder%@/", [targetFolder url], newFolderName]; - [mapping updateID: [self objectId] - withURL: newURL]; + [mapping updateID: [self objectId] withURL: newURL]; parentDBFolderPath = [[targetFolder dbFolder] path]; if (!parentDBFolderPath) parentDBFolderPath = @""; From bde4b22ba7740fee46d654c960d9f86f1ce7ff39 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 17 Aug 2012 19:04:57 +0000 Subject: [PATCH 110/127] Monotone-Parent: 572391072fa416635b9921d39ed76478ed762097 Monotone-Revision: 105b571703ff5c4cc1024854ef8a1d987aef2bf1 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-17T19:04:57 Monotone-Branch: ca.inverse.sogo --- OpenChange/EOBitmaskQualifier.h | 2 +- OpenChange/EOBitmaskQualifier.m | 2 +- OpenChange/EOQualifier+MAPI.h | 2 +- OpenChange/EOQualifier+MAPI.m | 2 +- OpenChange/MAPIApplication.h | 2 +- OpenChange/MAPIStoreActiveTables.h | 2 +- OpenChange/MAPIStoreActiveTables.m | 2 +- OpenChange/MAPIStoreAppointmentWrapper.h | 2 +- OpenChange/MAPIStoreAppointmentWrapper.m | 2 +- OpenChange/MAPIStoreAttachment.h | 2 +- OpenChange/MAPIStoreAttachment.m | 2 +- OpenChange/MAPIStoreAttachmentTable.h | 2 +- OpenChange/MAPIStoreAttachmentTable.m | 2 +- OpenChange/MAPIStoreAuthenticator.h | 2 +- OpenChange/MAPIStoreAuthenticator.m | 2 +- OpenChange/MAPIStoreCalendarAttachment.h | 2 +- OpenChange/MAPIStoreCalendarAttachment.m | 2 +- OpenChange/MAPIStoreCalendarContext.h | 2 +- OpenChange/MAPIStoreCalendarContext.m | 2 +- OpenChange/MAPIStoreCalendarFolder.h | 2 +- OpenChange/MAPIStoreCalendarFolder.m | 2 +- OpenChange/MAPIStoreCalendarMessage.h | 2 +- OpenChange/MAPIStoreCalendarMessage.m | 2 +- OpenChange/MAPIStoreCalendarMessageTable.h | 2 +- OpenChange/MAPIStoreCalendarMessageTable.m | 2 +- OpenChange/MAPIStoreContactsAttachment.h | 2 +- OpenChange/MAPIStoreContactsAttachment.m | 2 +- OpenChange/MAPIStoreContactsContext.h | 2 +- OpenChange/MAPIStoreContactsContext.m | 2 +- OpenChange/MAPIStoreContactsFolder.h | 2 +- OpenChange/MAPIStoreContactsFolder.m | 2 +- OpenChange/MAPIStoreContactsMessage.h | 2 +- OpenChange/MAPIStoreContactsMessage.m | 2 +- OpenChange/MAPIStoreContactsMessageTable.h | 2 +- OpenChange/MAPIStoreContactsMessageTable.m | 2 +- OpenChange/MAPIStoreContext.h | 2 +- OpenChange/MAPIStoreContext.m | 2 +- OpenChange/MAPIStoreDBFolder.m | 2 +- OpenChange/MAPIStoreDBMessage.m | 2 +- OpenChange/MAPIStoreEmbeddedMessage.h | 2 +- OpenChange/MAPIStoreEmbeddedMessage.m | 2 +- OpenChange/MAPIStoreFAIMessage.h | 2 +- OpenChange/MAPIStoreFAIMessage.m | 2 +- OpenChange/MAPIStoreFAIMessageTable.h | 2 +- OpenChange/MAPIStoreFAIMessageTable.m | 2 +- OpenChange/MAPIStoreFallbackContext.h | 2 +- OpenChange/MAPIStoreFallbackContext.m | 2 +- OpenChange/MAPIStoreFolder.h | 2 +- OpenChange/MAPIStoreFolder.m | 2 +- OpenChange/MAPIStoreFolderTable.h | 2 +- OpenChange/MAPIStoreFolderTable.m | 2 +- OpenChange/MAPIStoreGCSBaseContext.h | 2 +- OpenChange/MAPIStoreGCSBaseContext.m | 2 +- OpenChange/MAPIStoreGCSFolder.h | 2 +- OpenChange/MAPIStoreGCSFolder.m | 2 +- OpenChange/MAPIStoreGCSMessage.h | 2 +- OpenChange/MAPIStoreGCSMessage.m | 2 +- OpenChange/MAPIStoreGCSMessageTable.h | 2 +- OpenChange/MAPIStoreGCSMessageTable.m | 2 +- OpenChange/MAPIStoreMIME.h | 2 +- OpenChange/MAPIStoreMIME.m | 2 +- OpenChange/MAPIStoreMailAttachment.h | 2 +- OpenChange/MAPIStoreMailAttachment.m | 2 +- OpenChange/MAPIStoreMailContext.h | 2 +- OpenChange/MAPIStoreMailContext.m | 2 +- OpenChange/MAPIStoreMailFolder.h | 2 +- OpenChange/MAPIStoreMailFolder.m | 2 +- OpenChange/MAPIStoreMailMessage.h | 2 +- OpenChange/MAPIStoreMailMessage.m | 2 +- OpenChange/MAPIStoreMailMessageTable.h | 2 +- OpenChange/MAPIStoreMailMessageTable.m | 2 +- OpenChange/MAPIStoreMailVolatileMessage.h | 2 +- OpenChange/MAPIStoreMailVolatileMessage.m | 2 +- OpenChange/MAPIStoreMapping.h | 2 +- OpenChange/MAPIStoreMapping.m | 2 +- OpenChange/MAPIStoreMessage.h | 2 +- OpenChange/MAPIStoreMessage.m | 2 +- OpenChange/MAPIStoreMessageTable.h | 2 +- OpenChange/MAPIStoreMessageTable.m | 2 +- OpenChange/MAPIStoreNotesContext.h | 2 +- OpenChange/MAPIStoreNotesContext.m | 2 +- OpenChange/MAPIStoreNotesFolder.h | 2 +- OpenChange/MAPIStoreNotesFolder.m | 2 +- OpenChange/MAPIStoreNotesMessage.h | 2 +- OpenChange/MAPIStoreNotesMessage.m | 2 +- OpenChange/MAPIStoreObject.h | 2 +- OpenChange/MAPIStoreObject.m | 2 +- OpenChange/MAPIStorePermissionsTable.h | 2 +- OpenChange/MAPIStorePermissionsTable.m | 2 +- OpenChange/MAPIStoreRecurrenceUtils.h | 2 +- OpenChange/MAPIStoreRecurrenceUtils.m | 2 +- OpenChange/MAPIStoreSOGo.m | 2 +- OpenChange/MAPIStoreSOGoObject.h | 2 +- OpenChange/MAPIStoreSOGoObject.m | 2 +- OpenChange/MAPIStoreSamDBUtils.h | 2 +- OpenChange/MAPIStoreSamDBUtils.m | 2 +- OpenChange/MAPIStoreTable.h | 2 +- OpenChange/MAPIStoreTable.m | 2 +- OpenChange/MAPIStoreTasksContext.h | 2 +- OpenChange/MAPIStoreTasksContext.m | 2 +- OpenChange/MAPIStoreTasksFolder.h | 2 +- OpenChange/MAPIStoreTasksFolder.m | 2 +- OpenChange/MAPIStoreTasksMessage.h | 2 +- OpenChange/MAPIStoreTasksMessage.m | 2 +- OpenChange/MAPIStoreTasksMessageTable.h | 2 +- OpenChange/MAPIStoreTasksMessageTable.m | 2 +- OpenChange/MAPIStoreTypes.h | 2 +- OpenChange/MAPIStoreTypes.m | 2 +- OpenChange/NSArray+MAPIStore.m | 2 +- OpenChange/NSData+MAPIStore.m | 2 +- OpenChange/NSDate+MAPIStore.h | 2 +- OpenChange/NSDate+MAPIStore.m | 2 +- OpenChange/NSObject+MAPIStore.h | 2 +- OpenChange/NSObject+MAPIStore.m | 2 +- OpenChange/NSObject+PropertyList.m | 2 +- OpenChange/NSString+MAPIStore.h | 2 +- OpenChange/NSString+MAPIStore.m | 2 +- OpenChange/NSValue+MAPIStore.h | 2 +- OpenChange/NSValue+MAPIStore.m | 2 +- OpenChange/code-MAPIStorePropertySelectors.h | 2 +- OpenChange/code-MAPIStorePropertySelectors.m | 2 +- OpenChange/dbmsgreader.m | 2 +- OpenChange/plreader.m | 2 +- 123 files changed, 123 insertions(+), 123 deletions(-) diff --git a/OpenChange/EOBitmaskQualifier.h b/OpenChange/EOBitmaskQualifier.h index 263e37fc1..405a1f1fa 100644 --- a/OpenChange/EOBitmaskQualifier.h +++ b/OpenChange/EOBitmaskQualifier.h @@ -1,6 +1,6 @@ /* EOBitmaskQualifier.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/EOBitmaskQualifier.m b/OpenChange/EOBitmaskQualifier.m index c2bbf56ae..14f3eee93 100644 --- a/OpenChange/EOBitmaskQualifier.m +++ b/OpenChange/EOBitmaskQualifier.m @@ -1,6 +1,6 @@ /* EOBitmaskQualifier.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/EOQualifier+MAPI.h b/OpenChange/EOQualifier+MAPI.h index 72f368b63..9fabef4b9 100644 --- a/OpenChange/EOQualifier+MAPI.h +++ b/OpenChange/EOQualifier+MAPI.h @@ -1,6 +1,6 @@ /* EOQualifier+MAPI.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/EOQualifier+MAPI.m b/OpenChange/EOQualifier+MAPI.m index 8707dd788..65e28c6fd 100644 --- a/OpenChange/EOQualifier+MAPI.m +++ b/OpenChange/EOQualifier+MAPI.m @@ -1,6 +1,6 @@ /* EOQualifier+MAPI.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIApplication.h b/OpenChange/MAPIApplication.h index 2b30e692c..e96d2d545 100644 --- a/OpenChange/MAPIApplication.h +++ b/OpenChange/MAPIApplication.h @@ -1,6 +1,6 @@ /* MAPIApplication.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreActiveTables.h b/OpenChange/MAPIStoreActiveTables.h index 106e73b1e..8459bd9c1 100644 --- a/OpenChange/MAPIStoreActiveTables.h +++ b/OpenChange/MAPIStoreActiveTables.h @@ -1,6 +1,6 @@ /* MAPIStoreActiveTables.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreActiveTables.m b/OpenChange/MAPIStoreActiveTables.m index d72a62f02..a9cb0c254 100644 --- a/OpenChange/MAPIStoreActiveTables.m +++ b/OpenChange/MAPIStoreActiveTables.m @@ -1,6 +1,6 @@ /* MAPIStoreActiveTables.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreAppointmentWrapper.h b/OpenChange/MAPIStoreAppointmentWrapper.h index d0f3fbc00..aecf2200f 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.h +++ b/OpenChange/MAPIStoreAppointmentWrapper.h @@ -1,6 +1,6 @@ /* MAPIStoreAppointmentWrapper.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index 86437006a..07673012c 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -1,6 +1,6 @@ /* MAPIStoreAppointmentWrapper.m - this file is part of SOGo * - * Copyright (C) 2011, 2012 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreAttachment.h b/OpenChange/MAPIStoreAttachment.h index 5ee546c0e..c859e7c8a 100644 --- a/OpenChange/MAPIStoreAttachment.h +++ b/OpenChange/MAPIStoreAttachment.h @@ -1,6 +1,6 @@ /* MAPIStoreAttachment.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreAttachment.m b/OpenChange/MAPIStoreAttachment.m index a3c17ec45..05cdaec15 100644 --- a/OpenChange/MAPIStoreAttachment.m +++ b/OpenChange/MAPIStoreAttachment.m @@ -1,6 +1,6 @@ /* MAPIStoreAttachment.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreAttachmentTable.h b/OpenChange/MAPIStoreAttachmentTable.h index 94f57e551..d066a7b8c 100644 --- a/OpenChange/MAPIStoreAttachmentTable.h +++ b/OpenChange/MAPIStoreAttachmentTable.h @@ -1,6 +1,6 @@ /* MAPIStoreAttachmentTable.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreAttachmentTable.m b/OpenChange/MAPIStoreAttachmentTable.m index bdf8d960e..61c82dd1b 100644 --- a/OpenChange/MAPIStoreAttachmentTable.m +++ b/OpenChange/MAPIStoreAttachmentTable.m @@ -1,6 +1,6 @@ /* MAPIStoreAttachmentTable.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreAuthenticator.h b/OpenChange/MAPIStoreAuthenticator.h index 985de43b5..fc41d25d1 100644 --- a/OpenChange/MAPIStoreAuthenticator.h +++ b/OpenChange/MAPIStoreAuthenticator.h @@ -1,7 +1,7 @@ /* MAPIStoreAuthenticator.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreAuthenticator.m b/OpenChange/MAPIStoreAuthenticator.m index 023a68e83..c3174a615 100644 --- a/OpenChange/MAPIStoreAuthenticator.m +++ b/OpenChange/MAPIStoreAuthenticator.m @@ -1,6 +1,6 @@ /* MAPIStoreAuthenticator.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarAttachment.h b/OpenChange/MAPIStoreCalendarAttachment.h index c97f752d5..9dce8d17e 100644 --- a/OpenChange/MAPIStoreCalendarAttachment.h +++ b/OpenChange/MAPIStoreCalendarAttachment.h @@ -1,6 +1,6 @@ /* MAPIStoreCalendarAttachment.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarAttachment.m b/OpenChange/MAPIStoreCalendarAttachment.m index d44a21e47..cbe63c6d7 100644 --- a/OpenChange/MAPIStoreCalendarAttachment.m +++ b/OpenChange/MAPIStoreCalendarAttachment.m @@ -1,6 +1,6 @@ /* MAPIStoreCalendarAttachment.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarContext.h b/OpenChange/MAPIStoreCalendarContext.h index 96df4d1c2..e6f804805 100644 --- a/OpenChange/MAPIStoreCalendarContext.h +++ b/OpenChange/MAPIStoreCalendarContext.h @@ -1,6 +1,6 @@ /* MAPIStoreCalendarContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarContext.m b/OpenChange/MAPIStoreCalendarContext.m index 279e9a081..035741afb 100644 --- a/OpenChange/MAPIStoreCalendarContext.m +++ b/OpenChange/MAPIStoreCalendarContext.m @@ -1,6 +1,6 @@ /* MAPIStoreCalendarContext.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarFolder.h b/OpenChange/MAPIStoreCalendarFolder.h index 8c483f9c9..fd6c5d20f 100644 --- a/OpenChange/MAPIStoreCalendarFolder.h +++ b/OpenChange/MAPIStoreCalendarFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreCalendarFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarFolder.m b/OpenChange/MAPIStoreCalendarFolder.m index f35918596..eeb5bb81e 100644 --- a/OpenChange/MAPIStoreCalendarFolder.m +++ b/OpenChange/MAPIStoreCalendarFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreCalendarFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarMessage.h b/OpenChange/MAPIStoreCalendarMessage.h index a98149ac2..8b2de759d 100644 --- a/OpenChange/MAPIStoreCalendarMessage.h +++ b/OpenChange/MAPIStoreCalendarMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreCalendarMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index 7371aa826..6d65d2313 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreCalendarMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarMessageTable.h b/OpenChange/MAPIStoreCalendarMessageTable.h index 1bed13a1b..eeccbc455 100644 --- a/OpenChange/MAPIStoreCalendarMessageTable.h +++ b/OpenChange/MAPIStoreCalendarMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreCalendarMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarMessageTable.m b/OpenChange/MAPIStoreCalendarMessageTable.m index 6d897b772..6844d8433 100644 --- a/OpenChange/MAPIStoreCalendarMessageTable.m +++ b/OpenChange/MAPIStoreCalendarMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreCalendarMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsAttachment.h b/OpenChange/MAPIStoreContactsAttachment.h index b8f0d16e3..c4a368849 100644 --- a/OpenChange/MAPIStoreContactsAttachment.h +++ b/OpenChange/MAPIStoreContactsAttachment.h @@ -1,6 +1,6 @@ /* MAPIStoreContactsAttachment.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsAttachment.m b/OpenChange/MAPIStoreContactsAttachment.m index 00fc652d6..f578dbc61 100644 --- a/OpenChange/MAPIStoreContactsAttachment.m +++ b/OpenChange/MAPIStoreContactsAttachment.m @@ -1,6 +1,6 @@ /* MAPIStoreContactsAttachment.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsContext.h b/OpenChange/MAPIStoreContactsContext.h index 9e1e45498..68120215e 100644 --- a/OpenChange/MAPIStoreContactsContext.h +++ b/OpenChange/MAPIStoreContactsContext.h @@ -1,6 +1,6 @@ /* MAPIStoreContactsContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsContext.m b/OpenChange/MAPIStoreContactsContext.m index 967b1ccd3..bfef33e27 100644 --- a/OpenChange/MAPIStoreContactsContext.m +++ b/OpenChange/MAPIStoreContactsContext.m @@ -1,6 +1,6 @@ /* MAPIStoreContactsContext.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsFolder.h b/OpenChange/MAPIStoreContactsFolder.h index c269a6cfc..2bade99f7 100644 --- a/OpenChange/MAPIStoreContactsFolder.h +++ b/OpenChange/MAPIStoreContactsFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreContactsFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsFolder.m b/OpenChange/MAPIStoreContactsFolder.m index 3e7fe71c5..fc0c35840 100644 --- a/OpenChange/MAPIStoreContactsFolder.m +++ b/OpenChange/MAPIStoreContactsFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreContactsFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsMessage.h b/OpenChange/MAPIStoreContactsMessage.h index f22a077a1..48d5bafb0 100644 --- a/OpenChange/MAPIStoreContactsMessage.h +++ b/OpenChange/MAPIStoreContactsMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreContactsMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsMessage.m b/OpenChange/MAPIStoreContactsMessage.m index bc8d3a6d4..3097367c0 100644 --- a/OpenChange/MAPIStoreContactsMessage.m +++ b/OpenChange/MAPIStoreContactsMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreContactsMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * Ludovic Marcotte diff --git a/OpenChange/MAPIStoreContactsMessageTable.h b/OpenChange/MAPIStoreContactsMessageTable.h index 56a317cb0..0563f9b2e 100644 --- a/OpenChange/MAPIStoreContactsMessageTable.h +++ b/OpenChange/MAPIStoreContactsMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreContactsMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsMessageTable.m b/OpenChange/MAPIStoreContactsMessageTable.m index e46a5813e..524ed06c3 100644 --- a/OpenChange/MAPIStoreContactsMessageTable.m +++ b/OpenChange/MAPIStoreContactsMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreContactsMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContext.h b/OpenChange/MAPIStoreContext.h index fdea9bbd1..d57ffeb74 100644 --- a/OpenChange/MAPIStoreContext.h +++ b/OpenChange/MAPIStoreContext.h @@ -1,6 +1,6 @@ /* MAPIStoreContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m index 6899aa202..dceed826f 100644 --- a/OpenChange/MAPIStoreContext.m +++ b/OpenChange/MAPIStoreContext.m @@ -1,6 +1,6 @@ /* MAPIStoreContext.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreDBFolder.m b/OpenChange/MAPIStoreDBFolder.m index 0306c2012..cacbb2376 100644 --- a/OpenChange/MAPIStoreDBFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreDBFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreDBMessage.m b/OpenChange/MAPIStoreDBMessage.m index 3ea3704d0..2e535c7bc 100644 --- a/OpenChange/MAPIStoreDBMessage.m +++ b/OpenChange/MAPIStoreDBMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreDBMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreEmbeddedMessage.h b/OpenChange/MAPIStoreEmbeddedMessage.h index 62c9431ba..4ef65f261 100644 --- a/OpenChange/MAPIStoreEmbeddedMessage.h +++ b/OpenChange/MAPIStoreEmbeddedMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreEmbeddedMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreEmbeddedMessage.m b/OpenChange/MAPIStoreEmbeddedMessage.m index 2d408e1ba..562d581de 100644 --- a/OpenChange/MAPIStoreEmbeddedMessage.m +++ b/OpenChange/MAPIStoreEmbeddedMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreEmbeddedMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreFAIMessage.h b/OpenChange/MAPIStoreFAIMessage.h index fd4d08930..509bd37be 100644 --- a/OpenChange/MAPIStoreFAIMessage.h +++ b/OpenChange/MAPIStoreFAIMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreFAIMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreFAIMessage.m b/OpenChange/MAPIStoreFAIMessage.m index ef30a9b59..99ab23c85 100644 --- a/OpenChange/MAPIStoreFAIMessage.m +++ b/OpenChange/MAPIStoreFAIMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreFAIMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreFAIMessageTable.h b/OpenChange/MAPIStoreFAIMessageTable.h index 0aa6d7230..c12f20f99 100644 --- a/OpenChange/MAPIStoreFAIMessageTable.h +++ b/OpenChange/MAPIStoreFAIMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreFAIMessageTable.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreFAIMessageTable.m b/OpenChange/MAPIStoreFAIMessageTable.m index fb7b6df1f..531299868 100644 --- a/OpenChange/MAPIStoreFAIMessageTable.m +++ b/OpenChange/MAPIStoreFAIMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreFAIMessageTable.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreFallbackContext.h b/OpenChange/MAPIStoreFallbackContext.h index eaf992bb7..a6a2707ab 100644 --- a/OpenChange/MAPIStoreFallbackContext.h +++ b/OpenChange/MAPIStoreFallbackContext.h @@ -1,6 +1,6 @@ /* MAPIStoreFallbackContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreFallbackContext.m b/OpenChange/MAPIStoreFallbackContext.m index 37da58d7d..ea6fa7ff3 100644 --- a/OpenChange/MAPIStoreFallbackContext.m +++ b/OpenChange/MAPIStoreFallbackContext.m @@ -1,6 +1,6 @@ /* MAPIStoreFallbackContext.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc. + * Copyright (C) 2011-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreFolder.h b/OpenChange/MAPIStoreFolder.h index ccf3c800c..262334dfc 100644 --- a/OpenChange/MAPIStoreFolder.h +++ b/OpenChange/MAPIStoreFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 5cf2bf834..50b357236 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreFolderTable.h b/OpenChange/MAPIStoreFolderTable.h index f8c2b24d0..b584c6084 100644 --- a/OpenChange/MAPIStoreFolderTable.h +++ b/OpenChange/MAPIStoreFolderTable.h @@ -1,6 +1,6 @@ /* MAPIStoreFolderTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreFolderTable.m b/OpenChange/MAPIStoreFolderTable.m index c0beed517..d76c9890e 100644 --- a/OpenChange/MAPIStoreFolderTable.m +++ b/OpenChange/MAPIStoreFolderTable.m @@ -1,6 +1,6 @@ /* MAPIStoreFolderTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSBaseContext.h b/OpenChange/MAPIStoreGCSBaseContext.h index 76fba3602..8d9e57f5d 100644 --- a/OpenChange/MAPIStoreGCSBaseContext.h +++ b/OpenChange/MAPIStoreGCSBaseContext.h @@ -1,6 +1,6 @@ /* MAPIStoreGCSBaseContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSBaseContext.m b/OpenChange/MAPIStoreGCSBaseContext.m index 296479251..4da73b349 100644 --- a/OpenChange/MAPIStoreGCSBaseContext.m +++ b/OpenChange/MAPIStoreGCSBaseContext.m @@ -1,6 +1,6 @@ /* MAPIStoreGCSBaseContext.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSFolder.h b/OpenChange/MAPIStoreGCSFolder.h index d889b78a9..6d25069ca 100644 --- a/OpenChange/MAPIStoreGCSFolder.h +++ b/OpenChange/MAPIStoreGCSFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreGCSFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSFolder.m b/OpenChange/MAPIStoreGCSFolder.m index b94f10ad5..d042dfcf0 100644 --- a/OpenChange/MAPIStoreGCSFolder.m +++ b/OpenChange/MAPIStoreGCSFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreGCSFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSMessage.h b/OpenChange/MAPIStoreGCSMessage.h index 5ada9290b..cac182874 100644 --- a/OpenChange/MAPIStoreGCSMessage.h +++ b/OpenChange/MAPIStoreGCSMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreGCSMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSMessage.m b/OpenChange/MAPIStoreGCSMessage.m index 95c004430..143f9ef19 100644 --- a/OpenChange/MAPIStoreGCSMessage.m +++ b/OpenChange/MAPIStoreGCSMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreGCSMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSMessageTable.h b/OpenChange/MAPIStoreGCSMessageTable.h index 00b03cded..72190c221 100644 --- a/OpenChange/MAPIStoreGCSMessageTable.h +++ b/OpenChange/MAPIStoreGCSMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreGCSMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSMessageTable.m b/OpenChange/MAPIStoreGCSMessageTable.m index ef4006394..74d9d3151 100644 --- a/OpenChange/MAPIStoreGCSMessageTable.m +++ b/OpenChange/MAPIStoreGCSMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreGCSMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMIME.h b/OpenChange/MAPIStoreMIME.h index 427868fca..eb2d2a6b2 100644 --- a/OpenChange/MAPIStoreMIME.h +++ b/OpenChange/MAPIStoreMIME.h @@ -1,6 +1,6 @@ /* MAPIStoreMIME.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMIME.m b/OpenChange/MAPIStoreMIME.m index b23f660e2..712cc88bc 100644 --- a/OpenChange/MAPIStoreMIME.m +++ b/OpenChange/MAPIStoreMIME.m @@ -1,6 +1,6 @@ /* MAPIStoreMIME.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailAttachment.h b/OpenChange/MAPIStoreMailAttachment.h index f9f0011e9..b04b197ab 100644 --- a/OpenChange/MAPIStoreMailAttachment.h +++ b/OpenChange/MAPIStoreMailAttachment.h @@ -1,6 +1,6 @@ /* MAPIStoreMailAttachment.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailAttachment.m b/OpenChange/MAPIStoreMailAttachment.m index 6834b8c1d..e62250549 100644 --- a/OpenChange/MAPIStoreMailAttachment.m +++ b/OpenChange/MAPIStoreMailAttachment.m @@ -1,6 +1,6 @@ /* MAPIStoreMailAttachment.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailContext.h b/OpenChange/MAPIStoreMailContext.h index 5c23fc98a..9e8371714 100644 --- a/OpenChange/MAPIStoreMailContext.h +++ b/OpenChange/MAPIStoreMailContext.h @@ -1,6 +1,6 @@ /* MAPIStoreMailContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailContext.m b/OpenChange/MAPIStoreMailContext.m index e687a02b8..43212e513 100644 --- a/OpenChange/MAPIStoreMailContext.m +++ b/OpenChange/MAPIStoreMailContext.m @@ -1,6 +1,6 @@ /* MAPIStoreMailContext.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailFolder.h b/OpenChange/MAPIStoreMailFolder.h index ab6430489..ad1c2dfdb 100644 --- a/OpenChange/MAPIStoreMailFolder.h +++ b/OpenChange/MAPIStoreMailFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreMailFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index fc1a4278d..9bbaede63 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreMailFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailMessage.h b/OpenChange/MAPIStoreMailMessage.h index 378d8e490..76b7a3258 100644 --- a/OpenChange/MAPIStoreMailMessage.h +++ b/OpenChange/MAPIStoreMailMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreMailMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index d035810ac..1fb87664e 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreMailMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * Ludovic Marcotte diff --git a/OpenChange/MAPIStoreMailMessageTable.h b/OpenChange/MAPIStoreMailMessageTable.h index 1a5f1f8c4..8efa43c16 100644 --- a/OpenChange/MAPIStoreMailMessageTable.h +++ b/OpenChange/MAPIStoreMailMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreMailMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailMessageTable.m b/OpenChange/MAPIStoreMailMessageTable.m index c1561bbd5..3933b62db 100644 --- a/OpenChange/MAPIStoreMailMessageTable.m +++ b/OpenChange/MAPIStoreMailMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreMailMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailVolatileMessage.h b/OpenChange/MAPIStoreMailVolatileMessage.h index 53a51847f..212226abf 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.h +++ b/OpenChange/MAPIStoreMailVolatileMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreMailVolatileMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index e3764fdc2..fa12130cf 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreMailVolatileMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMapping.h b/OpenChange/MAPIStoreMapping.h index 74b320aa0..22ba052d3 100644 --- a/OpenChange/MAPIStoreMapping.h +++ b/OpenChange/MAPIStoreMapping.h @@ -1,6 +1,6 @@ /* MAPIStoreMapping.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMapping.m b/OpenChange/MAPIStoreMapping.m index 448ef1d1b..e5e762127 100644 --- a/OpenChange/MAPIStoreMapping.m +++ b/OpenChange/MAPIStoreMapping.m @@ -1,6 +1,6 @@ /* MAPIStoreMapping.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMessage.h b/OpenChange/MAPIStoreMessage.h index 28230622e..c782cb0d6 100644 --- a/OpenChange/MAPIStoreMessage.h +++ b/OpenChange/MAPIStoreMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index 20c518baa..f354930b6 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMessageTable.h b/OpenChange/MAPIStoreMessageTable.h index 0779afaef..9b1473325 100644 --- a/OpenChange/MAPIStoreMessageTable.h +++ b/OpenChange/MAPIStoreMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMessageTable.m b/OpenChange/MAPIStoreMessageTable.m index f93ec13da..75d5adab9 100644 --- a/OpenChange/MAPIStoreMessageTable.m +++ b/OpenChange/MAPIStoreMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreNotesContext.h b/OpenChange/MAPIStoreNotesContext.h index 3f44d575d..0c2f58261 100644 --- a/OpenChange/MAPIStoreNotesContext.h +++ b/OpenChange/MAPIStoreNotesContext.h @@ -1,6 +1,6 @@ /* MAPIStoreNotesContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreNotesContext.m b/OpenChange/MAPIStoreNotesContext.m index b73a4032a..36d6804b9 100644 --- a/OpenChange/MAPIStoreNotesContext.m +++ b/OpenChange/MAPIStoreNotesContext.m @@ -1,6 +1,6 @@ /* MAPIStoreNotesContext.m - this file is part of SOGo * - * Copyright (C) 2010-2011 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreNotesFolder.h b/OpenChange/MAPIStoreNotesFolder.h index 9baebab27..4f049fb4f 100644 --- a/OpenChange/MAPIStoreNotesFolder.h +++ b/OpenChange/MAPIStoreNotesFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreNotesFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreNotesFolder.m b/OpenChange/MAPIStoreNotesFolder.m index bac783bd2..ae2652d88 100644 --- a/OpenChange/MAPIStoreNotesFolder.m +++ b/OpenChange/MAPIStoreNotesFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreNotesFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreNotesMessage.h b/OpenChange/MAPIStoreNotesMessage.h index d4ec7e1ba..08c1223d0 100644 --- a/OpenChange/MAPIStoreNotesMessage.h +++ b/OpenChange/MAPIStoreNotesMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreNotesMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreNotesMessage.m b/OpenChange/MAPIStoreNotesMessage.m index 7cac637b8..52712277b 100644 --- a/OpenChange/MAPIStoreNotesMessage.m +++ b/OpenChange/MAPIStoreNotesMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreNotesMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreObject.h b/OpenChange/MAPIStoreObject.h index ccbc5a157..d7aa989de 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -1,6 +1,6 @@ /* MAPIStoreObject.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index 9f1b04969..185f19286 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -1,6 +1,6 @@ /* MAPIStoreObject.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStorePermissionsTable.h b/OpenChange/MAPIStorePermissionsTable.h index ef490d8b3..3f951f50c 100644 --- a/OpenChange/MAPIStorePermissionsTable.h +++ b/OpenChange/MAPIStorePermissionsTable.h @@ -1,6 +1,6 @@ /* MAPIStorePermissionsTable.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStorePermissionsTable.m b/OpenChange/MAPIStorePermissionsTable.m index b5704610b..3dba53d79 100644 --- a/OpenChange/MAPIStorePermissionsTable.m +++ b/OpenChange/MAPIStorePermissionsTable.m @@ -1,6 +1,6 @@ /* MAPIStorePermissionsTable.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreRecurrenceUtils.h b/OpenChange/MAPIStoreRecurrenceUtils.h index a72a23af8..68c84361e 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.h +++ b/OpenChange/MAPIStoreRecurrenceUtils.h @@ -1,6 +1,6 @@ /* MAPIStoreRecurrenceUtils.h - this file is part of $PROJECT_NAME_HERE$ * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreRecurrenceUtils.m b/OpenChange/MAPIStoreRecurrenceUtils.m index 4f36253d5..ebf588000 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.m +++ b/OpenChange/MAPIStoreRecurrenceUtils.m @@ -1,6 +1,6 @@ /* MAPIStoreRecurrenceUtils.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 22abf4e68..09921b9b6 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -1,6 +1,6 @@ /* MAPIStoreSOGo.m - this file is part of SOGo * - * Copyright (C) 2010, 2011 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreSOGoObject.h b/OpenChange/MAPIStoreSOGoObject.h index cacdf23b1..411736718 100644 --- a/OpenChange/MAPIStoreSOGoObject.h +++ b/OpenChange/MAPIStoreSOGoObject.h @@ -1,6 +1,6 @@ /* MAPIStoreObject.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreSOGoObject.m b/OpenChange/MAPIStoreSOGoObject.m index f6d849857..008083192 100644 --- a/OpenChange/MAPIStoreSOGoObject.m +++ b/OpenChange/MAPIStoreSOGoObject.m @@ -1,6 +1,6 @@ /* MAPIStoreObject.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreSamDBUtils.h b/OpenChange/MAPIStoreSamDBUtils.h index c58a12686..25ee5e4eb 100644 --- a/OpenChange/MAPIStoreSamDBUtils.h +++ b/OpenChange/MAPIStoreSamDBUtils.h @@ -1,6 +1,6 @@ /* MAPIStoreSamDBUtils.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreSamDBUtils.m b/OpenChange/MAPIStoreSamDBUtils.m index 4d7caff63..e1f3fff44 100644 --- a/OpenChange/MAPIStoreSamDBUtils.m +++ b/OpenChange/MAPIStoreSamDBUtils.m @@ -1,6 +1,6 @@ /* MAPIStoreSamDBUtils.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTable.h b/OpenChange/MAPIStoreTable.h index 53bfbc50c..8c4b4718a 100644 --- a/OpenChange/MAPIStoreTable.h +++ b/OpenChange/MAPIStoreTable.h @@ -1,6 +1,6 @@ /* MAPIStoreTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTable.m b/OpenChange/MAPIStoreTable.m index 81a4e974e..04dcdf717 100644 --- a/OpenChange/MAPIStoreTable.m +++ b/OpenChange/MAPIStoreTable.m @@ -1,6 +1,6 @@ /* MAPIStoreTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTasksContext.h b/OpenChange/MAPIStoreTasksContext.h index b26b580cc..70d416130 100644 --- a/OpenChange/MAPIStoreTasksContext.h +++ b/OpenChange/MAPIStoreTasksContext.h @@ -1,6 +1,6 @@ /* MAPIStoreTasksContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTasksContext.m b/OpenChange/MAPIStoreTasksContext.m index 2726a2a62..096ca3711 100644 --- a/OpenChange/MAPIStoreTasksContext.m +++ b/OpenChange/MAPIStoreTasksContext.m @@ -1,6 +1,6 @@ /* MAPIStoreTasksContext.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTasksFolder.h b/OpenChange/MAPIStoreTasksFolder.h index 5f30c77b4..dc9b6791a 100644 --- a/OpenChange/MAPIStoreTasksFolder.h +++ b/OpenChange/MAPIStoreTasksFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreTasksFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTasksFolder.m b/OpenChange/MAPIStoreTasksFolder.m index bfc0698e8..7b8990fc8 100644 --- a/OpenChange/MAPIStoreTasksFolder.m +++ b/OpenChange/MAPIStoreTasksFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreTasksFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTasksMessage.h b/OpenChange/MAPIStoreTasksMessage.h index 273cde7cb..3130b72a5 100644 --- a/OpenChange/MAPIStoreTasksMessage.h +++ b/OpenChange/MAPIStoreTasksMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreTasksMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTasksMessage.m b/OpenChange/MAPIStoreTasksMessage.m index 08b580085..93d73cfd6 100644 --- a/OpenChange/MAPIStoreTasksMessage.m +++ b/OpenChange/MAPIStoreTasksMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreTasksMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * Ludovic Marcotte diff --git a/OpenChange/MAPIStoreTasksMessageTable.h b/OpenChange/MAPIStoreTasksMessageTable.h index 2180dd9ec..4be570027 100644 --- a/OpenChange/MAPIStoreTasksMessageTable.h +++ b/OpenChange/MAPIStoreTasksMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreTasksMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTasksMessageTable.m b/OpenChange/MAPIStoreTasksMessageTable.m index 9f6e5ad28..2948177b0 100644 --- a/OpenChange/MAPIStoreTasksMessageTable.m +++ b/OpenChange/MAPIStoreTasksMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreTasksMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTypes.h b/OpenChange/MAPIStoreTypes.h index 8e2fb7d46..a556bb26f 100644 --- a/OpenChange/MAPIStoreTypes.h +++ b/OpenChange/MAPIStoreTypes.h @@ -1,6 +1,6 @@ /* MAPIStoreTypes.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTypes.m b/OpenChange/MAPIStoreTypes.m index b13585e66..43fa048ee 100644 --- a/OpenChange/MAPIStoreTypes.m +++ b/OpenChange/MAPIStoreTypes.m @@ -1,6 +1,6 @@ /* MAPIStoreTypes.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSArray+MAPIStore.m b/OpenChange/NSArray+MAPIStore.m index 7a41245d4..9ed20130a 100644 --- a/OpenChange/NSArray+MAPIStore.m +++ b/OpenChange/NSArray+MAPIStore.m @@ -1,6 +1,6 @@ /* NSArray+MAPIStore.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSData+MAPIStore.m b/OpenChange/NSData+MAPIStore.m index b0143dc1b..3ad9afb52 100644 --- a/OpenChange/NSData+MAPIStore.m +++ b/OpenChange/NSData+MAPIStore.m @@ -1,6 +1,6 @@ /* NSData+MAPIStore.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSDate+MAPIStore.h b/OpenChange/NSDate+MAPIStore.h index 93f09be37..0e417d21f 100644 --- a/OpenChange/NSDate+MAPIStore.h +++ b/OpenChange/NSDate+MAPIStore.h @@ -1,6 +1,6 @@ /* NSDate+MAPIStore.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSDate+MAPIStore.m b/OpenChange/NSDate+MAPIStore.m index 06e55f1d7..b96812adf 100644 --- a/OpenChange/NSDate+MAPIStore.m +++ b/OpenChange/NSDate+MAPIStore.m @@ -1,6 +1,6 @@ /* NSDate+MAPIStore.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSObject+MAPIStore.h b/OpenChange/NSObject+MAPIStore.h index 8e992f958..ff5bed57d 100644 --- a/OpenChange/NSObject+MAPIStore.h +++ b/OpenChange/NSObject+MAPIStore.h @@ -1,6 +1,6 @@ /* NSObject+MAPIStore.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSObject+MAPIStore.m b/OpenChange/NSObject+MAPIStore.m index 7eb14a768..1829b59f3 100644 --- a/OpenChange/NSObject+MAPIStore.m +++ b/OpenChange/NSObject+MAPIStore.m @@ -1,6 +1,6 @@ /* NSObject+MAPIStore.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSObject+PropertyList.m b/OpenChange/NSObject+PropertyList.m index 9f9762508..37861ed0f 100644 --- a/OpenChange/NSObject+PropertyList.m +++ b/OpenChange/NSObject+PropertyList.m @@ -1,6 +1,6 @@ /* dbmsgdump.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSString+MAPIStore.h b/OpenChange/NSString+MAPIStore.h index 26addcbdf..6db35543c 100644 --- a/OpenChange/NSString+MAPIStore.h +++ b/OpenChange/NSString+MAPIStore.h @@ -1,6 +1,6 @@ /* NSString+MAPIStore.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSString+MAPIStore.m b/OpenChange/NSString+MAPIStore.m index a4a894b6a..186c30e46 100644 --- a/OpenChange/NSString+MAPIStore.m +++ b/OpenChange/NSString+MAPIStore.m @@ -1,6 +1,6 @@ /* NSString+MAPIStore.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSValue+MAPIStore.h b/OpenChange/NSValue+MAPIStore.h index 6352b9a4c..da0b2aa41 100644 --- a/OpenChange/NSValue+MAPIStore.h +++ b/OpenChange/NSValue+MAPIStore.h @@ -1,6 +1,6 @@ /* NSValue+MAPIStore.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSValue+MAPIStore.m b/OpenChange/NSValue+MAPIStore.m index 83d583e33..a3301ce00 100644 --- a/OpenChange/NSValue+MAPIStore.m +++ b/OpenChange/NSValue+MAPIStore.m @@ -1,6 +1,6 @@ /* NSValue+MAPIStore.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/code-MAPIStorePropertySelectors.h b/OpenChange/code-MAPIStorePropertySelectors.h index cceb2b751..f338ebe62 100644 --- a/OpenChange/code-MAPIStorePropertySelectors.h +++ b/OpenChange/code-MAPIStorePropertySelectors.h @@ -1,6 +1,6 @@ /* code-MAPIStorePropertySelectors.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/code-MAPIStorePropertySelectors.m b/OpenChange/code-MAPIStorePropertySelectors.m index aae4f0489..86ac76f20 100644 --- a/OpenChange/code-MAPIStorePropertySelectors.m +++ b/OpenChange/code-MAPIStorePropertySelectors.m @@ -1,6 +1,6 @@ /* code-MAPIStorePropertySelectors.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/dbmsgreader.m b/OpenChange/dbmsgreader.m index b4b4332b3..0119a00c9 100644 --- a/OpenChange/dbmsgreader.m +++ b/OpenChange/dbmsgreader.m @@ -1,6 +1,6 @@ /* dbmsgreader.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/plreader.m b/OpenChange/plreader.m index b027a987c..f6ee15672 100644 --- a/OpenChange/plreader.m +++ b/OpenChange/plreader.m @@ -1,6 +1,6 @@ /* plreader.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * From 4f3934dc0eb718941cf617cb32b73b2473c352d5 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 17 Aug 2012 20:12:50 +0000 Subject: [PATCH 111/127] Monotone-Parent: 105b571703ff5c4cc1024854ef8a1d987aef2bf1 Monotone-Revision: deb19e29a470db5c60606444f9e82eb9aa85ce1d Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-17T20:12:50 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 8 ++++++++ OpenChange/MAPIStoreAppointmentWrapper.m | 6 ++++++ OpenChange/MAPIStoreCalendarMessage.m | 8 +++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 0750a45db..669f2a1d5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2012-08-17 Wolfgang Sourdeau + * OpenChange/MAPIStoreCalendarMessage.m + (-getPidTagMessageClass:inMemCtx:): return + "IPM.Schedule.Meeting.Request" when the owner user is an attendee. + + * OpenChange/MAPIStoreAppointmentWrapper.m + (-getPidLidAppointmentNotAllowPropose:inMemCtx): new getter that + always return "YES", in order to disallow counter proposals. + * OpenChange/MAPIStoreContext.m (-getPath:ofFMID:inMemCtx:): properly escape urls containing non-ascii chars. (-getRootFoldeR:withFID:): idem. diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index 07673012c..8e8e308d8 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -709,6 +709,12 @@ static NSCharacterSet *hexCharacterSet = nil; return MAPISTORE_SUCCESS; } + +- (int) getPidLidAppointmentNotAllowPropose: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getYes: data inMemCtx: memCtx]; +} - (int) getPidLidAppointmentStartWhole: (void **) data inMemCtx: (TALLOC_CTX *) memCtx diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index 6d65d2313..afdbb98b0 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -210,7 +210,13 @@ static Class NSArrayK; - (int) getPidTagMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = talloc_strdup (memCtx, "IPM.Appointment"); + SOGoUser *owner; + + owner = [[self userContext] sogoUser]; + if ([masterEvent userAsAttendee: owner]) + *data = talloc_strdup (memCtx, "IPM.Schedule.Meeting.Request"); + else + *data = talloc_strdup (memCtx, "IPM.Appointment"); return MAPISTORE_SUCCESS; } From f736efef62640c9b6d68bdf7583abef2243943db Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 17 Aug 2012 20:12:58 +0000 Subject: [PATCH 112/127] Monotone-Parent: deb19e29a470db5c60606444f9e82eb9aa85ce1d Monotone-Revision: 8353df7f94c6dafc3acc66e6a0b43ee47a209757 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-17T20:12:58 Monotone-Branch: ca.inverse.sogo --- OpenChange/gen-property-selectors.py | 44 ++-------------------------- 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/OpenChange/gen-property-selectors.py b/OpenChange/gen-property-selectors.py index 8c728bb99..f009d6864 100755 --- a/OpenChange/gen-property-selectors.py +++ b/OpenChange/gen-property-selectors.py @@ -7,27 +7,7 @@ output = "-" import os import sys -m_template = """/* %(filename)s (auto-generated) - this file is part of SOGo - * - * Copyright (C) 2011 Inverse inc. - * - * Author: Wolfgang Sourdeau - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ +m_template = """/* %(filename)s (auto-generated) */ #include #include @@ -53,27 +33,7 @@ static const SEL MAPIStorePropertyGetterSelectors[] = { #include "code-%(filename)s" """ -h_template = """/* %(filename)s (auto-generated) - this file is part of SOGo - * - * Copyright (C) 2011 Inverse inc. - * - * Author: Wolfgang Sourdeau - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ +h_template = """/* %(filename)s (auto-generated) */ #ifndef %(h_exclusion)s #define %(h_exclusion)s 1 From ef2ce2434f7b68ae2e004c3d7fd2f6500d6ff95e Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 21 Aug 2012 17:41:24 +0000 Subject: [PATCH 113/127] Monotone-Parent: 8353df7f94c6dafc3acc66e6a0b43ee47a209757 Monotone-Revision: 321dcc0c57ee3b7c5ea6cebb040566be569bacb3 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-21T17:41:24 Monotone-Branch: ca.inverse.sogo --- OpenChange/unrtf-0.21.2.diff | 556 +++++++++++++++++++++++++++++------ 1 file changed, 473 insertions(+), 83 deletions(-) diff --git a/OpenChange/unrtf-0.21.2.diff b/OpenChange/unrtf-0.21.2.diff index 466c2d16a..339480ac4 100644 --- a/OpenChange/unrtf-0.21.2.diff +++ b/OpenChange/unrtf-0.21.2.diff @@ -1,6 +1,6 @@ diff -durpN unrtf-0.21.2.old/outputs/html.conf unrtf-0.21.2/outputs/html.conf --- unrtf-0.21.2.old/outputs/html.conf 2010-08-15 08:44:09.000000000 -0400 -+++ unrtf-0.21.2/outputs/html.conf 2012-03-13 16:38:53.295941363 -0400 ++++ unrtf-0.21.2/outputs/html.conf 2012-08-21 13:33:44.761682724 -0400 @@ -5,7 +5,7 @@ comment_end --> @@ -21,7 +21,7 @@ diff -durpN unrtf-0.21.2.old/outputs/html.conf unrtf-0.21.2/outputs/html.conf diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c --- unrtf-0.21.2.old/src/attr.c 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/attr.c 2012-03-13 16:38:41.323940752 -0400 ++++ unrtf-0.21.2/src/attr.c 2012-08-21 13:38:56.717688715 -0400 @@ -1,23 +1,23 @@ /*============================================================================= - GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -504,7 +504,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + ++stack->tos; + stack->attr_stack[stack->tos] = attr; + if (param) -+ stack->attr_stack_params[stack->tos] = my_strdup(oc->conversion, param); ++ stack->attr_stack_params[stack->tos] = unrtf_strdup(oc->conversion, param); + else + stack->attr_stack_params[stack->tos] = NULL; @@ -641,7 +641,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + AttrStack *new_stack; - prev_stack = stack_of_stacks_top; -+ new_stack = (AttrStack*) my_malloc (sizeof (AttrStack)); ++ new_stack = (AttrStack*) unrtf_malloc (sizeof (AttrStack)); + memset ((void*) new_stack, 0, sizeof (AttrStack)); + new_stack->tos = -1; @@ -691,7 +691,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + attr_express_end (attr, param, oc); - if (param) my_free(param); -+ if (param) my_free(param); ++ if (param) unrtf_free(param); + stack->attr_stack_params[stack->tos] = NULL; - stack->tos--; @@ -769,7 +769,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + while (stack->tos>=0) + { + char *param=stack->attr_stack_params[stack->tos]; -+ if (param) my_free(param); ++ if (param) unrtf_free(param); + stack->attr_stack_params[stack->tos] = NULL; + stack->tos--; + } @@ -826,7 +826,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + } + } + -+ my_free ((void*) stack); ++ unrtf_free ((void*) stack); } /*======================================================================== @@ -859,7 +859,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + int attr=stack->attr_stack[stack->tos]; + char *param=stack->attr_stack_params[stack->tos]; + attr_express_end (attr,param, oc); -+ if (param) my_free(param); ++ if (param) unrtf_free(param); + stack->attr_stack_params[stack->tos] = NULL; + stack->tos--; + } @@ -1102,7 +1102,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + if (string == NULL) + return NULL; + else { -+ s = my_malloc(strlen(string) + 1 + 12/* Number of characters that can be in int type (including '\0') - AF */); ++ s = unrtf_malloc(strlen(string) + 1 + 12/* Number of characters that can be in int type (including '\0') - AF */); + while(string[i] != '\0' && (string[i] != '%' || (string[i] == '%' && (i != 0 && string[i-1] == '\\')))) { + if (string[i] != '\\' || string[i+1] != '%') { + s[j] = string[i]; @@ -1183,7 +1183,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c - c->text = text; + if (col == NULL) + { -+ col = (Collection *)my_malloc(sizeof(Collection)); ++ col = (Collection *)unrtf_malloc(sizeof(Collection)); + col->nr = nr; + col->text = strdup(text); + col->next = NULL; @@ -1195,7 +1195,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + if (c->nr == nr) + { + /* Here is a memory leak but not heavy. Do we need to care about this? -+ my_free(a->alias.text); ++ unrtf_free(a->alias.text); + */ + c->text = strdup(text); @@ -1214,7 +1214,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c - c->next->text = text; - c->next->next = NULL; - } -+ c->next = (Collection *)my_malloc(sizeof(Collection)); ++ c->next = (Collection *)unrtf_malloc(sizeof(Collection)); + c->next->nr = nr; + c->next->text = strdup(text); + c->next->next = NULL; @@ -1265,16 +1265,16 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + { + c2 = c->next; + if (c->text) { -+ my_free((void *)c->text); ++ unrtf_free((void *)c->text); + } -+ my_free((void *)c); ++ unrtf_free((void *)c); + c = c2; + } } - diff -durpN unrtf-0.21.2.old/src/attr.h unrtf-0.21.2/src/attr.h --- unrtf-0.21.2.old/src/attr.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/attr.h 2012-03-13 16:38:41.323940752 -0400 ++++ unrtf-0.21.2/src/attr.h 2012-08-21 13:33:44.785682699 -0400 @@ -1,23 +1,23 @@ /*============================================================================= - GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -1424,7 +1424,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.h unrtf-0.21.2/src/attr.h +#endif /* ATTR_H */ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c --- unrtf-0.21.2.old/src/convert.c 2011-06-07 08:00:23.000000000 -0400 -+++ unrtf-0.21.2/src/convert.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/convert.c 2012-08-21 13:38:56.721688436 -0400 @@ -1,24 +1,24 @@ /*=========================================================================== @@ -2697,7 +2697,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c - w=w->next; - } + oc->conversion->font_table[oc->conversion->total_fonts].num=num; -+ oc->conversion->font_table[oc->conversion->total_fonts].name=my_strdup(oc->conversion, name); ++ oc->conversion->font_table[oc->conversion->total_fonts].name=unrtf_strdup(oc->conversion, name); + if (safe_printf(device, 0, assemble_string(oc->personality->fonttable_fontnr, num))) fprintf(stderr, TOO_MANY_ARGS, "fonttable_fontnr"); + if (safe_printf(device, 1, oc->personality->fonttable_fontname, name)) fprintf(stderr, TOO_MANY_ARGS, "fonttable_fontname"); + oc->conversion->total_fonts++; @@ -2747,7 +2747,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c + + for (i = 0; i < cc->total_fonts; i++) { + if (cc->font_table[i].name) { -+ my_free(cc->font_table[i].name); ++ unrtf_free(cc->font_table[i].name); + cc->font_table[i].name = NULL; + } + } @@ -3596,7 +3596,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c + } else { + if (oc->personality->fonttable_begin != NULL) + { -+ name = my_malloc(12); ++ name = unrtf_malloc(12); + sprintf(name, "%d", num); + } #if 1 /* daved 0.21.1 */ @@ -6503,7 +6503,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c - *doublet = (int)ch; - *(doublet+1) = (int)ch2; - *(doublet+2) = 0; -+ doublet = (int *)my_malloc(12); ++ doublet = (int *)unrtf_malloc(12); + *doublet = (int)ch; + *(doublet+1) = (int)ch2; + *(doublet+2) = 0; @@ -7058,7 +7058,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c + + hash_free(&cc); + if (cc.input_str) -+ my_free(cc.input_str); ++ unrtf_free(cc.input_str); + word_free(word); + fonttable_free(oc.conversion); + if (my_iconv_is_valid(oc.conversion->desc)) @@ -7120,7 +7120,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c } diff -durpN unrtf-0.21.2.old/src/convert.h unrtf-0.21.2/src/convert.h --- unrtf-0.21.2.old/src/convert.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/convert.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/convert.h 2012-08-21 13:33:44.793682720 -0400 @@ -36,18 +36,135 @@ #ifndef _CONVERT @@ -7264,7 +7264,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.h unrtf-0.21.2/src/convert.h diff -durpN unrtf-0.21.2.old/src/defs.h unrtf-0.21.2/src/defs.h --- unrtf-0.21.2.old/src/defs.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/defs.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/defs.h 2012-08-21 13:33:44.817682703 -0400 @@ -64,9 +64,6 @@ #define SKIP_ONE_WORD 2 #endif @@ -7284,7 +7284,7 @@ diff -durpN unrtf-0.21.2.old/src/defs.h unrtf-0.21.2/src/defs.h +#define DEFAULT_OUTPUT "html" diff -durpN unrtf-0.21.2.old/src/error.c unrtf-0.21.2/src/error.c --- unrtf-0.21.2.old/src/error.c 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/error.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/error.c 2012-08-21 13:38:56.729687967 -0400 @@ -51,27 +51,11 @@ #include #endif @@ -7329,7 +7329,7 @@ diff -durpN unrtf-0.21.2.old/src/error.c unrtf-0.21.2/src/error.c #endif diff -durpN unrtf-0.21.2.old/src/error.h unrtf-0.21.2/src/error.h --- unrtf-0.21.2.old/src/error.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/error.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/error.h 2012-08-21 13:33:44.817682703 -0400 @@ -37,9 +37,10 @@ #define CHECK_MALLOC_SUCCESS(XX) { if ((XX)==NULL) { fprintf (stderr, "internal error: cannot allocate memory in %s at %d\n", __FILE__, __LINE__); exit (1); }} @@ -7344,7 +7344,7 @@ diff -durpN unrtf-0.21.2.old/src/error.h unrtf-0.21.2/src/error.h diff -durpN unrtf-0.21.2.old/src/hash.c unrtf-0.21.2/src/hash.c --- unrtf-0.21.2.old/src/hash.c 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/hash.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/hash.c 2012-08-21 13:38:56.733687861 -0400 @@ -53,24 +53,16 @@ #include #endif @@ -7442,12 +7442,12 @@ diff -durpN unrtf-0.21.2.old/src/hash.c unrtf-0.21.2/src/hash.c - i <<= 24; - hi->value = i | (hash_value++ & 0xffffff); - hi->next = NULL; -+ hi=(HashItem*) my_malloc(sizeof(HashItem)); ++ hi=(HashItem*) unrtf_malloc(sizeof(HashItem)); + if (!hi) + error_handler(cc, "Out of memory"); + memset ((void*)hi, 0, sizeof (HashItem)); + -+ hi->str = my_strdup(cc, str); ++ hi->str = unrtf_strdup(cc, str); + + i = *str; + if (i=='\\') i=str[1]; @@ -7529,7 +7529,7 @@ diff -durpN unrtf-0.21.2.old/src/hash.c unrtf-0.21.2/src/hash.c +{ + HashItem *next = item->next; + -+ my_free (item->str); ++ unrtf_free (item->str); + free (item); + if (next) + hashitem_free(next); @@ -7549,7 +7549,7 @@ diff -durpN unrtf-0.21.2.old/src/hash.c unrtf-0.21.2/src/hash.c +} diff -durpN unrtf-0.21.2.old/src/hash.h unrtf-0.21.2/src/hash.h --- unrtf-0.21.2.old/src/hash.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/hash.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/hash.h 2012-08-21 13:33:44.817682703 -0400 @@ -32,11 +32,15 @@ * 16 Dec 07, daved@physiol.usyd.edu.au: updated to GPL v3 *--------------------------------------------------------------------*/ @@ -7573,7 +7573,7 @@ diff -durpN unrtf-0.21.2.old/src/hash.h unrtf-0.21.2/src/hash.h +#endif /* HASH_H */ diff -durpN unrtf-0.21.2.old/src/main.c unrtf-0.21.2/src/main.c --- unrtf-0.21.2.old/src/main.c 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/main.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/main.c 2012-08-21 13:38:56.737687716 -0400 @@ -1,23 +1,23 @@ /*============================================================================= - GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -7995,7 +7995,7 @@ diff -durpN unrtf-0.21.2.old/src/main.c unrtf-0.21.2/src/main.c - diff -durpN unrtf-0.21.2.old/src/main.h unrtf-0.21.2/src/main.h --- unrtf-0.21.2.old/src/main.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/main.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/main.h 2012-08-21 13:33:44.821682709 -0400 @@ -35,21 +35,8 @@ * 17 Jan 10, daved@physiol.usyd.edu.au: change CONFIG_DIR to drop outputs/ *--------------------------------------------------------------------*/ @@ -8021,7 +8021,7 @@ diff -durpN unrtf-0.21.2.old/src/main.h unrtf-0.21.2/src/main.h +#define USAGE "unrtf [--version] [--verbose] [--help] [--nopict|-n] [--noremap] [--html] [--text] [--vt] [--latex] [--rtf] [-P config_search_path] [-t )] " diff -durpN unrtf-0.21.2.old/src/Makefile.am unrtf-0.21.2/src/Makefile.am --- unrtf-0.21.2.old/src/Makefile.am 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/Makefile.am 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/Makefile.am 2012-08-21 13:33:44.821682709 -0400 @@ -13,7 +13,6 @@ unrtf_SOURCES = attr.c attr.h \ malloc.c malloc.h \ output.c output.h \ @@ -8032,15 +8032,100 @@ diff -durpN unrtf-0.21.2.old/src/Makefile.am unrtf-0.21.2/src/Makefile.am util.c util.h \ diff -durpN unrtf-0.21.2.old/src/malloc.c unrtf-0.21.2/src/malloc.c --- unrtf-0.21.2.old/src/malloc.c 2010-07-09 01:13:05.000000000 -0400 -+++ unrtf-0.21.2/src/malloc.c 2012-03-13 16:38:41.327940973 -0400 -@@ -135,19 +135,19 @@ total_malloced (void) { ++++ unrtf-0.21.2/src/malloc.c 2012-08-21 13:39:15.329687813 -0400 +@@ -28,6 +28,8 @@ + * much memory is being used. + *---------------------------------------------------------------------- + * Changes: ++ * 21 Aug 12, wsourdeau@inverse.ca: renamed "my_*" to "unrtf_*", to ++ * avoid symbol classes with other libraries + * 14 Aug 01, tuorfa@yahoo.com: added Turbo C support. + * 16 Aug 01, Lars Unger : added Amiga/GCC support. + * 22 Sep 01, tuorfa@yahoo.com: added function-level comment blocks +@@ -35,7 +37,7 @@ + * 08 Oct 03, daved@physiol.usyd.edu.au: added stdlib.h for linux + * 29 Mar 05, daved@physiol.usyd.edu.au: changes requested by ZT Smith + * 16 Dec 07, daved@physiol.usyd.edu.au: updated to GPL v3 +- * 09 Nov 08, arkadiusz.firus@gmail.com: added my_realloc ++ * 09 Nov 08, arkadiusz.firus@gmail.com: added unrtf_realloc + *--------------------------------------------------------------------*/ + + #ifdef HAVE_CONFIG_H +@@ -60,14 +62,14 @@ + static unsigned long count=0; + + /*======================================================================== +- * Name: my_malloc ++ * Name: unrtf_malloc + * Purpose: Internal version of malloc necessary for record keeping. + * Args: Amount. + * Returns: Pointer. + *=======================================================================*/ + + char * +-my_malloc (unsigned long size) { ++unrtf_malloc (unsigned long size) { + char *ptr; + + ptr = malloc (size); +@@ -78,14 +80,14 @@ my_malloc (unsigned long size) { + } + + /*======================================================================== +- * Name: my_free ++ * Name: unrtf_free + * Purpose: Internal version of free necessary for record keeping. + * Args: Pointer. + * Returns: None. + *=======================================================================*/ + + void +-my_free (char* ptr) { ++unrtf_free (char* ptr) { + CHECK_PARAM_NOT_NULL(ptr); + + free (ptr); +@@ -93,20 +95,20 @@ my_free (char* ptr) { + + #if 1 /* AK3 - AF */ + /*======================================================================== +- * Name: my_realloc ++ * Name: unrtf_realloc + * Purpose: Internal version of realloc necessary for record keeping. + * Args: Pointer. + * Returns: None. + *=======================================================================*/ + char * +-my_realloc(char *ptr, unsigned long old_size, unsigned long new_size) ++unrtf_realloc(char *ptr, unsigned long old_size, unsigned long new_size) + { +- char *new_ptr = my_malloc(new_size); ++ char *new_ptr = unrtf_malloc(new_size); + + if (new_ptr != NULL) + memcpy(new_ptr, ptr, old_size); + +- my_free(ptr); ++ unrtf_free(ptr); + + return new_ptr; + } +@@ -128,26 +130,26 @@ total_malloced (void) { + + + /*======================================================================== +- * Name: my_strdup ++ * Name: unrtf_strdup + * Purpose: Internal version of strdup necessary for record keeping. + * Args: String. + * Returns: String. *=======================================================================*/ char * -my_strdup (char *src) { - unsigned long len; - char *ptr; -+my_strdup (struct ConversionContext *cc, char *src) { ++unrtf_strdup (struct ConversionContext *cc, char *src) { + unsigned long len; + char *ptr; @@ -8052,7 +8137,7 @@ diff -durpN unrtf-0.21.2.old/src/malloc.c unrtf-0.21.2/src/malloc.c - if (!ptr) - error_handler ("out of memory in strdup()"); + len = strlen(src); -+ ptr = my_malloc (len+1); ++ ptr = unrtf_malloc (len+1); + if (!ptr) + error_handler (cc, "out of memory in strdup()"); @@ -8063,32 +8148,253 @@ diff -durpN unrtf-0.21.2.old/src/malloc.c unrtf-0.21.2/src/malloc.c } /* added by daved */ #include -@@ -163,5 +163,5 @@ rpl_malloc (size_t n) +@@ -163,5 +165,5 @@ rpl_malloc (size_t n) { if (n == 0) n = 1; -return malloc (n); + return malloc (n); } +diff -durpN unrtf-0.21.2.old/src/malloc.c~ unrtf-0.21.2/src/malloc.c~ +--- unrtf-0.21.2.old/src/malloc.c~ 1969-12-31 19:00:00.000000000 -0500 ++++ unrtf-0.21.2/src/malloc.c~ 2012-08-21 13:38:56.745687548 -0400 +@@ -0,0 +1,169 @@ ++/*============================================================================= ++ GNU UnRTF, a command-line program to convert RTF documents to other formats. ++ Copyright (C) 2000,2001,2004 by Zachary Smith ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ ++ The maintainer is reachable by electronic mail at daved@physiol.usyd.edu.au ++=============================================================================*/ ++ ++ ++/*---------------------------------------------------------------------- ++ * Module name: malloc ++ * Author name: Zachary Smith ++ * Create date: 01 Aug 01 ++ * Purpose: Memory management. Allows us to keep track of how ++ * much memory is being used. ++ *---------------------------------------------------------------------- ++ * Changes: ++ * 21 Aug 12, wsourdeau@inverse.ca: rename "my_malloc" to "unrtf_malloc", to ++ * avoid symbol classes with other libraries ++ * 14 Aug 01, tuorfa@yahoo.com: added Turbo C support. ++ * 16 Aug 01, Lars Unger : added Amiga/GCC support. ++ * 22 Sep 01, tuorfa@yahoo.com: added function-level comment blocks ++ * 28 Sep 01, tuorfa@yahoo.com: removed Turbo C support. ++ * 08 Oct 03, daved@physiol.usyd.edu.au: added stdlib.h for linux ++ * 29 Mar 05, daved@physiol.usyd.edu.au: changes requested by ZT Smith ++ * 16 Dec 07, daved@physiol.usyd.edu.au: updated to GPL v3 ++ * 09 Nov 08, arkadiusz.firus@gmail.com: added unrtf_realloc ++ *--------------------------------------------------------------------*/ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#ifdef HAVE_STDIO_H ++#include ++#endif ++ ++#ifdef HAVE_STDLIB_H ++#include ++#endif ++ ++#ifdef HAVE_STRING_H ++#include ++#endif ++ ++#include "error.h" ++#include "malloc.h" ++ ++static unsigned long count=0; ++ ++/*======================================================================== ++ * Name: unrtf_malloc ++ * Purpose: Internal version of malloc necessary for record keeping. ++ * Args: Amount. ++ * Returns: Pointer. ++ *=======================================================================*/ ++ ++char * ++unrtf_malloc (unsigned long size) { ++ char *ptr; ++ ++ ptr = malloc (size); ++ if (ptr) ++ count += size; ++ ++ return ptr; ++} ++ ++/*======================================================================== ++ * Name: unrtf_free ++ * Purpose: Internal version of free necessary for record keeping. ++ * Args: Pointer. ++ * Returns: None. ++ *=======================================================================*/ ++ ++void ++unrtf_free (char* ptr) { ++ CHECK_PARAM_NOT_NULL(ptr); ++ ++ free (ptr); ++} ++ ++#if 1 /* AK3 - AF */ ++/*======================================================================== ++ * Name: unrtf_realloc ++ * Purpose: Internal version of realloc necessary for record keeping. ++ * Args: Pointer. ++ * Returns: None. ++ *=======================================================================*/ ++char * ++unrtf_realloc(char *ptr, unsigned long old_size, unsigned long new_size) ++{ ++ char *new_ptr = unrtf_malloc(new_size); ++ ++ if (new_ptr != NULL) ++ memcpy(new_ptr, ptr, old_size); ++ ++ unrtf_free(ptr); ++ ++ return new_ptr; ++} ++#endif ++ ++/*======================================================================== ++ * Name: total_malloced ++ * Purpose: Returns total amount of memory thus far allocated. Called at ++ * the end of main() when in debug mode. ++ * Args: None. ++ * Returns: Amount. ++ *=======================================================================*/ ++ ++unsigned long ++total_malloced (void) { ++ return count; ++} ++ ++ ++ ++/*======================================================================== ++ * Name: unrtf_strdup ++ * Purpose: Internal version of strdup necessary for record keeping. ++ * Args: String. ++ * Returns: String. ++ *=======================================================================*/ ++ ++char * ++unrtf_strdup (struct ConversionContext *cc, char *src) { ++ unsigned long len; ++ char *ptr; ++ ++ CHECK_PARAM_NOT_NULL(src); ++ ++ len = strlen(src); ++ ptr = unrtf_malloc (len+1); ++ if (!ptr) ++ error_handler (cc, "out of memory in strdup()"); ++ ++ sprintf (ptr, "%s", src); ++ return ptr; ++} ++/* added by daved */ ++#include ++#undef malloc ++ ++void *malloc (); ++ ++/* Allocate an N-byte block of memory from the heap. ++If N is zero, allocate a 1-byte block. */ ++ ++void * ++rpl_malloc (size_t n) ++{ ++ if (n == 0) ++ n = 1; ++ return malloc (n); ++} diff -durpN unrtf-0.21.2.old/src/malloc.h unrtf-0.21.2/src/malloc.h --- unrtf-0.21.2.old/src/malloc.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/malloc.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/malloc.h 2012-08-21 13:38:32.385687262 -0400 @@ -32,9 +32,10 @@ * 09 Nov 08, arkadiusz.firus@gmail.com: added my_realloc *--------------------------------------------------------------------*/ +-extern char * my_malloc (unsigned long); +-extern void my_free (char*); +-extern char * my_realloc(char*, unsigned long, unsigned long); +-extern unsigned long total_malloced (void); +-extern char * my_strdup (char*); ++struct ConversionContext; + ++extern char * unrtf_malloc (unsigned long); ++extern void unrtf_free (char*); ++extern char * unrtf_realloc(char*, unsigned long, unsigned long); ++extern unsigned long total_malloced (void); ++extern char * unrtf_strdup (struct ConversionContext *, char*); +diff -durpN unrtf-0.21.2.old/src/malloc.h~ unrtf-0.21.2/src/malloc.h~ +--- unrtf-0.21.2.old/src/malloc.h~ 1969-12-31 19:00:00.000000000 -0500 ++++ unrtf-0.21.2/src/malloc.h~ 2012-08-21 13:33:44.825682713 -0400 +@@ -0,0 +1,41 @@ ++/*============================================================================= ++ GNU UnRTF, a command-line program to convert RTF documents to other formats. ++ Copyright (C) 2000,2001,2004 by Zachary Smith ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ ++ The maintainer is reachable by electronic mail at daved@physiol.usyd.edu.au ++=============================================================================*/ ++ ++ ++/*---------------------------------------------------------------------- ++ * Module name: malloc ++ * Author name: Zachary Smith ++ * Create date: 1 Aug 2001 ++ * Purpose: Definitions for memory management. ++ *---------------------------------------------------------------------- ++ * Changes: ++ * 29 Mar 05, daved@physiol.usyd.edu.au: changes requested by ZT Smith ++ * 16 Dec 07, daved@physiol.usyd.edu.au: updated to GPL v3 ++ * 09 Nov 08, arkadiusz.firus@gmail.com: added my_realloc ++ *--------------------------------------------------------------------*/ ++ +struct ConversionContext; + - extern char * my_malloc (unsigned long); - extern void my_free (char*); - extern char * my_realloc(char*, unsigned long, unsigned long); - extern unsigned long total_malloced (void); --extern char * my_strdup (char*); -- ++extern char * my_malloc (unsigned long); ++extern void my_free (char*); ++extern char * my_realloc(char*, unsigned long, unsigned long); ++extern unsigned long total_malloced (void); +extern char * my_strdup (struct ConversionContext *, char*); diff -durpN unrtf-0.21.2.old/src/my_iconv.c unrtf-0.21.2/src/my_iconv.c --- unrtf-0.21.2.old/src/my_iconv.c 2010-08-16 00:12:43.000000000 -0400 -+++ unrtf-0.21.2/src/my_iconv.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/my_iconv.c 2012-08-21 13:38:56.753687604 -0400 @@ -12,154 +12,133 @@ #include #include @@ -8157,7 +8463,7 @@ diff -durpN unrtf-0.21.2.old/src/my_iconv.c unrtf-0.21.2/src/my_iconv.c -#endif + if ((cd.desc = iconv_open(tocode, fromcode)) == (iconv_t) -1) + { -+ path = my_malloc((strlen(cc->options->config_directory) + strlen(fromcode) + 10) * sizeof(char)); ++ path = unrtf_malloc((strlen(cc->options->config_directory) + strlen(fromcode) + 10) * sizeof(char)); + sprintf (path, "%s/%s.charmap", cc->options->config_directory, fromcode); - if (f != NULL) @@ -8176,7 +8482,7 @@ diff -durpN unrtf-0.21.2.old/src/my_iconv.c unrtf-0.21.2/src/my_iconv.c - } + if (f != NULL) + { -+ cd.char_table = (char **)my_malloc(char_table_size * sizeof(char *)); ++ cd.char_table = (char **)unrtf_malloc(char_table_size * sizeof(char *)); + c = fgetc(f); - fclose(f); @@ -8195,7 +8501,7 @@ diff -durpN unrtf-0.21.2.old/src/my_iconv.c unrtf-0.21.2/src/my_iconv.c + } - return cd; -+ my_free(path); ++ unrtf_free(path); + } + + return cd; @@ -8282,13 +8588,13 @@ diff -durpN unrtf-0.21.2.old/src/my_iconv.c unrtf-0.21.2/src/my_iconv.c + { + for (i = 0; i < char_table_size; i++) + { -+ my_free(cd.char_table[i]); ++ unrtf_free(cd.char_table[i]); + } - my_free((void *)cd.char_table); - cd.char_table = NULL; - } -+ my_free((void *)cd.char_table); ++ unrtf_free((void *)cd.char_table); + cd.char_table = NULL; + } @@ -8330,7 +8636,7 @@ diff -durpN unrtf-0.21.2.old/src/my_iconv.c unrtf-0.21.2/src/my_iconv.c diff -durpN unrtf-0.21.2.old/src/my_iconv.h unrtf-0.21.2/src/my_iconv.h --- unrtf-0.21.2.old/src/my_iconv.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/my_iconv.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/my_iconv.h 2012-08-21 13:33:44.825682713 -0400 @@ -5,6 +5,9 @@ * Purpose: my_conv definitions *--------------------------------------------------------------------*/ @@ -8360,7 +8666,7 @@ diff -durpN unrtf-0.21.2.old/src/my_iconv.h unrtf-0.21.2/src/my_iconv.h +#endif /* _MY_ICONV */ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c --- unrtf-0.21.2.old/src/output.c 2011-06-07 08:04:38.000000000 -0400 -+++ unrtf-0.21.2/src/output.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/output.c 2012-08-21 13:38:56.753687604 -0400 @@ -1,23 +1,23 @@ /*============================================================================= - GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -8432,7 +8738,7 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c - new_op = (OutputPersonality*) my_malloc (sizeof(OutputPersonality)); - if (!new_op) - error_handler ("cannot allocate output personality"); -+ new_op = (OutputPersonality*) my_malloc (sizeof(OutputPersonality)); ++ new_op = (OutputPersonality*) unrtf_malloc (sizeof(OutputPersonality)); + if (!new_op) + error_handler (cc, "cannot allocate output personality"); @@ -8458,7 +8764,7 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c + if (op->aliases) + free_collection(op->aliases); -+ my_free ((void*) op); ++ unrtf_free ((void*) op); +} /*======================================================================== @@ -8502,8 +8808,8 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c + else + if (result == NULL) + { -+ originbuf = inbuf = my_malloc(inbytes + 1); -+ origoutbuf = outbuf = my_malloc(outbytes + 1); ++ originbuf = inbuf = unrtf_malloc(inbytes + 1); ++ origoutbuf = outbuf = unrtf_malloc(outbytes + 1); - for (i = inbytes - 1; ch > 255; i--) - { @@ -8712,12 +9018,12 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c - *(inbuf+2) = 0; - fprintf(stderr, "inbuf = %o %o\n", *inbuf, *(inbuf+1)); - outbuf = my_malloc(outbytes + 1); -+ inbuf = (char *) my_malloc(inbytes + 1); ++ inbuf = (char *) unrtf_malloc(inbytes + 1); + *inbuf = *doublet; + *(inbuf+1) = (unsigned char *) *(doublet+1); + *(inbuf+2) = 0; + fprintf(stderr, "inbuf = %o %o\n", *inbuf, *(inbuf+1)); -+ outbuf = my_malloc(outbytes + 1); ++ outbuf = unrtf_malloc(outbytes + 1); #if 0 @@ -8925,7 +9231,7 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c + else + if (result == NULL) + { -+ inbuf = (char *) my_malloc(inbytes + 1); ++ inbuf = (char *) unrtf_malloc(inbytes + 1); + *inbuf = ch1; + *(inbuf+1) = ch2; + *(inbuf+2) = 0; @@ -8934,7 +9240,7 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c + fprintf(stderr, "inbuf = %o %o\n", *inbuf, *(inbuf+1)); #endif - outbuf = my_malloc(outbytes + 1); -+ outbuf = my_malloc(outbytes + 1); ++ outbuf = unrtf_malloc(outbytes + 1); - i = outbytes; - if (!my_iconv_is_valid(cd)) @@ -9544,7 +9850,7 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c - diff -durpN unrtf-0.21.2.old/src/output.h unrtf-0.21.2/src/output.h --- unrtf-0.21.2.old/src/output.h 2010-08-11 21:09:02.000000000 -0400 -+++ unrtf-0.21.2/src/output.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/output.h 2012-08-21 13:33:44.829682714 -0400 @@ -44,227 +44,228 @@ typedef Collection Aliases; @@ -9932,7 +10238,7 @@ diff -durpN unrtf-0.21.2.old/src/output.h unrtf-0.21.2/src/output.h - diff -durpN unrtf-0.21.2.old/src/parse.c unrtf-0.21.2/src/parse.c --- unrtf-0.21.2.old/src/parse.c 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/parse.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/parse.c 2012-08-21 13:38:56.765687661 -0400 @@ -1,23 +1,23 @@ /*============================================================================= - GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -10172,7 +10478,7 @@ diff -durpN unrtf-0.21.2.old/src/parse.c unrtf-0.21.2/src/parse.c + error_handler(cc, "No input buffer allocated"); + old_length = cc->current_max_length; + cc->current_max_length *= 2; -+ new_ptr = my_malloc (cc->current_max_length); ++ new_ptr = unrtf_malloc (cc->current_max_length); + if (!new_ptr) + error_handler(cc, "Out of memory while resizing buffer"); @@ -10181,7 +10487,7 @@ diff -durpN unrtf-0.21.2.old/src/parse.c unrtf-0.21.2/src/parse.c - input_str = new_ptr; - return TRUE; + memcpy (new_ptr, cc->input_str, old_length); -+ my_free(cc->input_str); ++ unrtf_free(cc->input_str); + cc->input_str = new_ptr; + return TRUE; } @@ -10220,9 +10526,9 @@ diff -durpN unrtf-0.21.2.old/src/parse.c unrtf-0.21.2/src/parse.c + /* Get some storage for a word. + */ + if (cc->input_str) { -+ my_free(cc->input_str); ++ unrtf_free(cc->input_str); + } -+ cc->input_str = my_malloc (cc->current_max_length); ++ cc->input_str = unrtf_malloc (cc->current_max_length); + if (!cc->input_str) + error_handler(cc, "Cannot allocate word storage"); @@ -10600,13 +10906,13 @@ diff -durpN unrtf-0.21.2.old/src/parse.c unrtf-0.21.2/src/parse.c - input_str = NULL; - } while (1); + /* Free up the memory allocated by read_word. */ -+ my_free(cc->input_str); ++ unrtf_free(cc->input_str); + cc->input_str = NULL; + } while (1); } diff -durpN unrtf-0.21.2.old/src/parse.h unrtf-0.21.2/src/parse.h --- unrtf-0.21.2.old/src/parse.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/parse.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/parse.h 2012-08-21 13:33:44.829682714 -0400 @@ -38,8 +38,6 @@ #include "word.h" #endif @@ -10697,9 +11003,81 @@ diff -durpN unrtf-0.21.2.old/src/path.h unrtf-0.21.2/src/path.h - -int check_dirs(); -void show_dirs(); +diff -durpN unrtf-0.21.2.old/src/unicode.c unrtf-0.21.2/src/unicode.c +--- unrtf-0.21.2.old/src/unicode.c 2011-06-07 08:06:43.000000000 -0400 ++++ unrtf-0.21.2/src/unicode.c 2012-08-21 13:38:56.765687661 -0400 +@@ -55,20 +55,20 @@ unicode_to_string(int uc) + + if (uc < 0x7f) + { +- string = my_malloc(2 * sizeof(char)); ++ string = unrtf_malloc(2 * sizeof(char)); + string[0] = (unsigned char) uc; + string[1] = '\0'; + } + else if (uc < 0x7ff) + { +- string = my_malloc(3 * sizeof(char)); ++ string = unrtf_malloc(3 * sizeof(char)); + string[0] = (unsigned char) 192 + (uc / 64); + string[1] = (unsigned char) 128 + (uc % 64); + string[2] = '\0'; + } + else if (uc < 0xffff) + { +- string = my_malloc(4 * sizeof(char)); ++ string = unrtf_malloc(4 * sizeof(char)); + string[0] = (unsigned char) 224 + (uc / (64 * 64)); + string[1] = (unsigned char) 128 + ((uc / 64) % 64); + string[2] = (unsigned char) 128 + (uc % 64); +@@ -76,7 +76,7 @@ unicode_to_string(int uc) + } + else if (uc < 0x1FFFFF) + { +- string = my_malloc(5 * sizeof(char)); ++ string = unrtf_malloc(5 * sizeof(char)); + string[0] = (unsigned char) 240 + (uc / (64 * 64 * 64)); + string[1] = (unsigned char) 128 + ((uc / (64 * 64)) % 64); + string[2] = (unsigned char) 128 + ((uc / 64) % 64); +@@ -85,7 +85,7 @@ unicode_to_string(int uc) + } + else if (uc < 0x3FFFFFF) + { +- string = my_malloc(6 * sizeof(char)); ++ string = unrtf_malloc(6 * sizeof(char)); + string[0] = (unsigned char) 248 + (uc / (64 * 64 * 64 * 64)); + string[1] = (unsigned char) 128 + ((uc / (64 * 64 * 64)) % 64); + string[2] = (unsigned char) 128 + ((uc / (64 * 64)) % 64); +@@ -95,7 +95,7 @@ unicode_to_string(int uc) + } + else if (uc < 0x7FFFFFFF) + { +- string = my_malloc(7 * sizeof(char)); ++ string = unrtf_malloc(7 * sizeof(char)); + string[0] = (unsigned char) 252 + (uc / (64 * 64 * 64 * 64 * 64)); + string[1] = (unsigned char) 128 + ((uc / (64 * 64 * 64 * 64)) % 64); + string[2] = (unsigned char) 128 + ((uc / (64 * 64 * 64)) % 64); +@@ -122,7 +122,7 @@ char * + get_unicode_char(FILE *file) + { + int allocated = 5, len = 0, uc; +- char c, *unicode_number = my_malloc(allocated * sizeof(char)); ++ char c, *unicode_number = unrtf_malloc(allocated * sizeof(char)); + + c = fgetc(file); + +@@ -139,7 +139,7 @@ get_unicode_char(FILE *file) + if (len == allocated) + { + allocated *= 2; +- unicode_number = my_realloc(unicode_number, allocated / 2, allocated); ++ unicode_number = unrtf_realloc(unicode_number, allocated / 2, allocated); + } + } + diff -durpN unrtf-0.21.2.old/src/unrtf.h unrtf-0.21.2/src/unrtf.h --- unrtf-0.21.2.old/src/unrtf.h 1969-12-31 19:00:00.000000000 -0500 -+++ unrtf-0.21.2/src/unrtf.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/unrtf.h 2012-08-21 13:33:44.833682714 -0400 @@ -0,0 +1,55 @@ +/*=========================================================================== + GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -10758,7 +11136,7 @@ diff -durpN unrtf-0.21.2.old/src/unrtf.h unrtf-0.21.2/src/unrtf.h +#endif /* UNRTF_H */ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c --- unrtf-0.21.2.old/src/user.c 2011-06-07 08:08:17.000000000 -0400 -+++ unrtf-0.21.2/src/user.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/user.c 2012-08-21 13:38:56.773687616 -0400 @@ -7,7 +7,7 @@ *---------------------------------------------------------------------- * Changes: @@ -10790,7 +11168,7 @@ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c - if ((f->file = fopen(file_name, "r")) == NULL || (f->name = my_malloc((strlen(file_name) + 1) * sizeof(char))) == NULL) - return NULL; -+ if ((f->file = fopen(file_name, "r")) == NULL || (f->name = my_malloc((strlen(file_name) + 1) * sizeof(char))) == NULL) ++ if ((f->file = fopen(file_name, "r")) == NULL || (f->name = unrtf_malloc((strlen(file_name) + 1) * sizeof(char))) == NULL) + return NULL; - f->line_nr = 1; @@ -10810,7 +11188,7 @@ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c - fclose(f->file); - my_free(f->name); + fclose(f->file); -+ my_free(f->name); ++ unrtf_free(f->name); } /*======================================================================== @@ -10833,7 +11211,7 @@ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c +#define ADD_CHAR(char) \ + if (def_buffer_length == chars_nr) \ + { \ -+ if ((def = my_realloc(def, def_buffer_length, def_buffer_length * 2)) == NULL) \ ++ if ((def = unrtf_realloc(def, def_buffer_length, def_buffer_length * 2)) == NULL) \ + { \ + perror("Cannot allocate memory."); \ + return NULL; \ @@ -10855,7 +11233,7 @@ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c - if ((def = my_malloc(def_buffer_length)) == NULL) - return NULL; -+ if ((def = my_malloc(def_buffer_length)) == NULL) ++ if ((def = unrtf_malloc(def_buffer_length)) == NULL) + return NULL; - c = fgetc(file->file); @@ -11060,11 +11438,11 @@ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c + add_alias(op, get_unicode(&name[2]), def); + else + { -+ my_free (def); ++ unrtf_free (def); + fprintf(stderr, "unrtf: unknown name \"%s\" in line %d of \"%s\"\n", name, file->line_nr, file->name); + return 1; + } -+ my_free (def); ++ unrtf_free (def); + } + else + if ((*defs[i].variable = give_definition(file)) == NULL) @@ -11188,7 +11566,7 @@ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c diff -durpN unrtf-0.21.2.old/src/user.h unrtf-0.21.2/src/user.h --- unrtf-0.21.2.old/src/user.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/user.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/user.h 2012-08-21 13:33:44.833682714 -0400 @@ -151,9 +151,10 @@ #ifndef _USER @@ -11202,9 +11580,21 @@ diff -durpN unrtf-0.21.2.old/src/user.h unrtf-0.21.2/src/user.h #define _USER #endif +diff -durpN unrtf-0.21.2.old/src/util.c unrtf-0.21.2/src/util.c +--- unrtf-0.21.2.old/src/util.c 2010-08-09 08:05:30.000000000 -0400 ++++ unrtf-0.21.2/src/util.c 2012-08-21 13:38:56.777687600 -0400 +@@ -110,7 +110,7 @@ concatenate (const char *s1, const char + { + char *result; + +- result = my_malloc((strlen(s1) + strlen(s2) + 1) * sizeof(char)); ++ result = unrtf_malloc((strlen(s1) + strlen(s2) + 1) * sizeof(char)); + strcpy(result, s1); + strcat(result, s2); + diff -durpN unrtf-0.21.2.old/src/word.c unrtf-0.21.2/src/word.c --- unrtf-0.21.2.old/src/word.c 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/word.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/word.c 2012-08-21 13:38:56.781687591 -0400 @@ -1,23 +1,23 @@ /*============================================================================= - GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -11298,7 +11688,7 @@ diff -durpN unrtf-0.21.2.old/src/word.c unrtf-0.21.2/src/word.c - error_handler ("out of memory"); - memset ((void*) w, 0, sizeof(Word)); - if (!w) error_handler ("cannot allocate a Word"); -+ w = (Word *) my_malloc(sizeof(Word)); ++ w = (Word *) unrtf_malloc(sizeof(Word)); + if (!w) + error_handler (cc, "out of memory"); + memset ((void*) w, 0, sizeof(Word)); @@ -11346,7 +11736,7 @@ diff -durpN unrtf-0.21.2.old/src/word.c unrtf-0.21.2/src/word.c - } + prev = w; + w = w->next; -+ my_free((char*) prev); ++ unrtf_free((char*) prev); + } } @@ -11501,7 +11891,7 @@ diff -durpN unrtf-0.21.2.old/src/word.c unrtf-0.21.2/src/word.c + if (s != NULL && s1 != NULL && !strcmp(s1, s)) + { + w2->next = w->next; -+ my_free((char *)w); ++ unrtf_free((char *)w); + w = w2; + } + else @@ -11529,7 +11919,7 @@ diff -durpN unrtf-0.21.2.old/src/word.c unrtf-0.21.2/src/word.c diff -durpN unrtf-0.21.2.old/src/word.h unrtf-0.21.2/src/word.h --- unrtf-0.21.2.old/src/word.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/word.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/word.h 2012-08-21 13:33:44.833682714 -0400 @@ -41,14 +41,15 @@ typedef struct _w { struct _w * child; } Word; From 4f9e0f9963981ef4d7fcaaeda5abfd80331008b7 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 21 Aug 2012 18:25:08 +0000 Subject: [PATCH 114/127] Monotone-Parent: 321dcc0c57ee3b7c5ea6cebb040566be569bacb3 Monotone-Revision: 78c0405a3665172ccb21ec34bba08331cc479f71 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-21T18:25:08 Monotone-Branch: ca.inverse.sogo --- OpenChange/GNUmakefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 1174670b2..39adc7c0e 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -169,7 +169,9 @@ DBMSGREADER_TOOL = dbmsgreader $(DBMSGREADER_TOOL)_OBJC_FILES += \ dbmsgreader.m -$(DBMSGREADER_TOOL)_LIB_DIRS += -L../SoObjects/SOGo/ -lSOGo -lNGObjWeb +$(DBMSGREADER_TOOL)_LIB_DIRS += \ + -L../SoObjects/SOGo/SOGo.framework/ -lSOGo \ + -lNGObjWeb TEST_TOOL_NAME += $(PLREADER_TOOL) $(DBMSGREADER_TOOL) From 56eae68d7c80b6978dcc2fbbd688a3ad67da7e3e Mon Sep 17 00:00:00 2001 From: Jean Raby Date: Tue, 21 Aug 2012 19:07:15 +0000 Subject: [PATCH 115/127] Missing library path for dbmsgreader Monotone-Parent: 78c0405a3665172ccb21ec34bba08331cc479f71 Monotone-Revision: 98ed5bb6af42d0b60f21c80b01ede4cb33ad82e7 Monotone-Author: jraby@inverse.ca Monotone-Date: 2012-08-21T19:07:15 Monotone-Branch: ca.inverse.sogo --- OpenChange/GNUmakefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 39adc7c0e..6bc588b71 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -170,7 +170,8 @@ $(DBMSGREADER_TOOL)_OBJC_FILES += \ dbmsgreader.m $(DBMSGREADER_TOOL)_LIB_DIRS += \ - -L../SoObjects/SOGo/SOGo.framework/ -lSOGo \ + -L../SoObjects/SOGo/SOGo.framework/ -L../OGoContentStore/obj/ \ + -L../SOPE/GDLContentStore/obj/ -L../SOPE/NGCards/obj/ -lSOGo -lNGObjWeb TEST_TOOL_NAME += $(PLREADER_TOOL) $(DBMSGREADER_TOOL) From 59a1f986ccad96bcede7220f87fa9cd43d0b31ea Mon Sep 17 00:00:00 2001 From: Jean Raby Date: Tue, 21 Aug 2012 19:10:57 +0000 Subject: [PATCH 116/127] missing backslash Monotone-Parent: 98ed5bb6af42d0b60f21c80b01ede4cb33ad82e7 Monotone-Revision: 4f5aec06157554c4d68363a46984c6fe335386fd Monotone-Author: jraby@inverse.ca Monotone-Date: 2012-08-21T19:10:57 Monotone-Branch: ca.inverse.sogo --- OpenChange/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 6bc588b71..ceaade415 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -171,7 +171,7 @@ $(DBMSGREADER_TOOL)_OBJC_FILES += \ $(DBMSGREADER_TOOL)_LIB_DIRS += \ -L../SoObjects/SOGo/SOGo.framework/ -L../OGoContentStore/obj/ \ - -L../SOPE/GDLContentStore/obj/ -L../SOPE/NGCards/obj/ -lSOGo + -L../SOPE/GDLContentStore/obj/ -L../SOPE/NGCards/obj/ -lSOGo \ -lNGObjWeb TEST_TOOL_NAME += $(PLREADER_TOOL) $(DBMSGREADER_TOOL) From 0f9bcd552d6b3f3fe345b017b66c5acda809c553 Mon Sep 17 00:00:00 2001 From: Jean Raby Date: Tue, 21 Aug 2012 19:59:32 +0000 Subject: [PATCH 117/127] Real fix... Monotone-Parent: 4f5aec06157554c4d68363a46984c6fe335386fd Monotone-Revision: 8cea0b1a81fe57f8395b91cfc3ed8063d49995ca Monotone-Author: jraby@inverse.ca Monotone-Date: 2012-08-21T19:59:32 Monotone-Branch: ca.inverse.sogo --- OpenChange/GNUmakefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index ceaade415..68f3e8dfb 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -170,9 +170,11 @@ $(DBMSGREADER_TOOL)_OBJC_FILES += \ dbmsgreader.m $(DBMSGREADER_TOOL)_LIB_DIRS += \ - -L../SoObjects/SOGo/SOGo.framework/ -L../OGoContentStore/obj/ \ - -L../SOPE/GDLContentStore/obj/ -L../SOPE/NGCards/obj/ -lSOGo \ - -lNGObjWeb + -L../SoObjects/SOGo/SOGo.framework/ -lSOGo \ + -L../OGoContentStore/obj/ -lOGoContentStore \ + -L../SOPE/GDLContentStore/obj/ -lGDLContentStore \ + -L../SOPE/NGCards/obj/ -lNGCards \ + -lNGObjWeb TEST_TOOL_NAME += $(PLREADER_TOOL) $(DBMSGREADER_TOOL) From e86f5ff8414b2eafbc286be69029fadb50f72265 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 21 Aug 2012 20:36:32 +0000 Subject: [PATCH 118/127] Monotone-Parent: 78c0405a3665172ccb21ec34bba08331cc479f71 Monotone-Revision: e70a6a4e35fcf0aacec5ec5ef392c0c8e6bb4e31 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-21T20:36:32 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 10 ++++++ OpenChange/MAPIStoreGCSFolder.h | 3 -- OpenChange/MAPIStoreGCSFolder.m | 59 +++++++++++++++------------------ 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/ChangeLog b/ChangeLog index 669f2a1d5..fecff2fe7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2012-08-21 Wolfgang Sourdeau + + * OpenChange/MAPIStoreGCSFolder.m + (-setChangeKey:forMessageWithKey:): removed useless method. + (-updateVersionsForMessageWithKey:withChangeKey:): set the change + key provided by the client as member of the predecessor + changelist, but never as the actual change key for the object. + This hopefully fixes the issue where Outlook deletes objects that + have a different change list than what they expect. + 2012-08-17 Wolfgang Sourdeau * OpenChange/MAPIStoreCalendarMessage.m diff --git a/OpenChange/MAPIStoreGCSFolder.h b/OpenChange/MAPIStoreGCSFolder.h index 6d25069ca..1f48e034a 100644 --- a/OpenChange/MAPIStoreGCSFolder.h +++ b/OpenChange/MAPIStoreGCSFolder.h @@ -45,11 +45,8 @@ withChangeKey: (NSData *) newChangeKey; - (NSNumber *) lastModifiedFromMessageChangeNumber: (NSNumber *) changeNum; - (NSNumber *) changeNumberForMessageWithKey: (NSString *) messageKey; - - (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey; - (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey; -- (void) setChangeKey: (NSData *) changeKey - forMessageWithKey: (NSString *) messageKey; - (NSArray *) activeUserRoles; diff --git a/OpenChange/MAPIStoreGCSFolder.m b/OpenChange/MAPIStoreGCSFolder.m index d042dfcf0..a5702131f 100644 --- a/OpenChange/MAPIStoreGCSFolder.m +++ b/OpenChange/MAPIStoreGCSFolder.m @@ -261,6 +261,7 @@ static Class NSNumberK; - (void) _setChangeKey: (NSData *) changeKey forMessageEntry: (NSMutableDictionary *) messageEntry + inChangeListOnly: (BOOL) inChangeListOnly { struct XID *xid; NSString *guid; @@ -273,12 +274,15 @@ static Class NSNumberK; globCnt = [NSData dataWithBytes: xid->Data length: xid->Size]; talloc_free (xid); - /* 1. set change key association */ - changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys: - guid, @"GUID", - globCnt, @"LocalId", - nil]; - [messageEntry setObject: changeKeyDict forKey: @"ChangeKey"]; + if (!inChangeListOnly) + { + /* 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"]; @@ -286,11 +290,10 @@ static Class NSNumberK; { changeList = [NSMutableDictionary new]; [messageEntry setObject: changeList - forKey: @"PredecessorChangeList"]; + forKey: @"PredecessorChangeList"]; [changeList release]; } - [changeList setObject: globCnt - forKey: guid]; + [changeList setObject: globCnt forKey: guid]; } - (EOQualifier *) componentQualifier @@ -433,7 +436,8 @@ static Class NSNumberK; [messageEntry setObject: changeNumber forKey: @"version"]; changeKey = [self getReplicaKeyFromGlobCnt: newChangeNum >> 16]; - [self _setChangeKey: changeKey forMessageEntry: messageEntry]; + [self _setChangeKey: changeKey forMessageEntry: messageEntry + inChangeListOnly: NO]; [mapping setObject: cLastModified forKey: changeNumber]; @@ -464,10 +468,21 @@ static Class NSNumberK; - (void) updateVersionsForMessageWithKey: (NSString *) messageKey withChangeKey: (NSData *) newChangeKey { - [self synchroniseCache]; + NSMutableDictionary *messages, *messageEntry; + [self synchroniseCache]; if (newChangeKey) - [self setChangeKey: newChangeKey forMessageWithKey: messageKey]; + { + messages = [[versionsMessage properties] objectForKey: @"Messages"]; + messageEntry = [messages objectForKey: messageKey]; + if (!messageEntry) + [NSException raise: @"MAPIStoreIOException" + format: @"no version record found for message '%@'", + messageKey]; + [self _setChangeKey: newChangeKey forMessageEntry: messageEntry + inChangeListOnly: YES]; + [versionsMessage save]; + } } - (NSNumber *) lastModifiedFromMessageChangeNumber: (NSNumber *) changeNum @@ -493,26 +508,6 @@ static Class NSNumberK; return changeNumber; } -- (void) setChangeKey: (NSData *) changeKey - forMessageWithKey: (NSString *) messageKey -{ - NSMutableDictionary *messages; - NSMutableDictionary *messageEntry; - - messages = [[versionsMessage properties] objectForKey: @"Messages"]; - messageEntry = [messages objectForKey: messageKey]; - if (!messageEntry) - { - [self synchroniseCache]; - messageEntry = [messages objectForKey: messageKey]; - if (!messageEntry) - abort (); - } - [self _setChangeKey: changeKey forMessageEntry: messageEntry]; - - [versionsMessage save]; -} - - (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey { NSDictionary *messages, *changeKeyDict; From 2037ff8a6b491a0fab2d122a9d8e1c322e3cebff Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 21 Aug 2012 20:37:50 +0000 Subject: [PATCH 119/127] Monotone-Parent: e70a6a4e35fcf0aacec5ec5ef392c0c8e6bb4e31 Monotone-Revision: 289c3552a8d15a19943bfe3a54272bf413087c4f Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-21T20:37:50 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++ OpenChange/MAPIStoreContactsMessage.m | 52 ++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index fecff2fe7..6039c337c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2012-08-21 Wolfgang Sourdeau + * OpenChange/MAPIStoreContactsMessage.m + (-getPidTagAlternateRecipientAllowed:inMemCtx:) + (-getPidTagMessageFlags:inMemCtx:) + (-getPidTagDeleteAfterSubmit:inMemCtx:): new getters. + * OpenChange/MAPIStoreGCSFolder.m (-setChangeKey:forMessageWithKey:): removed useless method. (-updateVersionsForMessageWithKey:withChangeKey:): set the change diff --git a/OpenChange/MAPIStoreContactsMessage.m b/OpenChange/MAPIStoreContactsMessage.m index 3097367c0..c02eb8cbd 100644 --- a/OpenChange/MAPIStoreContactsMessage.m +++ b/OpenChange/MAPIStoreContactsMessage.m @@ -110,6 +110,28 @@ return MAPISTORE_SUCCESS; } +- (int) getPidTagAlternateRecipientAllowed: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx + +{ + return [self getYes: data inMemCtx: memCtx]; +} + +- (int) getPidTagMessageFlags: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = MAPILongValue (memCtx, MSGFLAG_READ); + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagDeleteAfterSubmit: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx + +{ + return [self getNo: data inMemCtx: memCtx]; +} + - (int) getPidTagMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -189,13 +211,34 @@ - (int) getPidLidFileUnder: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidTagDisplayName: data inMemCtx: memCtx]; + NSString *surName, *givenName, *middleName; + NSMutableString *fileUnder; + CardElement *n; + + n = [[sogoObject vCard] n]; + surName = [n flattenedValueAtIndex: 0 + forKey: @""]; + fileUnder = [surName mutableCopy]; + [fileUnder autorelease]; + [fileUnder appendString: @","]; + givenName = [n flattenedValueAtIndex: 1 + forKey: @""]; + if ([givenName length] > 0) + [fileUnder appendFormat: @" %@", givenName]; + middleName = [n flattenedValueAtIndex: 2 + forKey: @""]; + if ([middleName length] > 0) + [fileUnder appendFormat: @" %@", middleName]; + + *data = [fileUnder asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; } - (int) getPidLidFileUnderId: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = MAPILongValue (memCtx, 0xffffffff); + *data = MAPILongValue (memCtx, 0x00008017); /* what ol2003 sets */ return MAPISTORE_SUCCESS; } @@ -209,7 +252,7 @@ vCard = [sogoObject vCard]; fn = [vCard fn]; email = [vCard preferredEMail]; - *data = [[NSString stringWithFormat: @"%@ <%@>", fn, email] + *data = [[NSString stringWithFormat: @"%@ (%@)", fn, email] asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; @@ -218,7 +261,8 @@ - (int) getPidLidEmail1OriginalDisplayName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidLidEmail1DisplayName: data inMemCtx: memCtx]; + return [self getPidLidEmail1EmailAddress: data + inMemCtx: memCtx]; } - (int) getPidLidEmail1EmailAddress: (void **) data From 8670c3c5616bc6dd07dccead501c8a59f53f1a62 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 21 Aug 2012 20:38:43 +0000 Subject: [PATCH 120/127] Monotone-Parent: 289c3552a8d15a19943bfe3a54272bf413087c4f Monotone-Revision: 30720cd63a96f71fe1ddecf048357f4063f4a056 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-21T20:38:43 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ OpenChange/MAPIStoreMailMessage.m | 6 ------ OpenChange/MAPIStoreMessage.m | 6 ++++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6039c337c..9ef94919c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-08-21 Wolfgang Sourdeau + * OpenChange/MAPIStoreMessage.m + (-getPidTagDeleteAfterSubmit:inMemCtx:): moved from + MAPIStoreMailMessage. + * OpenChange/MAPIStoreContactsMessage.m (-getPidTagAlternateRecipientAllowed:inMemCtx:) (-getPidTagMessageFlags:inMemCtx:) diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 1fb87664e..a88e5bc04 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -1000,12 +1000,6 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) return [self getNo: data inMemCtx: memCtx]; } -- (int) getPidTagDeleteAfterSubmit: (void **) data // TODO - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getNo: data inMemCtx: memCtx]; -} - - (int) getPidLidGlobalObjectId: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index f354930b6..325757b81 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -801,6 +801,12 @@ rtf2html (NSData *compressedRTF) return [self getEmptyString: data inMemCtx: memCtx]; } +- (int) getPidTagDeleteAfterSubmit: (void **) data // TODO + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getNo: data inMemCtx: memCtx]; +} + - (int) getPidTagDisplayTo: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { From f1c5ee15b7e42805816026fa4236278181ef0a42 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 21 Aug 2012 20:39:36 +0000 Subject: [PATCH 121/127] Monotone-Parent: 30720cd63a96f71fe1ddecf048357f4063f4a056 Monotone-Revision: c61e2dc9a2d1575387224156c338b5517bdcbae1 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-21T20:39:36 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 +++ OpenChange/MAPIStoreFolder.m | 48 +++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 9ef94919c..6ebfc2314 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-08-21 Wolfgang Sourdeau + * OpenChange/MAPIStoreFolder.m (-getPidTagAccessLevel) + (-getPidTagRights, -getPidTagAccessControlListData): fixed + methods. + * OpenChange/MAPIStoreMessage.m (-getPidTagDeleteAfterSubmit:inMemCtx:): moved from MAPIStoreMailMessage. diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 50b357236..8cb57b5ac 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -25,6 +25,7 @@ #import #import #import +#import #import #import #import @@ -46,6 +47,7 @@ #import "MAPIStoreSamDBUtils.h" #import "MAPIStoreTypes.h" #import "MAPIStoreUserContext.h" +#import "NSData+MAPIStore.h" #import "NSDate+MAPIStore.h" #import "NSString+MAPIStore.h" #import "NSObject+MAPIStore.h" @@ -1315,7 +1317,51 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (int) getPidTagAccessLevel: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = MAPILongValue (memCtx, 0x01); + SOGoUser *ownerUser; + BOOL userIsOwner; + + ownerUser = [[self userContext] sogoUser]; + + userIsOwner = [[context activeUser] isEqual: ownerUser]; + + *data = MAPILongValue (memCtx, (userIsOwner) ? 0x01 : 0x00); + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagRights: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + uint32_t rights = 0; + SOGoUser *ownerUser; + BOOL userIsOwner; + + ownerUser = [[self userContext] sogoUser]; + + userIsOwner = [[context activeUser] isEqual: ownerUser]; + if (userIsOwner || [self subscriberCanReadMessages]) + rights |= RightsReadItems; + if (userIsOwner || [self subscriberCanCreateMessages]) + rights |= RightsCreateItems; + if (userIsOwner || [self subscriberCanModifyMessages]) + rights |= RightsEditOwn | RightsEditAll; + if (userIsOwner || [self subscriberCanDeleteMessages]) + rights |= RightsDeleteOwn | RightsDeleteAll; + if ((userIsOwner || [self subscriberCanCreateSubFolders]) + && [self supportsSubFolders]) + rights |= RightsCreateSubfolders; + if (userIsOwner) + rights |= RightsFolderOwner | RightsFolderContact; + + *data = MAPILongValue (memCtx, rights); + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagAccessControlListData: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [[NSData data] asBinaryInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } From 54434e98961a9e37b865e670970312c81259c3b4 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 21 Aug 2012 20:39:46 +0000 Subject: [PATCH 122/127] Monotone-Parent: c61e2dc9a2d1575387224156c338b5517bdcbae1 Monotone-Revision: f878485f243e179600dcdcf48b5dffc712d954ca Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-21T20:39:46 Monotone-Branch: ca.inverse.sogo --- OpenChange/NSData+MAPIStore.h | 2 ++ OpenChange/NSData+MAPIStore.m | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/OpenChange/NSData+MAPIStore.h b/OpenChange/NSData+MAPIStore.h index 20409c1ac..5715b9128 100644 --- a/OpenChange/NSData+MAPIStore.h +++ b/OpenChange/NSData+MAPIStore.h @@ -45,6 +45,8 @@ + (id) dataWithChangeKeyGUID: (NSString *) guidString andCnt: (NSData *) globCnt; +- (void) hexDumpWithLineSize: (NSUInteger) lineSize; + @end @interface NSMutableData (MAPIStoreDataTypes) diff --git a/OpenChange/NSData+MAPIStore.m b/OpenChange/NSData+MAPIStore.m index 3ad9afb52..b1200c5f4 100644 --- a/OpenChange/NSData+MAPIStore.m +++ b/OpenChange/NSData+MAPIStore.m @@ -20,6 +20,8 @@ * Boston, MA 02111-1307, USA. */ +#import + #import "NSString+MAPIStore.h" #import "NSData+MAPIStore.h" @@ -185,6 +187,36 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID * return changeKey; } +- (void) hexDumpWithLineSize: (NSUInteger) lineSize +{ + const char *bytes; + NSUInteger lineCount, count, max, charCount, charMax; + NSMutableString *line; + + bytes = [self bytes]; + max = [self length]; + + lineCount = 0; + for (count = 0; count < max; count++) + { + line = [NSMutableString stringWithFormat: @"%d: ", lineCount]; + if (lineSize) + { + if ((max - count) > lineSize) + charMax = lineSize; + else + charMax = max - count; + } + else + charMax = max; + for (charCount = 0; charCount < charMax; charCount++) + [line appendFormat: @" %.2x", *(bytes + count + charCount)]; + [self logWithFormat: @" %@", line]; + count += charMax; + lineCount++; + } +} + @end @implementation NSMutableData (MAPIStoreDataTypes) From 6f0cc7502d712165b46acc589d53a2f995149ccc Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Thu, 23 Aug 2012 16:51:24 +0000 Subject: [PATCH 123/127] See ChangeLog Monotone-Parent: ec64b102b590c4a7b217fe508a46ad302e12adce Monotone-Revision: 28a7f739364a5ec7c2076aea5f8a59c6910c4727 Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2012-08-23T16:51:24 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 6 ++++++ SoObjects/Mailer/SOGoMailFolder.m | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/ChangeLog b/ChangeLog index 6ebfc2314..9ec30eb61 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-08-23 Ludovic Marcotte + + * SoObjects/Mailer/SOGoMailFolder.m - added safety + checks around the ACL code so we don't crash if + we can't read the ACLs. + 2012-08-21 Wolfgang Sourdeau * OpenChange/MAPIStoreFolder.m (-getPidTagAccessLevel) diff --git a/SoObjects/Mailer/SOGoMailFolder.m b/SoObjects/Mailer/SOGoMailFolder.m index 1bf4c6a30..5e6348bde 100644 --- a/SoObjects/Mailer/SOGoMailFolder.m +++ b/SoObjects/Mailer/SOGoMailFolder.m @@ -1171,6 +1171,9 @@ static NSString *defaultUserID = @"anyone"; NSEnumerator *usernames; NSString *username; + if ([mailboxACL isKindOfClass: [NSException class]]) + return; + newIMAPAcls = [NSMutableDictionary new]; usernames = [[mailboxACL allKeys] objectEnumerator]; @@ -1193,6 +1196,9 @@ static NSString *defaultUserID = @"anyone"; NSString *newUsername; NSString *imapPrefix; + if ([mailboxACL isKindOfClass: [NSException class]]) + return; + imapPrefix = [[[context activeUser] domainDefaults] imapAclGroupIdPrefix]; newIMAPAcls = [[NSMutableDictionary alloc] init]; From 29c5915c490d27cb30c029d8410472f7eccc426b Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Fri, 24 Aug 2012 10:25:13 +0000 Subject: [PATCH 124/127] Improved documentation regarding Dovecot's IMAP proxy Monotone-Parent: 28a7f739364a5ec7c2076aea5f8a59c6910c4727 Monotone-Revision: e9cb8a37d8bab3091b59b8f07c29c1b5b23e141d Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2012-08-24T10:25:13 Monotone-Branch: ca.inverse.sogo --- ...Native Microsoft Outlook Configuration.odt | Bin 30477 -> 30380 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Documentation/SOGo Native Microsoft Outlook Configuration.odt b/Documentation/SOGo Native Microsoft Outlook Configuration.odt index 1eed637675fbca3e3830e70c38515cf47c8c3036..9dc7e0eb17eba7ed8319a799803ff1ecf2994439 100644 GIT binary patch delta 27190 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 delta 27266 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�IliXk8gqgV_JLLv4-c$4K4cKWn#Z!Ojp<1{b*L; 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 From ea30ab1a5e48663c90afff060ca2362cc7987908 Mon Sep 17 00:00:00 2001 From: Jean Raby Date: Fri, 24 Aug 2012 14:43:33 +0000 Subject: [PATCH 125/127] Updated installation step for Debian Squeeze. Monotone-Parent: e9cb8a37d8bab3091b59b8f07c29c1b5b23e141d Monotone-Revision: 62e7b3488d4ad08a0899f6a8ce833621b1476f8c Monotone-Author: jraby@inverse.ca Monotone-Date: 2012-08-24T14:43:33 Monotone-Branch: ca.inverse.sogo --- ...Native Microsoft Outlook Configuration.odt | Bin 30380 -> 29805 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Documentation/SOGo Native Microsoft Outlook Configuration.odt b/Documentation/SOGo Native Microsoft Outlook Configuration.odt index 9dc7e0eb17eba7ed8319a799803ff1ecf2994439..44790c9ffbd37e7aa544c44c4f998de19565d49c 100644 GIT binary patch delta 27413 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

^-f!XZ~U^;tUhF;;Q3ohHhzi zD23rLrPJ@2LRh$AVeG3yV#2?0mRW(ld727jO_Wc6PTA8|TG>6dIrR;|lA*X=1kf>0bS<#VA3AM>6#y8Ui#7w+dPdFKAXvdER}YqJuT%7s-vGO&6o z`#__B6#-d?xpn)M$y+<>$w6_f)}@A|#p&uf)STvqqD6oD$f^;8b_fEKt@fLn+ou;f zhE^F+$qNq##_0I(rrpTT({5>DC4Opg84=olidxTETgu|UT6f|-i&|cx!TU%v?kRHP zI24C(n;q;=$ozCj6E@IYEeKTY`RU3jATzw78 z9)1)T<7_4F8HE!PxGT89a;&mfoOiqH?B*l}>bCop^j6R&&YIA9%pbq!!wVF=f1FA> zmL(#=QgUU`jQZSOvRi2&)f%w>9@G_OWBl;yrOzkAu7v5IC9tgLB#d&BuYN-UL;Bln zk1uk_ulSk!@z1C~r*-^=kbd5LNu2f~m;6Ni)N6j9r{_gW{S{cx*?WGUOYP6d-#^{* zlE>#)3_L3|2EVfU`~?2g>i+!j%P-&v@83TP^ONOg#eXlr{;}e4T7Q&;|BU>-`uIm= z=`-@5XZEvP`xE)I=D%tR2KFKp{)%1gf0ep^uT}o>0RO^)fxW1ezXD(9UwQsTyZn2y zKUPZnFUWqcW&U@00Dr;rdu{XYd0uqGUorF-JioNgzh`+-JAcJ%-GA+(KWd+U&-BOo z@caeSFD>-H%i{PKEWfnT|77`j(!R9fr@;B5j{b^b-G6P>-)N;j&&r>qzaPF|w9#Mj qO7Hhd>7Q}GAA(*6_g~>^`!_?qoa7sbm)$-*zlxtnt^>Q5PyYe=AN3Ic From 766b0a1dfb86613c108478649fc0f281b16c1710 Mon Sep 17 00:00:00 2001 From: Jean Raby Date: Tue, 28 Aug 2012 14:38:52 +0000 Subject: [PATCH 126/127] * Scripts/openchange_cleanup.py: New script to clean an openchange user profile * packaging/*: install the new script. Including a small tweak for python2.6 on rhel5 Monotone-Parent: 62e7b3488d4ad08a0899f6a8ce833621b1476f8c Monotone-Revision: 2d2ee6b01c8bc748013e83a629b2cc184404a017 Monotone-Author: jraby@inverse.ca Monotone-Date: 2012-08-28T14:38:52 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ packaging/debian-multiarch/sogo.docs | 1 + packaging/debian/sogo.docs | 1 + packaging/rhel/sogo.spec | 17 +++++++++++++++-- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9ec30eb61..f1ad054e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2012-08-28 Jean Raby + * Scripts/openchange_cleanup.py: + New script to clean an openchange user profile + 2012-08-23 Ludovic Marcotte * SoObjects/Mailer/SOGoMailFolder.m - added safety diff --git a/packaging/debian-multiarch/sogo.docs b/packaging/debian-multiarch/sogo.docs index e789c21d8..ded20965f 100644 --- a/packaging/debian-multiarch/sogo.docs +++ b/packaging/debian-multiarch/sogo.docs @@ -1,4 +1,5 @@ NEWS TODO Scripts/*.sh +Scripts/*.py Scripts/updates.php diff --git a/packaging/debian/sogo.docs b/packaging/debian/sogo.docs index e789c21d8..ded20965f 100644 --- a/packaging/debian/sogo.docs +++ b/packaging/debian/sogo.docs @@ -1,4 +1,5 @@ NEWS TODO Scripts/*.sh +Scripts/*.py Scripts/updates.php diff --git a/packaging/rhel/sogo.spec b/packaging/rhel/sogo.spec index 70c939781..91d055fe2 100644 --- a/packaging/rhel/sogo.spec +++ b/packaging/rhel/sogo.spec @@ -3,6 +3,8 @@ %global oc_build_depends samba4 openchange %endif +%{!?python_sys_pyver: %global python_sys_pyver %(/usr/bin/python -c "import sys; print sys.hexversion")} + Summary: SOGo Name: sogo Version: %{sogo_version} @@ -17,7 +19,7 @@ Prefix: /usr AutoReqProv: off Requires: gnustep-base >= 1.23, sope%{sope_major_version}%{sope_minor_version}-core, httpd, sope%{sope_major_version}%{sope_minor_version}-core, sope%{sope_major_version}%{sope_minor_version}-appserver, sope%{sope_major_version}%{sope_minor_version}-ldap, sope%{sope_major_version}%{sope_minor_version}-cards >= %{sogo_version}, sope%{sope_major_version}%{sope_minor_version}-gdl1-contentstore >= %{sogo_version}, sope%{sope_major_version}%{sope_minor_version}-sbjson, libmemcached BuildRoot: %{_tmppath}/%{name}-%{version}-%{release} -BuildRequires: gcc-objc gnustep-base gnustep-make sope%{sope_major_version}%{sope_minor_version}-appserver-devel sope%{sope_major_version}%{sope_minor_version}-core-devel sope%{sope_major_version}%{sope_minor_version}-ldap-devel sope%{sope_major_version}%{sope_minor_version}-mime-devel sope%{sope_major_version}%{sope_minor_version}-xml-devel sope%{sope_major_version}%{sope_minor_version}-gdl1-devel sope%{sope_major_version}%{sope_minor_version}-sbjson-devel libmemcached-devel %{?oc_build_depends} +BuildRequires: gcc-objc gnustep-base gnustep-make sope%{sope_major_version}%{sope_minor_version}-appserver-devel sope%{sope_major_version}%{sope_minor_version}-core-devel sope%{sope_major_version}%{sope_minor_version}-ldap-devel sope%{sope_major_version}%{sope_minor_version}-mime-devel sope%{sope_major_version}%{sope_minor_version}-xml-devel sope%{sope_major_version}%{sope_minor_version}-gdl1-devel sope%{sope_major_version}%{sope_minor_version}-sbjson-devel libmemcached-devel sed %{?oc_build_depends} # Required by MS Exchange freebusy lookups @@ -133,6 +135,14 @@ SOGo backend for OpenChange rm -fr ${RPM_BUILD_ROOT} %setup -q -n SOGo-%{sogo_version} + +# small tweak to the python script for RHEL5 +# if hex(sys.hexversion) < 0x02060000 +%if %{python_sys_pyver} < 33947648 + sed -i 's!/usr/bin/env python!/usr/bin/env python2.6!' Scripts/openchange_cleanup.py +%endif + + # ****************************** build ******************************** %build . /usr/share/GNUstep/Makefiles/GNUstep.sh @@ -234,7 +244,7 @@ rm -fr ${RPM_BUILD_ROOT} %config(noreplace) %{_sysconfdir}/cron.d/sogo %config(noreplace) %{_sysconfdir}/httpd/conf.d/SOGo.conf %config(noreplace) %{_sysconfdir}/sysconfig/sogo -%doc ChangeLog NEWS Scripts/*sh Scripts/updates.php +%doc ChangeLog NEWS Scripts/*sh Scripts/*py Scripts/updates.php %files -n sogo-tool %{_sbindir}/sogo-tool @@ -312,6 +322,9 @@ fi # ********************************* changelog ************************* %changelog +* Tue Aug 28 2012 Jean Raby +- Add openchange_cleanup.py and tweak it to work on RHEL5 + * Tue Jul 31 2012 Jean Raby - treat logrotate file as a config file From 6f7b728d557463ec1bbf718705fb0d41c6c796a5 Mon Sep 17 00:00:00 2001 From: Jean Raby Date: Tue, 28 Aug 2012 15:03:20 +0000 Subject: [PATCH 127/127] Document openchange_cleanup.py Monotone-Parent: 2d2ee6b01c8bc748013e83a629b2cc184404a017 Monotone-Revision: 02b6f913c445756d25887e84a443f77942949032 Monotone-Author: jraby@inverse.ca Monotone-Date: 2012-08-28T15:03:20 Monotone-Branch: ca.inverse.sogo --- ...Native Microsoft Outlook Configuration.odt | Bin 29805 -> 29764 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Documentation/SOGo Native Microsoft Outlook Configuration.odt b/Documentation/SOGo Native Microsoft Outlook Configuration.odt index 44790c9ffbd37e7aa544c44c4f998de19565d49c..c208d51c9c89ecb4fd409ed4f1e66f60174c532f 100644 GIT binary patch delta 19033 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

    &yEI%0?*W=L;S!{7r9#AEkSin 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 UpKk#F7ut4~1s%FEnzWky7l5RPjsO4v delta 19093 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

    tEJ;NBa~M1qU_!@VI_9BP9$~>|(7*tY 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 H_OJXOi~N?n